Vermin module and colonies plugin

This is the start of the vermin module.  Right now it just gets a list
of the positions at which vermin are created (spawn points).  Most
spawn points are invisible and transient, but colonies (ant hills and
such) are permanent and visible.  The address of the spawn points vector
is only provided for Linux 0.31.25

The colonies plugin uses the vermin module to list the location and
species of colonies, and can either wipe them all out or turn them all
into honey bee colonies.
develop
Matthew Cline 2011-07-12 23:17:51 -07:00
parent 1b011cdf6c
commit d1170d54c3
9 changed files with 473 additions and 3 deletions

@ -990,6 +990,17 @@
<Offset name="custom_workshop_name"/> <Offset name="custom_workshop_name"/>
<Offset name="custom_workshop_type"/> <Offset name="custom_workshop_type"/>
</Group> </Group>
<Group name="Vermin">
<Group name="Spawn Points" description="vermin spawn points, including colonies">
<Address name="vector"/>
<Offset name="race"/>
<Offset name="type"/>
<Offset name="position"/>
<Offset name="in_use"/>
<Offset name="unknown"/>
<Offset name="countdown"/> to what???
</Group>
</Group>
<Group name="Items"> <Group name="Items">
<!-- most of those seem completely unused! --> <!-- most of those seem completely unused! -->
<Address name="items_vector" /> <Address name="items_vector" />
@ -3029,6 +3040,17 @@
<Offset name="flags3" value="0x94"/> <Offset name="flags3" value="0x94"/>
</Group> </Group>
</Group> </Group>
<Group name="Vermin" valid="true">
<Group name="Spawn Points">
<Address name="vector" value="0x93f77c4"/>
<Offset name="race" value="0x0"/>
<Offset name="type" value="0x2"/>
<Offset name="position" value="0x4"/>
<Offset name="in_use" value="0xa"/>
<Offset name="unknown" value="0xb"/>
<Offset name="countdown" value="0xc"/>
</Group>
</Group>
<Group name="Position" valid="true"> <Group name="Position" valid="true">
<Address name="cursor_xyz" value="0x8c3de60"/> <Address name="cursor_xyz" value="0x8c3de60"/>
</Group> </Group>

@ -75,6 +75,7 @@ modules/Maps.cpp
modules/Materials.cpp modules/Materials.cpp
modules/Translation.cpp modules/Translation.cpp
modules/Vegetation.cpp modules/Vegetation.cpp
modules/Vermin.cpp
modules/World.cpp modules/World.cpp
) )

@ -443,4 +443,5 @@ MODULE_GETTER(Items);
MODULE_GETTER(Translation); MODULE_GETTER(Translation);
MODULE_GETTER(Vegetation); MODULE_GETTER(Vegetation);
MODULE_GETTER(Buildings); MODULE_GETTER(Buildings);
MODULE_GETTER(Constructions); MODULE_GETTER(Constructions);
MODULE_GETTER(Vermin);

@ -48,6 +48,7 @@ namespace DFHack
class Vegetation; class Vegetation;
class Buildings; class Buildings;
class Constructions; class Constructions;
class Vermin;
class VersionInfo; class VersionInfo;
class VersionInfoFactory; class VersionInfoFactory;
class Console; class Console;
@ -105,6 +106,8 @@ namespace DFHack
Buildings * getBuildings(); Buildings * getBuildings();
/// get the constructions module /// get the constructions module
Constructions * getConstructions(); Constructions * getConstructions();
/// get the vermin module
Vermin * getVermin();
/// sets the current hotkey command /// sets the current hotkey command
bool setHotkeyCmd( std::string cmd ); bool setHotkeyCmd( std::string cmd );
/// removes the hotkey command and gives it to the caller thread /// removes the hotkey command and gives it to the caller thread
@ -144,6 +147,7 @@ namespace DFHack
Vegetation * pVegetation; Vegetation * pVegetation;
Buildings * pBuildings; Buildings * pBuildings;
Constructions * pConstructions; Constructions * pConstructions;
Vermin * pVermin;
} s_mods; } s_mods;
std::vector <Module *> allModules; std::vector <Module *> allModules;
DFHack::PluginManager * plug_mgr; DFHack::PluginManager * plug_mgr;
@ -156,4 +160,4 @@ namespace DFHack
// Very important! // Very important!
bool started; bool started;
}; };
} }

