2013-01-03 16:14:16 -07:00
# include "assignJob.h"
# include "edgeCost.h"
2012-08-23 18:37:43 -06:00
# include "Core.h"
2012-12-16 14:53:02 -07:00
# include "Console.h"
2012-08-23 18:37:43 -06:00
# include "DataDefs.h"
2012-12-16 14:53:02 -07:00
# include "Export.h"
# include "PluginManager.h"
# include "Types.h"
# include "modules/Buildings.h"
# include "modules/EventManager.h"
2013-01-04 19:02:09 -07:00
# include "modules/Gui.h"
2012-12-19 16:46:46 -07:00
# include "modules/Job.h"
2012-12-16 19:44:23 -07:00
# include "modules/Maps.h"
2012-12-16 14:53:02 -07:00
# include "modules/MapCache.h"
2012-12-16 19:44:23 -07:00
# include "modules/Units.h"
2012-12-16 14:53:02 -07:00
# include "modules/World.h"
2012-12-19 16:46:46 -07:00
# include "df/body_part_raw_flags.h"
2012-08-23 18:37:43 -06:00
# include "df/building.h"
2012-12-19 16:46:46 -07:00
# include "df/building_type.h"
# include "df/caste_body_info.h"
2012-08-23 18:37:43 -06:00
# include "df/coord.h"
2013-01-03 21:18:40 -07:00
# include "df/creature_raw.h"
2012-12-19 16:46:46 -07:00
# include "df/general_ref.h"
# include "df/general_ref_building_holderst.h"
# include "df/general_ref_unit.h"
# include "df/general_ref_unit_holderst.h"
# include "df/general_ref_unit_workerst.h"
2013-05-31 17:27:22 -06:00
# include "df/global_objects.h"
2013-01-03 19:25:50 -07:00
# include "df/invasion_info.h"
2012-12-19 16:46:46 -07:00
# include "df/item.h"
# include "df/itemdef_weaponst.h"
# include "df/item_quality.h"
# include "df/item_weaponst.h"
2012-12-17 18:12:11 -07:00
# include "df/inorganic_raw.h"
2012-12-19 16:46:46 -07:00
# include "df/job.h"
2013-06-09 21:07:51 -06:00
# include "df/job_list_link.h"
2012-12-19 16:46:46 -07:00
# include "df/job_skill.h"
# include "df/job_type.h"
2012-08-23 18:37:43 -06:00
# include "df/map_block.h"
2012-12-17 18:12:11 -07:00
# include "df/strain_type.h"
2012-12-19 16:46:46 -07:00
# include "df/tile_building_occ.h"
# include "df/tile_occupancy.h"
2012-12-17 15:36:35 -07:00
# include "df/tiletype.h"
2012-12-17 18:12:11 -07:00
# include "df/tiletype_material.h"
2012-12-17 15:36:35 -07:00
# include "df/tiletype_shape.h"
# include "df/tiletype_shape_basic.h"
2012-12-19 16:46:46 -07:00
# include "df/ui.h"
# include "df/unit.h"
# include "df/unit_inventory_item.h"
2012-08-23 18:37:43 -06:00
# include "df/world.h"
2012-08-24 09:40:51 -06:00
2012-08-23 18:37:43 -06:00
# include <algorithm>
2012-12-17 18:44:35 -07:00
# include <ctime>
2012-12-17 15:36:35 -07:00
# include <cstdlib>
2012-12-17 12:22:45 -07:00
# include <cstring>
2012-12-17 18:12:11 -07:00
# include <iostream>
2012-08-23 18:37:43 -06:00
# include <map>
# include <set>
2012-12-16 14:53:02 -07:00
# include <vector>
2012-12-18 13:22:21 -07:00
# include <unordered_map>
2013-06-09 14:23:41 -06:00
# include <unordered_set>
2012-12-18 13:22:21 -07:00
2012-08-23 18:37:43 -06:00
using namespace std ;
using namespace DFHack ;
using namespace df : : enums ;
2013-06-09 21:07:51 -06:00
command_result diggingInvadersCommand ( color_ostream & out , std : : vector < std : : string > & parameters ) ;
2013-01-03 19:25:50 -07:00
void watchForJobComplete ( color_ostream & out , void * ptr ) ;
2013-06-09 21:07:51 -06:00
void newInvasionHandler ( color_ostream & out , void * ptr ) ;
//int32_t manageInvasion(color_ostream& out);
2012-08-23 18:37:43 -06:00
DFHACK_PLUGIN ( " diggingInvaders " ) ;
2013-01-03 19:25:50 -07:00
//TODO: when world unloads
static int32_t lastInvasionJob = - 1 ;
2013-01-03 22:08:54 -07:00
static int32_t lastInvasionDigger = - 1 ;
2013-06-09 21:07:51 -06:00
//static EventManager::EventHandler jobCompleteHandler(watchForJobComplete, 5);
2013-01-03 21:18:40 -07:00
static bool enabled = false ;
2013-06-09 21:07:51 -06:00
static bool activeDigging = false ;
static unordered_set < string > diggingRaces ;
static unordered_set < int32_t > invaderJobs ;
static df : : coord lastDebugEdgeCostPoint ;
2013-01-03 19:25:50 -07:00
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
2012-08-23 18:37:43 -06:00
{
2013-06-09 21:07:51 -06:00
EventManager : : EventHandler handler ( newInvasionHandler , 1000 ) ;
EventManager : : registerListener ( EventManager : : EventType : : INVASION , handler , plugin_self ) ;
2013-06-09 14:23:41 -06:00
2012-08-23 18:37:43 -06:00
commands . push_back ( PluginCommand (
" diggingInvaders " , " Makes invaders dig to your dwarves. " ,
2013-06-09 21:07:51 -06:00
diggingInvadersCommand , false , /* true means that the command can't be used from non-interactive user interface */
2013-01-03 21:18:40 -07:00
" diggingInvaders enable \n enables the plugin \n "
" diggingInvaders disable \n disables the plugin \n "
" diggingInvaders add GOBLIN \n registers the race GOBLIN as a digging invader \n "
" diggingInvaders remove GOBLIN \n unregisters the race GOBLIN as a digging invader \n "
" diggingInvaders \n Makes invaders try to dig now. \n "
2012-08-23 18:37:43 -06:00
) ) ;
2013-01-03 20:46:17 -07:00
2013-06-09 21:07:51 -06:00
* df : : global : : debug_showambush = true ;
2012-08-23 18:37:43 -06:00
return CR_OK ;
}
DFhackCExport command_result plugin_shutdown ( color_ostream & out )
{
return CR_OK ;
}
2013-01-03 20:46:17 -07:00
DFhackCExport command_result plugin_onstatechange ( color_ostream & out , state_change_event event )
{
2013-06-09 21:07:51 -06:00
EventManager : : EventHandler invasionHandler ( newInvasionHandler , 1000 ) ;
2013-01-03 20:46:17 -07:00
switch ( event ) {
case DFHack : : SC_WORLD_LOADED :
//TODO: check game mode
lastInvasionJob = - 1 ;
//in case there are invaders when the game is loaded, we should check
2013-06-09 14:23:41 -06:00
EventManager : : registerTick ( invasionHandler , 10 , plugin_self ) ;
2013-01-03 20:46:17 -07:00
break ;
case DFHack : : SC_WORLD_UNLOADED :
// cleanup
break ;
default :
break ;
}
return CR_OK ;
}
2012-12-18 13:22:21 -07:00
df : : coord getRoot ( df : : coord point , unordered_map < df : : coord , df : : coord > & rootMap ) ;
2012-08-23 18:37:43 -06:00
class PointComp {
public :
2013-06-09 21:17:31 -06:00
unordered_map < df : : coord , cost_t , PointHash > * pointCost ;
PointComp ( unordered_map < df : : coord , cost_t , PointHash > * p ) : pointCost ( p ) {
2012-08-23 20:25:25 -06:00
}
2012-12-16 15:06:46 -07:00
int32_t operator ( ) ( df : : coord p1 , df : : coord p2 ) {
2012-12-16 19:44:23 -07:00
if ( p1 = = p2 ) return 0 ;
2012-12-17 12:22:45 -07:00
auto i1 = pointCost - > find ( p1 ) ;
auto i2 = pointCost - > find ( p2 ) ;
2012-08-23 20:25:25 -06:00
if ( i1 = = pointCost - > end ( ) & & i2 = = pointCost - > end ( ) )
return p1 < p2 ;
if ( i1 = = pointCost - > end ( ) )
2012-12-17 12:22:45 -07:00
return true ;
2012-08-23 20:25:25 -06:00
if ( i2 = = pointCost - > end ( ) )
2012-12-17 12:22:45 -07:00
return false ;
2013-06-09 21:17:31 -06:00
cost_t c1 = ( * i1 ) . second ;
cost_t c2 = ( * i2 ) . second ;
2012-08-23 20:25:25 -06:00
if ( c1 ! = c2 )
return c1 < c2 ;
return p1 < p2 ;
}
2012-08-23 18:37:43 -06:00
} ;
2012-12-18 13:22:21 -07:00
//bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges);
2013-06-09 21:07:51 -06:00
void findAndAssignInvasionJob ( color_ostream & out , void * ) ;
2013-01-03 16:45:53 -07:00
2013-06-09 21:07:51 -06:00
void newInvasionHandler ( color_ostream & out , void * ptr ) {
if ( activeDigging )
return ;
activeDigging = true ;
EventManager : : EventHandler handler ( findAndAssignInvasionJob , 1 ) ;
EventManager : : registerTick ( handler , 1 , plugin_self ) ;
#if 0
2013-01-03 19:25:50 -07:00
//called when there's a new invasion
//TODO: check if invaders can dig
2013-01-03 22:08:54 -07:00
if ( manageInvasion ( out ) = = - 2 )
return ;
//schedule the next thing
uint32_t tick = World : : ReadCurrentTick ( ) ;
tick = tick % 1000 ;
tick = 1000 - tick ;
2013-06-09 21:07:51 -06:00
EventManager : : EventHandler handle ( newInvasionHandler , 1000 ) ;
2013-06-09 14:23:41 -06:00
EventManager : : registerTick ( handle , tick , plugin_self ) ;
2013-06-09 21:07:51 -06:00
# endif
2013-01-03 19:25:50 -07:00
}
2013-01-03 16:45:53 -07:00
2013-06-09 21:07:51 -06:00
#if 0
2013-01-03 19:25:50 -07:00
void watchForJobComplete ( color_ostream & out , void * ptr ) {
2013-05-31 17:27:22 -06:00
/*
2013-01-03 16:45:53 -07:00
df : : job * job = ( df : : job * ) ptr ;
if ( job - > id ! = lastInvasionJob )
return ;
2013-06-09 14:23:41 -06:00
EventManager : : unregister ( EventManager : : EventType : : JOB_COMPLETED , jobCompleteHandler , plugin_self ) ;
2013-05-31 17:27:22 -06:00
*/
2013-01-03 16:45:53 -07:00
2013-01-03 22:35:47 -07:00
manageInvasion ( out ) ;
2013-01-03 16:45:53 -07:00
}
2013-06-09 21:07:51 -06:00
# endif
2012-12-16 19:44:23 -07:00
2013-06-09 21:07:51 -06:00
#if 0
2013-01-03 19:25:50 -07:00
int32_t manageInvasion ( color_ostream & out ) {
2013-05-31 18:39:43 -06:00
//EventManager::unregisterAll(plugin_self);
2013-01-03 20:46:17 -07:00
if ( ! enabled ) {
return - 1 ;
}
int32_t lastInvasion = df : : global : : ui - > invasions . next_id - 1 ;
if ( lastInvasion < 0 | | df : : global : : ui - > invasions . list [ lastInvasion ] - > flags . bits . active = = 0 ) {
2013-01-03 19:25:50 -07:00
//if the invasion is over, we're done
2013-01-03 22:43:39 -07:00
//out.print("Invasion is over. Stopping diggingInvaders.\n");
2013-01-03 22:08:54 -07:00
return - 2 ;
2013-01-03 19:25:50 -07:00
}
2013-05-31 17:27:22 -06:00
EventManager : : registerTick ( jobCompleteHandler , 1 , plugin_self ) ;
2013-01-03 16:45:53 -07:00
if ( lastInvasionJob ! = - 1 ) {
2013-01-03 22:08:54 -07:00
//check if he's still doing it
2013-05-31 17:27:22 -06:00
df : : unit * worker = df : : unit : : find ( lastInvasionDigger ) ;
//int32_t index = df::unit::binsearch_index(df::global::world->units.all, lastInvasionDigger);
if ( ! worker ) {
2013-01-03 22:08:54 -07:00
out . print ( " Error %s line %d. \n " , __FILE__ , __LINE__ ) ;
return - 1 ;
}
2013-05-31 17:27:22 -06:00
df : : job * job = worker - > job . current_job ;
2013-01-03 22:43:39 -07:00
//out.print("job id: old = %d, new = %d\n", lastInvasionJob, job == NULL ? -1 : job->id);
2013-01-03 22:35:47 -07:00
if ( job ! = NULL & & lastInvasionJob = = job - > id ) {
2013-01-03 22:43:39 -07:00
//out.print("Still working on the previous job.\n");
2013-01-03 22:08:54 -07:00
return - 1 ;
}
//return 1; //still invading, but nothing new done
2013-01-03 16:45:53 -07:00
}
2013-05-31 17:27:22 -06:00
2013-01-03 22:08:54 -07:00
int32_t unitId = findAndAssignInvasionJob ( out ) ;
if ( unitId = = - 1 ) {
2013-01-03 19:25:50 -07:00
//might need to do more digging later, after we've killed off a few locals
2013-01-03 22:43:39 -07:00
//out.print("DiggingInvaders is waiting.\n");
2013-01-03 19:25:50 -07:00
return - 1 ;
}
2013-01-03 16:45:53 -07:00
2013-01-03 22:08:54 -07:00
lastInvasionDigger = unitId ;
{
2013-06-09 15:52:13 -06:00
df : : unit * unit = df : : unit : : find ( unitId ) ;
if ( ! unit ) {
2013-01-05 09:06:46 -07:00
//out.print("Error %s line %d: unitId = %d, index = %d.\n", __FILE__, __LINE__, unitId, index);
2013-01-03 22:08:54 -07:00
return - 1 ;
}
2013-06-09 15:52:13 -06:00
lastInvasionJob = unit - > job . current_job - > id ;
2013-01-03 22:08:54 -07:00
}
2013-01-03 16:45:53 -07:00
2013-06-09 14:23:41 -06:00
//EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, jobCompleteHandler, plugin_self);
2013-01-03 22:43:39 -07:00
//out.print("DiggingInvaders: job assigned.\n");
2013-06-09 15:52:13 -06:00
* df : : global : : pause_state = true ;
2013-01-03 19:25:50 -07:00
return 0 ; //did something
}
2013-06-09 21:07:51 -06:00
# endif
2013-01-03 19:25:50 -07:00
2013-06-09 21:07:51 -06:00
command_result diggingInvadersCommand ( color_ostream & out , std : : vector < std : : string > & parameters ) {
2013-01-03 21:18:40 -07:00
for ( size_t a = 0 ; a < parameters . size ( ) ; a + + ) {
if ( parameters [ a ] = = " enable " ) {
enabled = true ;
} else if ( parameters [ a ] = = " disable " ) {
enabled = false ;
} else if ( parameters [ a ] = = " add " | | parameters [ a ] = = " remove " ) {
if ( a + 1 > = parameters . size ( ) )
return CR_WRONG_USAGE ;
string race = parameters [ a + 1 ] ;
2013-06-09 21:07:51 -06:00
if ( parameters [ a ] = = " add " ) {
diggingRaces . insert ( race ) ;
} else {
diggingRaces . erase ( race ) ;
}
/*bool foundIt = false;
2013-01-03 21:18:40 -07:00
for ( size_t b = 0 ; b < df : : global : : world - > raws . creatures . all . size ( ) ; b + + ) {
df : : creature_raw * raw = df : : global : : world - > raws . creatures . all [ b ] ;
if ( race = = raw - > creature_id ) {
2013-01-03 22:43:39 -07:00
//out.print("%s = %s\n", race.c_str(), raw->creature_id.c_str());
2013-01-03 21:18:40 -07:00
if ( parameters [ a ] = = " add " ) {
diggingRaces . insert ( b ) ;
} else {
diggingRaces . erase ( b ) ;
}
foundIt = true ;
break ;
}
}
if ( ! foundIt ) {
out . print ( " Couldn't find \" %s \" \n " , race . c_str ( ) ) ;
return CR_WRONG_USAGE ;
2013-06-09 21:07:51 -06:00
} */
2013-01-03 21:18:40 -07:00
a + + ;
2013-01-04 19:02:09 -07:00
} else if ( parameters [ a ] = = " setCost " ) {
if ( a + 2 > = parameters . size ( ) )
return CR_WRONG_USAGE ;
string costStr = parameters [ a + 1 ] ;
int32_t costDim = - 1 ;
2013-01-05 09:06:46 -07:00
if ( costStr = = " walk " ) {
costDim = CostDimension : : Walk ;
2013-01-04 19:02:09 -07:00
} else if ( costStr = = " destroyBuilding " ) {
costDim = CostDimension : : DestroyBuilding ;
} else if ( costStr = = " dig " ) {
costDim = CostDimension : : Dig ;
} else if ( costStr = = " destroyConstruction " ) {
costDim = CostDimension : : DestroyConstruction ;
} else {
return CR_WRONG_USAGE ;
}
2013-06-09 21:17:31 -06:00
cost_t value ;
2013-01-04 19:02:09 -07:00
stringstream asdf ( parameters [ a + 2 ] ) ;
asdf > > value ;
if ( value < = 0 )
return CR_WRONG_USAGE ;
costWeight [ costDim ] = value ;
a + = 2 ;
} else if ( parameters [ a ] = = " edgeCost " ) {
df : : coord bob = Gui : : getCursorPos ( ) ;
out . print ( " (%d,%d,%d), (%d,%d,%d): cost = %lld \n " , lastDebugEdgeCostPoint . x , lastDebugEdgeCostPoint . y , lastDebugEdgeCostPoint . z , bob . x , bob . y , bob . z , getEdgeCost ( out , lastDebugEdgeCostPoint , bob ) ) ;
lastDebugEdgeCostPoint = bob ;
}
else {
return CR_WRONG_USAGE ;
2013-01-03 21:18:40 -07:00
}
}
2013-05-31 18:39:43 -06:00
2013-06-09 21:07:51 -06:00
if ( parameters . size ( ) = = 0 ) {
//manageInvasion(out);
newInvasionHandler ( out , ( void * ) 0 ) ;
}
2012-12-17 18:12:11 -07:00
return CR_OK ;
}
2013-06-09 21:07:51 -06:00
/////////////////////////////////////////////////////////////////////////////////////////
//dijkstra globals
vector < int32_t > invaders ;
unordered_set < df : : coord , PointHash > invaderPts ;
unordered_set < df : : coord , PointHash > localPts ;
unordered_map < df : : coord , df : : coord , PointHash > parentMap ;
2013-06-09 21:17:31 -06:00
unordered_map < df : : coord , cost_t , PointHash > costMap ;
2013-06-09 21:07:51 -06:00
PointComp comp ( & costMap ) ;
set < df : : coord , PointComp > fringe ( comp ) ;
EventManager : : EventHandler findJobTickHandler ( findAndAssignInvasionJob , 1 ) ;
2013-06-09 21:17:31 -06:00
const int32_t edgesPerFrame = 10000000 ;
2013-06-09 21:07:51 -06:00
int32_t localPtsFound = 0 ;
unordered_set < df : : coord , PointHash > closedSet ;
unordered_map < df : : coord , int32_t , PointHash > workNeeded ; //non-walking work needed to get there
bool foundTarget = false ;
int32_t edgeCount = 0 ;
void clearDijkstra ( ) {
invaders . clear ( ) ;
invaderPts . clear ( ) ;
localPts . clear ( ) ;
parentMap . clear ( ) ;
costMap . clear ( ) ;
comp = PointComp ( & costMap ) ;
fringe = set < df : : coord , PointComp > ( comp ) ;
localPtsFound = edgeCount = 0 ;
foundTarget = false ;
closedSet . clear ( ) ;
workNeeded . clear ( ) ;
}
/////////////////////////////////////////////////////////////////////////////////////////
void findAndAssignInvasionJob ( color_ostream & out , void * tickTime ) {
CoreSuspender suspend ;
//returns the worker id of the job created //used to
//out.print("%s, %d: %d\n", __FILE__, __LINE__, (int32_t)tickTime);
2012-08-23 18:37:43 -06:00
2013-06-09 21:07:51 -06:00
if ( ! activeDigging ) {
clearDijkstra ( ) ;
return ;
}
EventManager : : unregister ( EventManager : : EventType : : TICK , findJobTickHandler , plugin_self ) ;
EventManager : : registerTick ( findJobTickHandler , 1 , plugin_self ) ;
2013-06-09 15:52:13 -06:00
2013-06-09 21:07:51 -06:00
if ( fringe . empty ( ) ) {
df : : unit * lastDigger = df : : unit : : find ( lastInvasionDigger ) ;
if ( lastDigger & & lastDigger - > job . current_job & & lastDigger - > job . current_job - > id = = lastInvasionJob ) {
return ;
}
//out.print("%s,%d: lastDigger = %d, last job = %d, last digger's job = %d\n", __FILE__, __LINE__, lastInvasionDigger, lastInvasionJob, !lastDigger ? -1 : (!lastDigger->job.current_job ? -1 : lastDigger->job.current_job->id));
lastInvasionDigger = lastInvasionJob = - 1 ;
clearDijkstra ( ) ;
unordered_set < uint16_t > invaderConnectivity ;
unordered_set < uint16_t > localConnectivity ;
//find all locals and invaders
for ( size_t a = 0 ; a < df : : global : : world - > units . all . size ( ) ; a + + ) {
df : : unit * unit = df : : global : : world - > units . all [ a ] ;
if ( unit - > flags1 . bits . dead )
2012-12-17 11:37:02 -07:00
continue ;
2013-06-09 21:07:51 -06:00
if ( Units : : isCitizen ( unit ) ) {
if ( localPts . find ( unit - > pos ) ! = localPts . end ( ) )
continue ;
localPts . insert ( unit - > pos ) ;
df : : map_block * block = Maps : : getTileBlock ( unit - > pos ) ;
localConnectivity . insert ( block - > walkable [ unit - > pos . x & 0xF ] [ unit - > pos . y & 0xF ] ) ;
} else if ( unit - > flags1 . bits . active_invader ) {
df : : creature_raw * raw = df : : creature_raw : : find ( unit - > race ) ;
if ( raw = = NULL ) {
out . print ( " %s,%d: WTF? Couldn't find creature raw. \n " , __FILE__ , __LINE__ ) ;
continue ;
}
if ( diggingRaces . find ( raw - > creature_id ) = = diggingRaces . end ( ) )
continue ;
if ( invaderPts . find ( unit - > pos ) ! = invaderPts . end ( ) )
continue ;
//must be able to wield a pick: this is overly pessimistic
if ( unit - > status2 . limbs_grasp_count < unit - > status2 . limbs_grasp_max )
continue ;
df : : map_block * block = Maps : : getTileBlock ( unit - > pos ) ;
invaderConnectivity . insert ( block - > walkable [ unit - > pos . x & 0xF ] [ unit - > pos . y & 0xF ] ) ;
if ( invaderPts . size ( ) > 0 )
continue ;
invaderPts . insert ( unit - > pos ) ;
costMap [ unit - > pos ] = 0 ;
fringe . insert ( unit - > pos ) ;
invaders . push_back ( unit - > id ) ;
} else {
2013-06-09 15:52:13 -06:00
continue ;
2013-06-09 21:07:51 -06:00
}
2012-12-17 11:37:02 -07:00
}
2013-01-03 11:11:11 -07:00
2013-06-09 21:07:51 -06:00
if ( invaders . empty ( ) | | localPts . empty ( ) ) {
activeDigging = false ;
return ;
}
2013-01-03 20:46:17 -07:00
2013-06-09 21:07:51 -06:00
//if local connectivity is not disjoint from invader connectivity, no digging required
bool overlap = false ;
for ( auto a = localConnectivity . begin ( ) ; a ! = localConnectivity . end ( ) ; a + + ) {
uint16_t conn = * a ;
if ( invaderConnectivity . find ( conn ) = = invaderConnectivity . end ( ) )
continue ;
overlap = true ;
break ;
}
if ( overlap ) {
//still keep checking next frame: might kill a few outsiders then dig down
return ;
}
2013-01-03 20:46:17 -07:00
}
2013-06-09 21:07:51 -06:00
df : : unit * firstInvader = df : : unit : : find ( invaders [ 0 ] ) ;
if ( firstInvader = = NULL ) {
fringe . clear ( ) ;
return ;
2013-01-03 20:46:17 -07:00
}
2013-06-09 21:07:51 -06:00
//TODO: check that firstInvader is an appropriate digger
2013-05-31 18:39:43 -06:00
//out << firstInvader->id << endl;
//out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl;
//out << __LINE__ << endl;
2013-06-09 21:07:51 -06:00
uint32_t xMax , yMax , zMax ;
Maps : : getSize ( xMax , yMax , zMax ) ;
xMax * = 16 ;
yMax * = 16 ;
MapExtras : : MapCache cache ;
2012-12-16 19:44:23 -07:00
2012-12-17 18:44:35 -07:00
clock_t t0 = clock ( ) ;
clock_t totalEdgeTime = 0 ;
2013-06-09 21:07:51 -06:00
int32_t edgesExpanded = 0 ;
2012-12-17 11:37:02 -07:00
while ( ! fringe . empty ( ) ) {
2013-06-09 21:07:51 -06:00
if ( edgesExpanded + + > = edgesPerFrame ) {
return ;
}
2012-12-17 11:37:02 -07:00
df : : coord pt = * ( fringe . begin ( ) ) ;
fringe . erase ( fringe . begin ( ) ) ;
2013-05-31 17:27:22 -06:00
//out.print("line %d: fringe size = %d, localPtsFound = %d / %d, closedSetSize = %d, pt = %d,%d,%d\n", __LINE__, fringe.size(), localPtsFound, localPts.size(), closedSet.size(), pt.x,pt.y,pt.z);
2012-12-17 11:37:02 -07:00
if ( closedSet . find ( pt ) ! = closedSet . end ( ) ) {
2013-01-03 22:43:39 -07:00
out . print ( " %s, line %d: Double closure! Bad! \n " , __FILE__ , __LINE__ ) ;
2012-12-17 11:37:02 -07:00
break ;
}
2012-12-19 16:46:46 -07:00
closedSet . insert ( pt ) ;
2012-12-17 11:37:02 -07:00
if ( localPts . find ( pt ) ! = localPts . end ( ) ) {
localPtsFound + + ;
2013-01-04 19:02:09 -07:00
if ( true | | localPtsFound > = localPts . size ( ) ) {
2013-01-03 22:35:47 -07:00
foundTarget = true ;
2012-12-17 11:37:02 -07:00
break ;
2013-01-03 22:35:47 -07:00
}
2013-01-03 12:38:05 -07:00
if ( workNeeded . find ( pt ) = = workNeeded . end ( ) | | workNeeded [ pt ] = = 0 ) {
//there are still dwarves to kill that don't require digging to get to
2013-06-09 21:07:51 -06:00
return ;
2013-01-03 12:38:05 -07:00
}
2012-12-17 11:37:02 -07:00
}
2012-12-16 19:44:23 -07:00
2013-06-09 21:17:31 -06:00
cost_t myCost = costMap [ pt ] ;
2012-12-17 18:44:35 -07:00
clock_t edgeTime = clock ( ) ;
vector < Edge > * myEdges = getEdgeSet ( out , pt , cache , xMax , yMax , zMax ) ;
totalEdgeTime + = ( clock ( ) - edgeTime ) ;
for ( auto a = myEdges - > begin ( ) ; a ! = myEdges - > end ( ) ; a + + ) {
Edge & e = * a ;
2013-01-04 16:11:38 -07:00
if ( e . p1 = = df : : coord ( ) )
break ;
edgeCount + + ;
2012-12-17 18:44:35 -07:00
df : : coord & other = e . p1 ;
2012-12-17 11:37:02 -07:00
if ( other = = pt )
other = e . p2 ;
2012-12-18 13:22:21 -07:00
//if ( closedSet.find(other) != closedSet.end() )
// continue;
auto i = costMap . find ( other ) ;
if ( i ! = costMap . end ( ) ) {
2013-06-09 21:17:31 -06:00
cost_t cost = ( * i ) . second ;
2012-12-18 13:22:21 -07:00
if ( cost < = myCost + e . cost ) {
continue ;
}
fringe . erase ( ( * i ) . first ) ;
2012-08-23 20:25:25 -06:00
}
2012-12-18 13:22:21 -07:00
costMap [ other ] = myCost + e . cost ;
fringe . insert ( other ) ;
parentMap [ other ] = pt ;
2012-12-19 22:35:45 -07:00
workNeeded [ other ] = ( e . cost > 1 ? 1 : 0 ) + workNeeded [ pt ] ;
2012-08-23 20:25:25 -06:00
}
2012-12-17 18:44:35 -07:00
delete myEdges ;
2012-12-17 11:37:02 -07:00
}
2012-12-17 18:44:35 -07:00
clock_t time = clock ( ) - t0 ;
2013-06-09 21:17:31 -06:00
out . print ( " tickTime = %d, time = %d, totalEdgeTime = %d, total points = %d, total edges = %d, time per point = %.3f, time per edge = %.3f, clocks/sec = %d \n " , ( int32_t ) tickTime , time , totalEdgeTime , closedSet . size ( ) , edgeCount , ( float ) time / closedSet . size ( ) , ( float ) time / edgeCount , CLOCKS_PER_SEC ) ;
2013-06-09 21:07:51 -06:00
fringe . clear ( ) ;
2012-12-17 11:37:02 -07:00
2013-01-03 22:35:47 -07:00
if ( ! foundTarget )
2013-06-09 21:07:51 -06:00
return ;
2013-01-03 22:35:47 -07:00
2012-12-19 16:46:46 -07:00
unordered_set < df : : coord , PointHash > requiresZNeg ;
unordered_set < df : : coord , PointHash > requiresZPos ;
2013-06-09 21:07:51 -06:00
2012-12-17 11:37:02 -07:00
//find important edges
2013-01-03 12:16:10 -07:00
Edge firstImportantEdge ( df : : coord ( ) , df : : coord ( ) , - 1 ) ;
2013-06-09 21:07:51 -06:00
df : : coord closest ;
2013-06-09 21:17:31 -06:00
cost_t closestCostEstimate = 0 ;
cost_t closestCostActual = 0 ;
2012-12-17 11:37:02 -07:00
for ( auto i = localPts . begin ( ) ; i ! = localPts . end ( ) ; i + + ) {
df : : coord pt = * i ;
if ( costMap . find ( pt ) = = costMap . end ( ) )
continue ;
if ( parentMap . find ( pt ) = = parentMap . end ( ) )
continue ;
2013-06-09 21:07:51 -06:00
closest = pt ;
closestCostEstimate = costMap [ closest ] ;
2013-01-03 12:16:10 -07:00
//if ( workNeeded[pt] == 0 )
// continue;
2012-12-17 11:37:02 -07:00
while ( parentMap . find ( pt ) ! = parentMap . end ( ) ) {
2013-01-03 12:38:05 -07:00
//out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z);
2012-12-17 11:37:02 -07:00
df : : coord parent = parentMap [ pt ] ;
2013-06-09 21:07:51 -06:00
closestCostActual + = getEdgeCost ( out , parent , pt ) ;
2013-01-03 11:32:50 -07:00
if ( Maps : : canStepBetween ( parent , pt ) ) {
2013-01-02 20:11:05 -07:00
} else {
2013-01-03 11:11:11 -07:00
if ( pt . x = = parent . x & & pt . y = = parent . y ) {
if ( pt . z < parent . z ) {
requiresZNeg . insert ( parent ) ;
requiresZPos . insert ( pt ) ;
} else if ( pt . z > parent . z ) {
requiresZNeg . insert ( pt ) ;
requiresZPos . insert ( parent ) ;
}
2013-01-02 20:11:05 -07:00
}
//if ( workNeeded[pt] > workNeeded[parent] ) {
2013-01-03 12:16:10 -07:00
//importantEdges.push_front(Edge(pt,parent,0));
2013-01-02 20:11:05 -07:00
//}
2013-01-03 12:16:10 -07:00
firstImportantEdge = Edge ( pt , parent , 0 ) ;
2013-01-03 22:43:39 -07:00
//out.print("(%d,%d,%d) -> (%d,%d,%d)\n", parent.x,parent.y,parent.z, pt.x,pt.y,pt.z);
2012-12-19 16:46:46 -07:00
}
2012-12-17 11:37:02 -07:00
pt = parent ;
2012-08-23 20:25:25 -06:00
}
2012-12-17 12:22:45 -07:00
break ;
2012-12-16 19:44:23 -07:00
}
2013-06-09 21:07:51 -06:00
if ( firstImportantEdge . p1 = = df : : coord ( ) )
return ;
if ( closestCostActual ! = closestCostEstimate ) {
out . print ( " %s,%d: closest = (%d,%d,%d), estimate = %lld != actual = %lld \n " , __FILE__ , __LINE__ , closest . x , closest . y , closest . z , closestCostEstimate , closestCostActual ) ;
return ;
}
2013-01-04 19:02:09 -07:00
#if 0
2012-12-19 16:46:46 -07:00
unordered_set < df : : coord , PointHash > toDelete ;
for ( auto a = requiresZNeg . begin ( ) ; a ! = requiresZNeg . end ( ) ; a + + ) {
df : : coord pos = * a ;
df : : tiletype * type = Maps : : getTileType ( pos ) ;
df : : tiletype_shape shape = ENUM_ATTR ( tiletype , shape , * type ) ;
if ( ENUM_ATTR ( tiletype_shape , passable_low , shape ) ) {
toDelete . insert ( pos ) ;
}
}
requiresZNeg . erase ( toDelete . begin ( ) , toDelete . end ( ) ) ;
toDelete . clear ( ) ;
for ( auto a = requiresZPos . begin ( ) ; a ! = requiresZPos . end ( ) ; a + + ) {
df : : coord pos = * a ;
df : : tiletype * type = Maps : : getTileType ( pos ) ;
df : : tiletype_shape shape = ENUM_ATTR ( tiletype , shape , * type ) ;
if ( ENUM_ATTR ( tiletype_shape , passable_high , shape ) ) {
toDelete . insert ( pos ) ;
}
}
requiresZPos . erase ( toDelete . begin ( ) , toDelete . end ( ) ) ;
toDelete . clear ( ) ;
2013-01-04 19:02:09 -07:00
# endif
2012-12-19 22:35:45 -07:00
2013-06-09 21:07:51 -06:00
assignJob ( out , firstImportantEdge , parentMap , costMap , invaders , requiresZNeg , requiresZPos , cache ) ;
lastInvasionDigger = firstInvader - > id ;
lastInvasionJob = firstInvader - > job . current_job ? firstInvader - > job . current_job - > id : - 1 ;
invaderJobs . erase ( lastInvasionJob ) ;
for ( df : : job_list_link * link = & df : : global : : world - > job_list ; link ! = NULL ; link = link - > next ) {
if ( link - > item = = NULL )
continue ;
df : : job * job = link - > item ;
if ( invaderJobs . find ( job - > id ) = = invaderJobs . end ( ) ) {
continue ;
}
//cancel it
job - > flags . bits . item_lost = 1 ;
out . print ( " %s,%d: cancelling job %d. \n " , __FILE__ , __LINE__ , job - > id ) ;
//invaderJobs.remove(job->id);
}
invaderJobs . erase ( lastInvasionJob ) ;
return ;
2012-08-23 18:37:43 -06:00
}
df : : coord getRoot ( df : : coord point , map < df : : coord , df : : coord > & rootMap ) {
2012-08-23 20:25:25 -06:00
map < df : : coord , df : : coord > : : iterator i = rootMap . find ( point ) ;
if ( i = = rootMap . end ( ) ) {
rootMap [ point ] = point ;
return point ;
}
df : : coord parent = ( * i ) . second ;
if ( parent = = point )
return parent ;
df : : coord root = getRoot ( parent , rootMap ) ;
rootMap [ point ] = root ;
return root ;
2012-08-23 18:37:43 -06:00
}