1+ // Quick Dumper : Moves items marked as "dump" to cursor
2+ // FIXME: local item cache in map blocks needs to be fixed after teleporting items
3+ #include < iostream>
4+ #include < iomanip>
5+ #include < sstream>
6+ #include < climits>
7+ #include < vector>
8+ #include < set>
9+ using namespace std ;
10+
11+ #include < dfhack/Core.h>
12+ #include < dfhack/Console.h>
13+ #include < dfhack/Export.h>
14+ #include < dfhack/PluginManager.h>
15+ #include < vector>
16+ #include < string>
17+ #include < dfhack/modules/Maps.h>
18+ #include < dfhack/modules/Gui.h>
19+ #include < dfhack/modules/Items.h>
20+ #include < dfhack/modules/Materials.h>
21+ #include < dfhack/extra/MapExtras.h>
22+
23+ using namespace DFHack ;
24+ using MapExtras::Block;
25+ using MapExtras::MapCache;
26+
27+ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters);
28+
29+ DFhackCExport const char * plugin_name ( void )
30+ {
31+ return " autodump" ;
32+ }
33+
34+ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
35+ {
36+ commands.clear ();
37+ commands.push_back (PluginCommand (" autodump" ,
38+ " Teleport items marked for dumping to the cursor." ,
39+ df_autodump));
40+ return CR_OK ;
41+ }
42+
43+ DFhackCExport command_result plugin_shutdown ( Core * c )
44+ {
45+ return CR_OK ;
46+ }
47+
48+ typedef std::map <DFCoord, uint32_t > coordmap;
49+
50+ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters)
51+ {
52+ // Command line options
53+ bool destroy = false ;
54+ if (parameters.size () > 0 )
55+ {
56+ string & p = parameters[0 ];
57+ if (p == " destroy" )
58+ destroy = true ;
59+ else if (p == " ?" || p == " help" )
60+ {
61+ c->con .print (
62+ " This utility lets you quickly move all items designated to be dumped.\n "
63+ " Items are instantly moved to the cursor position, the dump flag is unset,\n "
64+ " and the forbid flag is set, as if it had been dumped normally.\n "
65+ " Be aware that any active dump item tasks still point at the item.\n\n "
66+ );
67+ return CR_OK ;
68+ }
69+ }
70+ c->Suspend ();
71+ DFHack::occupancies40d * occupancies;
72+ DFHack::VersionInfo *mem = c->vinfo ;
73+ DFHack::Gui * Gui = c->getGui ();
74+ DFHack::Items * Items = c->getItems ();
75+ DFHack::Maps *Maps = c->getMaps ();
76+
77+ vector <t_item*> p_items;
78+ if (!Items->readItemVector (p_items))
79+ {
80+ c->con .printerr (" Can't access the item vector.\n " );
81+ c->Resume ();
82+ return CR_FAILURE ;
83+ }
84+ std::size_t numItems = p_items.size ();
85+
86+ // init the map
87+ if (!Maps->Start ())
88+ {
89+ c->con .printerr (" Can't initialize map.\n " );
90+ c->Resume ();
91+ return CR_FAILURE ;
92+ }
93+ MapCache MC (Maps);
94+ int i = 0 ;
95+ int dumped_total = 0 ;
96+
97+ int cx, cy, cz;
98+ DFCoord pos_cursor;
99+ if (!destroy)
100+ {
101+ if (!Gui->getCursorCoords (cx,cy,cz))
102+ {
103+ c->con .printerr (" Cursor position not found. Please enabled the cursor.\n " );
104+ c->Resume ();
105+ return CR_FAILURE ;
106+ }
107+ pos_cursor = DFCoord (cx,cy,cz);
108+ {
109+ Block * b = MC .BlockAt (pos_cursor / 16 );
110+ if (!b)
111+ {
112+ c->con .printerr (" Cursor is in an invalid/uninitialized area. Place it over a floor.\n " );
113+ c->Resume ();
114+ return CR_FAILURE ;
115+ }
116+ uint16_t ttype = MC .tiletypeAt (pos_cursor);
117+ if (!DFHack::isFloorTerrain (ttype))
118+ {
119+ c->con .printerr (" Cursor should be placed over a floor.\n " );
120+ c->Resume ();
121+ return CR_FAILURE ;
122+ }
123+ }
124+ }
125+ coordmap counts;
126+ // proceed with the dumpification operation
127+ for (std::size_t i=0 ; i< numItems; i++)
128+ {
129+ t_item * itm = p_items[i];
130+ DFCoord pos_item (itm->x , itm->y , itm->z );
131+
132+ // keep track how many items are at places. all items.
133+ coordmap::iterator it = counts.find (pos_item);
134+ if (it == counts.end ())
135+ {
136+ std::pair< coordmap::iterator, bool > inserted = counts.insert (std::make_pair (pos_item,1 ));
137+ it = inserted.first ;
138+ }
139+ else
140+ {
141+ it->second ++;
142+ }
143+ // iterator is valid here, we use it later to decrement the pile counter if the item is moved
144+
145+ // only dump the stuff marked for dumping and laying on the ground
146+ if ( !itm->flags .dump
147+ || !itm->flags .on_ground
148+ || itm->flags .construction
149+ || itm->flags .hidden
150+ || itm->flags .in_building
151+ || itm->flags .in_chest
152+ || itm->flags .in_inventory
153+ || itm->flags .construction
154+ )
155+ continue ;
156+
157+ if (!destroy) // move to cursor
158+ {
159+ // Change flags to indicate the dump was completed, as if by super-dwarfs
160+ itm->flags .dump = false ;
161+ itm->flags .forbid = true ;
162+
163+ // Don't move items if they're already at the cursor
164+ if (pos_cursor == pos_item)
165+ continue ;
166+
167+ // Move the item
168+ itm->x = pos_cursor.x ;
169+ itm->y = pos_cursor.y ;
170+ itm->z = pos_cursor.z ;
171+ }
172+ else // destroy
173+ {
174+ itm->flags .garbage_colect = true ;
175+ }
176+ // keeping track of item pile sizes ;)
177+ it->second --;
178+ dumped_total++;
179+ }
180+ if (!destroy) // TODO: do we have to do any of this when destroying items?
181+ {
182+ // for each item pile, see if it reached zero. if so, unset item flag on the tile it's on
183+ coordmap::iterator it = counts.begin ();
184+ coordmap::iterator end = counts.end ();
185+ while (it != end)
186+ {
187+ if (it->second == 0 )
188+ {
189+ t_occupancy occ = MC .occupancyAt (it->first );
190+ occ.bits .item = false ;
191+ MC .setOccupancyAt (it->first , occ);
192+ }
193+ it++;
194+ }
195+ // Set "item here" flag on target tile, if we moved any items to the target tile.
196+ if (dumped_total > 0 )
197+ {
198+ // assume there is a possibility the cursor points at some weird location with missing block data
199+ Block * b = MC .BlockAt (pos_cursor / 16 );
200+ if (b)
201+ {
202+ t_occupancy occ = MC .occupancyAt (pos_cursor);
203+ occ.bits .item = 1 ;
204+ MC .setOccupancyAt (pos_cursor,occ);
205+ }
206+ }
207+ // write map changes back to DF.
208+ MC .WriteAll ();
209+ // Is this necessary? Is "forbid" a dirtyable attribute like "dig" is?
210+ Maps->WriteDirtyBit (cx/16 , cy/16 , cz, true );
211+ }
212+ c->Resume ();
213+ c->con .print (" Done. %d items %s.\n " , dumped_total, destroy ? " marked for desctruction" : " quickdumped" );
214+ return CR_OK ;
215+ }
0 commit comments