@ -0,0 +1,86 @@
#pragma once
#ifndef CL_MOD_VERMIN
#define CL_MOD_VERMIN
/**
* \defgroup grp_vermin Wild vermin (ants, bees, etc)
* @ingroup grp_vermin
*/
#include "dfhack/Export.h"
#include "dfhack/Module.h"
#ifdef __cplusplus
namespace DFHack
{
#endif
/**
* Structure for holding a read DF vermin spawn point object
* \ingroup grp_vermin
*/
struct t_spawnPoint
{
uint32_t origin;
uint16_t race;
uint16_t type;
uint16_t x;
uint16_t y;
uint16_t z;
bool in_use;
uint8_t unknown;
uint32_t countdown;
};
#ifdef __cplusplus
class DFContextShared;
class SpawnPoints;
/**
* The Vermin module - allows reading DF vermin
* \ingroup grp_modules
* \ingroup grp_vermin
*/
class DFHACK_EXPORT Vermin : public Module
{
public:
Vermin();
~Vermin();
bool Finish();
// NOTE: caller must call delete on result when done.
SpawnPoints* getSpawnPoints();
private:
struct Private;
Private *d;
friend class SpawnPoints;
};
class DFHACK_EXPORT SpawnPoints
{
public:
static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
protected:
SpawnPoints(Vermin * v);
public:
~SpawnPoints();
size_t size();
bool Read (const uint32_t index, t_spawnPoint & point);
bool Write (const uint32_t index, t_spawnPoint & point);
bool isValid();
static bool isWildColony(t_spawnPoint & point);
private:
Vermin* v;
std::vector <void*> * p_sp;
friend class Vermin;
};
}
#endif // __cplusplus
#endif

@ -0,0 +1,191 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include <string>
#include <vector>
#include <map>
using namespace std;
#include "dfhack/VersionInfo.h"
#include "dfhack/Types.h"
#include "dfhack/Error.h"
#include "dfhack/Process.h"
#include "dfhack/modules/Vermin.h"
#include "ModuleFactory.h"
#include "dfhack/Core.h"
using namespace DFHack;
struct Vermin::Private
{
uint32_t spawn_points_vector;
uint32_t race_offset;
uint32_t type_offset;
uint32_t position_offset;
uint32_t in_use_offset;
uint32_t unknown_offset;
uint32_t countdown_offset;
Process * owner;
bool Inited;
bool Started;
};
Module* DFHack::createVermin()
{
return new Vermin();
}
#include <stdio.h>
Vermin::Vermin()
{
Core & c = Core::getInstance();
d = new Private;
d->owner = c.p;
d->Inited = d->Started = false;
VersionInfo * mem = c.vinfo;
OffsetGroup * OG_vermin = mem->getGroup("Vermin");
OffsetGroup * OG_spawn = OG_vermin->getGroup("Spawn Points");
d->Inited = true;
try
{
d->spawn_points_vector = OG_spawn->getAddress("vector");
d->race_offset = OG_spawn->getOffset("race");
d->type_offset = OG_spawn->getOffset("type");
d->position_offset = OG_spawn->getOffset("position");
d->in_use_offset = OG_spawn->getOffset("in_use");
d->unknown_offset = OG_spawn->getOffset("unknown");
d->countdown_offset = OG_spawn->getOffset("countdown");
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Vermin not available... " << e.what() << endl;
d->Inited = false;
}
}
bool Vermin::Finish()
{
return true;
}
Vermin::~Vermin()
{
delete d;
}
// NOTE: caller must call delete on result when done.
SpawnPoints* Vermin::getSpawnPoints()
{
if (!d->Inited)
{
cerr << "Couldn't get spawn points: Vermin module not inited" << endl;
return NULL;
}
return new SpawnPoints(this);
}
SpawnPoints::SpawnPoints(Vermin* v_)
{
v = v_;
p_sp = NULL;
if (!v->d->Inited)
{
cerr << "Couldn't get spawn points: Vermin module not inited" << endl;
return;
}
//p_sp = new DfVector <uint32_t> (v->d->spawn_points_vector);
//p_sp = new vector <void*> (v->d->spawn_points_vector);
p_sp = (vector <void*>*) (v->d->spawn_points_vector);
}
SpawnPoints::~SpawnPoints()
{
// Do NOT delete p_sp; it's a pointer to memory the game owns.
}
size_t SpawnPoints::size()
{
if (!isValid())
return 0;
return p_sp->size();
}
bool SpawnPoints::Read (const uint32_t index, t_spawnPoint & sp)
{
if(!isValid())
return false;
// read pointer from vector at position
uint32_t temp = (uint32_t) p_sp->at (index);
sp.origin = temp;
sp.race = v->d->owner->readWord(temp + v->d->race_offset);
sp.type = v->d->owner->readWord(temp + v->d->type_offset);
sp.in_use = v->d->owner->readByte(temp + v->d->in_use_offset);
sp.unknown = v->d->owner->readByte(temp + v->d->unknown_offset);
sp.countdown = v->d->owner->readDWord(temp + v->d->countdown_offset);
// Three consecutive 16 bit numbers for x/y/z
v->d->owner->read(temp + v->d->position_offset, 6, (uint8_t*) &sp.x);
return true;
}
bool SpawnPoints::Write (const uint32_t index, t_spawnPoint & sp)
{
if(!isValid())
return false;
// read pointer from vector at position
uint32_t temp = (uint32_t) p_sp->at (index);
v->d->owner->writeWord(temp + v->d->race_offset, sp.race);
v->d->owner->writeWord(temp + v->d->type_offset, sp.type);
v->d->owner->writeByte(temp + v->d->in_use_offset, sp.in_use);
v->d->owner->writeByte(temp + v->d->unknown_offset, sp.unknown);
v->d->owner->writeDWord(temp + v->d->countdown_offset, sp.countdown);
// Three consecutive 16 bit numbers for x/y/z
v->d->owner->write(temp + v->d->position_offset, 6, (uint8_t*) &sp.x);
return true;
}
bool SpawnPoints::isWildColony(t_spawnPoint & point)
{
return (point.type == TYPE_WILD_COLONY);
}
bool SpawnPoints::isValid()
{
return (v != NULL && v->d->Inited && p_sp != NULL);
}

