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>
2018-06-11 10:57:06 -06:00
# include <cinttypes>
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 ) ;
2013-06-09 23:58:27 -06:00
void clearDijkstra ( ) ;
void findAndAssignInvasionJob ( color_ostream & out , void * ) ;
2013-06-09 21:07:51 -06:00
//int32_t manageInvasion(color_ostream& out);
2012-08-23 18:37:43 -06:00
2013-10-19 19:42:24 -06:00
DFHACK_PLUGIN_IS_ENABLED ( enabled ) ;
2012-08-23 18:37:43 -06:00
DFHACK_PLUGIN ( " diggingInvaders " ) ;
2014-12-02 19:44:20 -07:00
REQUIRE_GLOBAL ( world ) ;
2012-08-23 18:37:43 -06:00
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 23:58:27 -06:00
static int32_t edgesPerTick = 100 ;
2013-06-09 21:07:51 -06:00
//static EventManager::EventHandler jobCompleteHandler(watchForJobComplete, 5);
static bool activeDigging = false ;
static unordered_set < string > diggingRaces ;
static unordered_set < int32_t > invaderJobs ;
static df : : coord lastDebugEdgeCostPoint ;
2013-06-15 21:04:15 -06:00
unordered_map < string , DigAbilities > digAbilities ;
static cost_t costWeightDefault [ ] = {
//Distance
1 ,
//Destroy Building
2 ,
//Dig
10000 ,
//DestroyRoughConstruction
1000 ,
//DestroySmoothConstruction
100 ,
} ;
static int32_t jobDelayDefault [ ] = {
//Distance
- 1 ,
//Destroy Building
1000 ,
//Dig
1000 ,
//DestroyRoughConstruction
1000 ,
//DestroySmoothConstruction
100 ,
} ;
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
{
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-06-09 23:58:27 -06:00
" diggingInvaders 0 \n disables the plugin \n "
" diggingInvaders 1 \n enables the plugin \n "
2013-01-03 21:18:40 -07:00
" diggingInvaders enable \n enables the plugin \n "
" diggingInvaders disable \n disables the plugin \n "
2013-06-09 23:58:27 -06:00
" diggingInvaders add GOBLIN \n registers the race GOBLIN as a digging invader. Case-sensitive. \n "
" diggingInvaders remove GOBLIN \n unregisters the race GOBLIN as a digging invader. Case-sensitive. \n "
2013-06-15 21:04:15 -06:00
" diggingInvaders setCost GOBLIN walk n \n sets the walk cost in the path algorithm for the race GOBLIN \n "
" diggingInvaders setCost GOBLIN destroyBuilding n \n "
" diggingInvaders setCost GOBLIN dig n \n "
" diggingInvaders setCost GOBLIN destroyRoughConstruction n \n rough constructions are made from boulders \n "
" diggingInvaders setCost GOBLIN destroySmoothConstruction n \n smooth constructions are made from blocks or bars instead of boulders \n "
" diggingInvaders setDelay GOBLIN destroyBuilding n \n adds to the job_completion_timer of destroy building jobs that are assigned to invaders \n "
" diggingInvaders setDelay GOBLIN dig n \n "
" diggingInvaders setDelay GOBLIN destroyRoughConstruction n \n "
" diggingInvaders setDelay GOBLIN destroySmoothConstruction n \n "
2013-06-09 23:58:27 -06:00
" diggingInvaders now \n makes invaders try to dig now, if plugin is enabled \n "
" diggingInvaders clear \n clears all digging invader races \n "
" diggingInvaders edgesPerTick n \n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited. "
// " diggingInvaders\n Makes invaders try to dig now.\n"
2012-08-23 18:37:43 -06:00
) ) ;
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -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-10-19 19:42:24 -06:00
DFhackCExport command_result plugin_enable ( color_ostream & out , bool enable ) {
if ( enabled = = enable )
return CR_OK ;
2015-02-14 20:53:06 -07:00
2013-10-19 19:42:24 -06:00
enabled = enable ;
EventManager : : unregisterAll ( plugin_self ) ;
clearDijkstra ( ) ;
lastInvasionJob = lastInvasionDigger = - 1 ;
activeDigging = false ;
invaderJobs . clear ( ) ;
if ( enabled ) {
EventManager : : EventHandler handler ( newInvasionHandler , 1000 ) ;
EventManager : : registerListener ( EventManager : : EventType : : INVASION , handler , plugin_self ) ;
findAndAssignInvasionJob ( out , ( void * ) 0 ) ;
}
2015-02-14 20:53:06 -07:00
2013-10-19 19:42:24 -06:00
return CR_OK ;
}
2013-01-03 20:46:17 -07:00
DFhackCExport command_result plugin_onstatechange ( color_ostream & out , state_change_event event )
{
switch ( event ) {
case DFHack : : SC_WORLD_LOADED :
//TODO: check game mode
2013-06-09 23:58:27 -06:00
//in case there are invaders when the game is loaded, we check if there's work to be done
activeDigging = enabled ;
clearDijkstra ( ) ;
findAndAssignInvasionJob ( out , ( void * ) 0 ) ;
2013-01-03 20:46:17 -07:00
break ;
case DFHack : : SC_WORLD_UNLOADED :
// cleanup
2013-10-19 19:42:24 -06:00
plugin_enable ( out , false ) ;
2013-01-03 20:46:17 -07:00
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 ) {
2015-02-14 20:53:06 -07:00
2012-08-23 20:25:25 -06:00
}
2015-02-14 20:53:06 -07:00
2017-08-07 07:29:46 -06:00
int32_t operator ( ) ( df : : coord p1 , df : : coord p2 ) const {
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-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 ;
2013-06-09 23:58:27 -06:00
findAndAssignInvasionJob ( out , ( void * ) 0 ) ;
2013-01-03 16:45:53 -07:00
}
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 + + ) {
2013-06-09 23:58:27 -06:00
if ( parameters [ a ] = = " 1 " | | parameters [ a ] = = " enable " ) {
2013-10-19 19:42:24 -06:00
plugin_enable ( out , true ) ;
2013-06-09 23:58:27 -06:00
} else if ( parameters [ a ] = = " 0 " | | parameters [ a ] = = " disable " ) {
2013-10-19 19:42:24 -06:00
plugin_enable ( out , false ) ;
2013-01-03 21:18:40 -07:00
} 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 ) ;
2013-06-15 21:04:15 -06:00
DigAbilities & abilities = digAbilities [ race ] ;
memcpy ( abilities . costWeight , costWeightDefault , costDim * sizeof ( cost_t ) ) ;
memcpy ( abilities . jobDelay , jobDelayDefault , costDim * sizeof ( int32_t ) ) ;
2013-06-09 21:07:51 -06:00
} else {
diggingRaces . erase ( race ) ;
2013-06-15 21:04:15 -06:00
digAbilities . erase ( race ) ;
2013-06-09 21:07:51 -06:00
}
2013-01-03 21:18:40 -07:00
a + + ;
2015-02-14 20:53:06 -07:00
2013-06-11 03:14:56 -06:00
} else if ( parameters [ a ] = = " setCost " | | parameters [ a ] = = " setDelay " ) {
2013-06-15 21:04:15 -06:00
if ( a + 3 > = parameters . size ( ) )
2013-01-04 19:02:09 -07:00
return CR_WRONG_USAGE ;
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
string raceString = parameters [ a + 1 ] ;
if ( digAbilities . find ( raceString ) = = digAbilities . end ( ) ) {
DigAbilities bob ;
memset ( & bob , 0xFF , sizeof ( bob ) ) ;
digAbilities [ raceString ] = bob ;
}
DigAbilities & abilities = digAbilities [ raceString ] ;
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
string costStr = parameters [ a + 2 ] ;
2013-01-04 19:02:09 -07:00
int32_t costDim = - 1 ;
2013-01-05 09:06:46 -07:00
if ( costStr = = " walk " ) {
costDim = CostDimension : : Walk ;
2013-06-11 03:14:56 -06:00
if ( parameters [ a ] = = " setDelay " )
return CR_WRONG_USAGE ;
2013-01-04 19:02:09 -07:00
} else if ( costStr = = " destroyBuilding " ) {
costDim = CostDimension : : DestroyBuilding ;
} else if ( costStr = = " dig " ) {
costDim = CostDimension : : Dig ;
2013-06-15 21:04:15 -06:00
} else if ( costStr = = " destroyRoughConstruction " ) {
costDim = CostDimension : : DestroyRoughConstruction ;
} else if ( costStr = = " destroySmoothConstruction " ) {
costDim = CostDimension : : DestroySmoothConstruction ;
2013-01-04 19:02:09 -07:00
} else {
return CR_WRONG_USAGE ;
}
2015-02-14 20:53:06 -07:00
2013-06-09 21:17:31 -06:00
cost_t value ;
2013-06-15 21:04:15 -06:00
stringstream asdf ( parameters [ a + 3 ] ) ;
2013-01-04 19:02:09 -07:00
asdf > > value ;
2013-06-15 21:04:15 -06:00
//if ( parameters[a] == "setCost" && value <= 0 )
// return CR_WRONG_USAGE;
if ( parameters [ a ] = = " setCost " ) {
abilities . costWeight [ costDim ] = value ;
} else {
abilities . jobDelay [ costDim ] = value ;
}
a + = 3 ;
2013-01-04 19:02:09 -07:00
} else if ( parameters [ a ] = = " edgeCost " ) {
2013-06-15 21:04:15 -06:00
if ( a + 1 > = parameters . size ( ) )
return CR_WRONG_USAGE ;
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
string raceString = parameters [ a + 1 ] ;
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
if ( digAbilities . find ( raceString ) = = digAbilities . end ( ) ) {
out . print ( " Race %s does not have dig abilities assigned. \n " , raceString . c_str ( ) ) ;
return CR_WRONG_USAGE ;
}
DigAbilities & abilities = digAbilities [ raceString ] ;
2015-02-14 20:53:06 -07:00
2013-01-04 19:02:09 -07:00
df : : coord bob = Gui : : getCursorPos ( ) ;
2018-06-11 10:57:06 -06:00
out . print ( " (%d,%d,%d), (%d,%d,%d): cost = % " PRId64 " \n " , lastDebugEdgeCostPoint . x , lastDebugEdgeCostPoint . y , lastDebugEdgeCostPoint . z , bob . x , bob . y , bob . z , getEdgeCost ( out , lastDebugEdgeCostPoint , bob , abilities ) ) ;
2013-01-04 19:02:09 -07:00
lastDebugEdgeCostPoint = bob ;
2013-06-15 21:04:15 -06:00
a + + ;
2013-06-09 23:58:27 -06:00
} else if ( parameters [ a ] = = " now " ) {
activeDigging = true ;
findAndAssignInvasionJob ( out , ( void * ) 0 ) ;
} else if ( parameters [ a ] = = " clear " ) {
diggingRaces . clear ( ) ;
2013-06-15 21:04:15 -06:00
digAbilities . clear ( ) ;
2013-06-09 23:58:27 -06:00
} else if ( parameters [ a ] = = " edgesPerTick " ) {
if ( a + 1 > = parameters . size ( ) )
return CR_WRONG_USAGE ;
stringstream asdf ( parameters [ a + 1 ] ) ;
int32_t edgeCount = 100 ;
asdf > > edgeCount ;
edgesPerTick = edgeCount ;
a + + ;
2013-01-04 19:02:09 -07:00
}
else {
return CR_WRONG_USAGE ;
2013-01-03 21:18:40 -07:00
}
}
2013-06-09 23:58:27 -06:00
activeDigging = enabled ;
out . print ( " diggingInvaders: enabled = %d, activeDigging = %d, edgesPerTick = %d \n " , enabled , activeDigging , edgesPerTick ) ;
2015-02-14 20:53:06 -07:00
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 ) ;
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);
2015-02-14 20:53:06 -07:00
2013-06-09 23:58:27 -06:00
if ( ! enabled | | ! activeDigging ) {
2013-06-09 21:07:51 -06:00
clearDijkstra ( ) ;
return ;
}
2015-02-14 20:53:06 -07:00
2021-08-28 13:41:50 -06:00
//this line is actually redundant now: EventManager::unregister(EventManager::EventType::TICK, findJobTickHandler, plugin_self);
EventManager : : registerTick ( findJobTickHandler , 1 , plugin_self ) ;
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 ;
2015-02-14 20:53:06 -07:00
2013-06-09 21:07:51 -06:00
clearDijkstra ( ) ;
unordered_set < uint16_t > invaderConnectivity ;
unordered_set < uint16_t > localConnectivity ;
//find all locals and invaders
2014-12-02 19:44:20 -07:00
for ( size_t a = 0 ; a < world - > units . all . size ( ) ; a + + ) {
df : : unit * unit = world - > units . all [ a ] ;
2018-06-14 04:30:41 -06:00
if ( ! Units : : isActive ( unit ) )
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 ;
}
2013-06-15 21:04:15 -06:00
/*
2013-06-09 21:07:51 -06:00
if ( diggingRaces . find ( raw - > creature_id ) = = diggingRaces . end ( ) )
continue ;
2013-06-15 21:04:15 -06:00
*/
if ( digAbilities . find ( raw - > creature_id ) = = digAbilities . end ( ) )
continue ;
2013-06-09 21:07:51 -06:00
if ( invaderPts . find ( unit - > pos ) ! = invaderPts . end ( ) )
continue ;
//must be able to wield a pick: this is overly pessimistic
2013-06-11 05:17:41 -06:00
if ( unit - > status2 . limbs_grasp_max < = 0 | | unit - > status2 . limbs_grasp_count < unit - > status2 . limbs_grasp_max )
2013-06-09 21:07:51 -06:00
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
}
2015-02-14 20:53:06 -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
}
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
df : : creature_raw * creature_raw = df : : creature_raw : : find ( firstInvader - > race ) ;
if ( creature_raw = = NULL | | digAbilities . find ( creature_raw - > creature_id ) = = digAbilities . end ( ) ) {
//inappropriate digger: no dig abilities
fringe . clear ( ) ;
return ;
}
DigAbilities & abilities = digAbilities [ creature_raw - > creature_id ] ;
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;
2015-02-14 20:53:06 -07:00
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 ;
2015-02-14 20:53:06 -07:00
2021-09-06 23:16:21 -06:00
// clock_t t0 = clock();
2012-12-17 18:44:35 -07:00
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 23:58:27 -06:00
if ( edgesPerTick > 0 & & edgesExpanded + + > = edgesPerTick ) {
2013-06-09 21:07:51 -06:00
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 ) ;
2015-02-14 20:53:06 -07:00
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 ( ) ;
2013-06-15 21:04:15 -06:00
vector < Edge > * myEdges = getEdgeSet ( out , pt , cache , xMax , yMax , zMax , abilities ) ;
2012-12-17 18:44:35 -07:00
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
}
2021-09-06 23:16:21 -06:00
// clock_t time = clock() - t0;
2013-06-09 23:58:27 -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 ;
2015-02-14 20:53:06 -07: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-11 05:17:41 -06:00
//df::coord closest;
//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-11 05:17:41 -06:00
//closest = pt;
//closestCostEstimate = costMap[closest];
2015-02-14 20:53:06 -07:00
//if ( workNeeded[pt] == 0 )
2013-01-03 12:16:10 -07:00
// 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-15 21:04:15 -06:00
cost_t cost = getEdgeCost ( out , parent , pt , abilities ) ;
2013-06-11 05:17:41 -06:00
if ( cost < 0 ) {
//path invalidated
return ;
}
//closestCostActual += cost;
2013-01-03 11:32:50 -07:00
if ( Maps : : canStepBetween ( parent , pt ) ) {
2015-02-14 20:53:06 -07:00
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 ;
2015-02-14 20:53:06 -07:00
2013-06-11 05:17:41 -06:00
/*
2013-06-09 21:07:51 -06:00
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-06-11 05:17:41 -06:00
*/
2015-02-14 20:53:06 -07:00
2013-06-15 21:04:15 -06:00
assignJob ( out , firstImportantEdge , parentMap , costMap , invaders , requiresZNeg , requiresZPos , cache , abilities ) ;
2013-06-09 21:07:51 -06:00
lastInvasionDigger = firstInvader - > id ;
lastInvasionJob = firstInvader - > job . current_job ? firstInvader - > job . current_job - > id : - 1 ;
invaderJobs . erase ( lastInvasionJob ) ;
2017-11-24 22:59:59 -07:00
for ( df : : job_list_link * link = & world - > jobs . list ; link ! = NULL ; link = link - > next ) {
2013-06-09 21:07:51 -06:00
if ( link - > item = = NULL )
continue ;
df : : job * job = link - > item ;
if ( invaderJobs . find ( job - > id ) = = invaderJobs . end ( ) ) {
continue ;
}
2015-02-14 20:53:06 -07:00
2013-06-09 21:07:51 -06:00
//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
}