diff --git a/Memory.xml b/Memory.xml index a41125537..f651c07df 100644 --- a/Memory.xml +++ b/Memory.xml @@ -990,6 +990,17 @@ + + +
+ + + + + + to what??? + +
@@ -3029,6 +3040,17 @@ + + +
+ + + + + + + +
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 803ade583..a0142fa3b 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -75,6 +75,7 @@ modules/Maps.cpp modules/Materials.cpp modules/Translation.cpp modules/Vegetation.cpp +modules/Vermin.cpp modules/World.cpp ) diff --git a/library/Core.cpp b/library/Core.cpp index 5c9358cfc..403e22267 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -438,4 +438,5 @@ MODULE_GETTER(Items); MODULE_GETTER(Translation); MODULE_GETTER(Vegetation); MODULE_GETTER(Buildings); -MODULE_GETTER(Constructions); \ No newline at end of file +MODULE_GETTER(Constructions); +MODULE_GETTER(Vermin); diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index f2610edfe..26342446c 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -48,6 +48,7 @@ namespace DFHack class Vegetation; class Buildings; class Constructions; + class Vermin; class VersionInfo; class VersionInfoFactory; class PluginManager; @@ -104,6 +105,8 @@ namespace DFHack Buildings * getBuildings(); /// get the constructions module Constructions * getConstructions(); + /// get the vermin module + Vermin * getVermin(); /// sets the current hotkey command bool setHotkeyCmd( std::string cmd ); /// removes the hotkey command and gives it to the caller thread @@ -143,6 +146,7 @@ namespace DFHack Vegetation * pVegetation; Buildings * pBuildings; Constructions * pConstructions; + Vermin * pVermin; } s_mods; std::vector allModules; DFHack::PluginManager * plug_mgr; @@ -155,4 +159,4 @@ namespace DFHack // Very important! bool started; }; -} \ No newline at end of file +} diff --git a/library/include/dfhack/modules/Vermin.h b/library/include/dfhack/modules/Vermin.h new file mode 100644 index 000000000..f5eaac583 --- /dev/null +++ b/library/include/dfhack/modules/Vermin.h @@ -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 * p_sp; + + friend class Vermin; + }; +} +#endif // __cplusplus + +#endif diff --git a/library/modules/Vermin.cpp b/library/modules/Vermin.cpp new file mode 100644 index 000000000..67fd623e4 --- /dev/null +++ b/library/modules/Vermin.cpp @@ -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 +#include +#include +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 + +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 (v->d->spawn_points_vector); + //p_sp = new vector (v->d->spawn_points_vector); + p_sp = (vector *) (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); +} diff --git a/library/private/ModuleFactory.h b/library/private/ModuleFactory.h index f3ca601dc..cd1ef73a2 100644 --- a/library/private/ModuleFactory.h +++ b/library/private/ModuleFactory.h @@ -41,5 +41,6 @@ namespace DFHack Module* createBuildings(); Module* createConstructions(); Module* createMaps(); + Module* createVermin(); } -#endif \ No newline at end of file +#endif diff --git a/package/linux/dfhack b/package/linux/dfhack index 8484a3e5e..35e9cfeb2 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -2,6 +2,8 @@ # NOTE: This is dfhack's modification of the normal invocation script, # changed to properly set LD_PRELOAD so as to run DFHACK. +# +# You can run DF under gdb by passing -g or --gdb as the first argument. DF_DIR=$(dirname "$0") cd "${DF_DIR}" @@ -10,4 +12,19 @@ export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. export LD_PRELOAD=./libdfhack.so -./libs/Dwarf_Fortress $* # Go, go, go! :) +case "$1" in + -g | --gdb) + shift + gdb ./libs/Dwarf_Fortress $* + ret=$? + ;; + *) + ./libs/Dwarf_Fortress $* + ret=$? + ;; +esac + +# Reset terminal to sane state in case of a crash +reset -I + +exit $ret diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 25fb0471b..ff7daf24f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -33,3 +33,4 @@ DFHACK_PLUGIN(prospector prospector.cpp) DFHACK_PLUGIN(cleanmap cleanmap.cpp) DFHACK_PLUGIN(weather weather.cpp) DFHACK_PLUGIN(vdig vdig.cpp) +DFHACK_PLUGIN(colonies colonies.cpp) diff --git a/plugins/colonies.cpp b/plugins/colonies.cpp new file mode 100644 index 000000000..bd5bfe839 --- /dev/null +++ b/plugins/colonies.cpp @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::string; +using namespace DFHack; +#include + +DFhackCExport command_result colonies (Core * c, vector & parameters); + +DFhackCExport const char * plugin_name ( void ) +{ + return "colonies"; +} + +DFhackCExport command_result plugin_init ( Core * c, std::vector &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(Core *c, DFHack::SpawnPoints *points, + DFHack::Materials *Materials); + +DFhackCExport command_result colonies (Core * c, vector & 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) + { + + c->con << "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()) + { + c->con << "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(c, 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(Core *c, 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; + + c->con.print("Spawn point %u: %s at %d:%d:%d\n", i, + race.c_str(), sp.x, sp.y, sp.z); + } + } + + if (numColonies == 0) + c->con << "No colonies present." << std::endl; +}