@ -41,5 +41,6 @@ namespace DFHack
Module* createBuildings(); Module* createBuildings();
Module* createConstructions(); Module* createConstructions();
Module* createMaps(); Module* createMaps();
Module* createVermin();
} }
#endif #endif

@ -33,3 +33,4 @@ DFHACK_PLUGIN(prospector prospector.cpp)
DFHACK_PLUGIN(cleanmap cleanmap.cpp) DFHACK_PLUGIN(cleanmap cleanmap.cpp)
DFHACK_PLUGIN(weather weather.cpp) DFHACK_PLUGIN(weather weather.cpp)
DFHACK_PLUGIN(vdig vdig.cpp) DFHACK_PLUGIN(vdig vdig.cpp)
DFHACK_PLUGIN(colonies colonies.cpp)

@ -0,0 +1,163 @@
#include <dfhack/Core.h>
#include <dfhack/Console.h>
#include <dfhack/Export.h>
#include <dfhack/PluginManager.h>
#include <vector>
#include <string>
#include <dfhack/modules/Vermin.h>
using std::vector;
using std::string;
using namespace DFHack;
#include <DFHack.h>
DFhackCExport command_result colonies (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "colonies";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("colonies",
"List or change wild colonies (ants hills and such)\
\n Options: 'kill' = destroy all colonies\
\n 'bees' = change all colonies to honey bees",
colonies));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
void destroyColonies(DFHack::SpawnPoints *points);
void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials);
void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials);
DFhackCExport command_result colonies (Core * c, vector <string> & parameters)
{
bool destroy = false;
bool convert = false;
for(int i = 0; i < parameters.size();i++)
{
if(parameters[i] == "kill")
destroy = true;
else if(parameters[i] == "bees")
convert = true;
}
if (destroy && convert)
{
dfout << "Kill or make bees? DECIDE!" << std::endl;
return CR_FAILURE;
}
c->Suspend();
Vermin * vermin = c->getVermin();
Materials * materials = c->getMaterials();
SpawnPoints *points = vermin->getSpawnPoints();
if(!points->isValid())
{
std::cerr << "vermin not supported for this DF version" << std::endl;
return CR_FAILURE;
}
materials->ReadCreatureTypesEx();
if (destroy)
destroyColonies(points);
else if (convert)
convertColonies(points, materials);
else
showColonies(points, materials);
delete points;
vermin->Finish();
materials->Finish();
c->Resume();
return CR_OK;
}
void destroyColonies(DFHack::SpawnPoints *points)
{
uint32_t numSpawnPoints = points->size();
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
points->Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
{
sp.in_use = false;
points->Write(i, sp);
}
}
}
// Convert all colonies to honey bees.
void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials)
{
int bee_idx = -1;
for (size_t i = 0; i < Materials->raceEx.size(); i++)
if (strcmp(Materials->raceEx[i].rawname, "HONEY_BEE") == 0)
{
bee_idx = i;
break;
}
if (bee_idx == -1)
{
std::cerr << "Honey bees not present in game." << std::endl;
return;
}
uint32_t numSpawnPoints = points->size();
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
points->Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
{
sp.race = bee_idx;
points->Write(i, sp);
}
}
}
void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials)
{
uint32_t numSpawnPoints = points->size();
int numColonies = 0;
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
points->Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
{
numColonies++;
string race="(no race)";
if (Materials->raceEx[sp.race].rawname[0])
race = Materials->raceEx[sp.race].rawname;
fprintf(dfout_C, "Spawn point %u: %s at %d:%d:%d\n",
i, race.c_str(), sp.x, sp.y, sp.z);
}
}
if (numColonies == 0)
dfout << "No colonies present." << std::endl;
}