Merge branch 'master' into export-plugin
commit
8e2fef0c97
@ -1,96 +0,0 @@
|
||||
/*
|
||||
https://github.com/peterix/dfhack
|
||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DFVECTOR_H_INCLUDED
|
||||
#define DFVECTOR_H_INCLUDED
|
||||
|
||||
#include "Pragma.h"
|
||||
#include "Export.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "MemAccess.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
template <class T>
|
||||
class DFHACK_EXPORT DfVector
|
||||
{
|
||||
private:
|
||||
std::vector<T> * real_vec;
|
||||
public:
|
||||
DfVector(uint32_t address)
|
||||
{
|
||||
real_vec = (std::vector<T> *) address;
|
||||
};
|
||||
~DfVector()
|
||||
{
|
||||
};
|
||||
// get offset of the specified index
|
||||
inline const T& operator[] (uint32_t index)
|
||||
{
|
||||
// FIXME: vector out of bounds exception
|
||||
//assert(index < size);
|
||||
return real_vec->at(index);
|
||||
};
|
||||
// get offset of the specified index
|
||||
inline const T& at (uint32_t index)
|
||||
{
|
||||
//assert(index < size);
|
||||
return real_vec->at(index);
|
||||
};
|
||||
// update value at index
|
||||
bool set(uint32_t index, T value)
|
||||
{
|
||||
if (index >= real_vec->size())
|
||||
return false;
|
||||
real_vec->at(index) = value;
|
||||
return true;
|
||||
}
|
||||
// remove value
|
||||
bool remove(uint32_t index)
|
||||
{
|
||||
if (index >= real_vec->size())
|
||||
return false;
|
||||
// Remove the item
|
||||
real_vec->erase(real_vec->begin() + index);
|
||||
return true;
|
||||
}
|
||||
// get vector size
|
||||
inline uint32_t size ()
|
||||
{
|
||||
return real_vec->size();
|
||||
};
|
||||
// get vector start
|
||||
inline const T * start ()
|
||||
{
|
||||
return real_vec->data();
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif // DFVECTOR_H_INCLUDED
|
@ -1,3 +1,3 @@
|
||||
*.h
|
||||
*.inc
|
||||
static*.inc
|
||||
*.xml
|
||||
|
@ -0,0 +1,45 @@
|
||||
coord(const coord2d &c, uint16_t _z) : x(c.x), y(c.y), z(_z) {}
|
||||
coord(uint16_t _x, uint16_t _y, uint16_t _z) : x(_x), y(_y), z(_z) {}
|
||||
|
||||
operator coord2d() const { return coord2d(x,y); }
|
||||
|
||||
bool isValid() const { return x != -30000; }
|
||||
void clear() { x = y = z = -30000; }
|
||||
|
||||
bool operator==(const coord &other) const
|
||||
{
|
||||
return (x == other.x) && (y == other.y) && (z == other.z);
|
||||
}
|
||||
bool operator!=(const coord &other) const
|
||||
{
|
||||
return (x != other.x) || (y != other.y) || (z != other.z);
|
||||
}
|
||||
|
||||
bool operator<(const coord &other) const
|
||||
{
|
||||
if (x != other.x) return (x < other.x);
|
||||
if (y != other.y) return (y < other.y);
|
||||
return z < other.z;
|
||||
}
|
||||
|
||||
coord operator/(int number) const
|
||||
{
|
||||
return coord(x/number, y/number, z);
|
||||
}
|
||||
coord operator*(int number) const
|
||||
{
|
||||
return coord(x*number, y*number, z);
|
||||
}
|
||||
coord operator%(int number) const
|
||||
{
|
||||
return coord(x%number, y%number, z);
|
||||
}
|
||||
|
||||
coord operator-(int number) const
|
||||
{
|
||||
return coord(x,y,z-number);
|
||||
}
|
||||
coord operator+(int number) const
|
||||
{
|
||||
return coord(x,y,z+number);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
coord2d(uint16_t _x, uint16_t _y) : x(_x), y(_y) {}
|
||||
|
||||
bool isValid() const { return x != -30000; }
|
||||
void clear() { x = y = -30000; }
|
||||
|
||||
bool operator==(const coord2d &other) const
|
||||
{
|
||||
return (x == other.x) && (y == other.y);
|
||||
}
|
||||
bool operator!=(const coord2d &other) const
|
||||
{
|
||||
return (x != other.x) || (y != other.y);
|
||||
}
|
||||
|
||||
bool operator<(const coord2d &other) const
|
||||
{
|
||||
if (x != other.x) return (x < other.x);
|
||||
return y < other.y;
|
||||
}
|
||||
|
||||
coord2d operator/(int number) const
|
||||
{
|
||||
return coord2d(x/number, y/number);
|
||||
}
|
||||
coord2d operator*(int number) const
|
||||
{
|
||||
return coord2d(x*number, y*number);
|
||||
}
|
||||
coord2d operator%(int number) const
|
||||
{
|
||||
return coord2d(x%number, y%number);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
unsigned size() const { return x.size(); }
|
||||
|
||||
coord operator[] (unsigned idx) const {
|
||||
if (idx >= x.size() || idx >= y.size() || idx >= z.size())
|
||||
return coord();
|
||||
else
|
||||
return coord(x[idx], y[idx], z[idx]);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
https://github.com/peterix/dfhack
|
||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef CL_MOD_JOB
|
||||
#define CL_MOD_JOB
|
||||
|
||||
#include "Export.h"
|
||||
#include "Module.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace df
|
||||
{
|
||||
struct job;
|
||||
struct job_item;
|
||||
struct job_item_filter;
|
||||
struct building;
|
||||
}
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
// Duplicate the job structure. It is not linked into any DF lists.
|
||||
DFHACK_EXPORT df::job *cloneJobStruct(df::job *job);
|
||||
|
||||
// Delete a cloned structure.
|
||||
DFHACK_EXPORT void deleteJobStruct(df::job *job);
|
||||
|
||||
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
|
||||
DFHACK_EXPORT bool operator== (const df::job &a, const df::job &b);
|
||||
|
||||
DFHACK_EXPORT void printJobDetails(Core *c, df::job *job);
|
||||
|
||||
DFHACK_EXPORT df::building *getJobHolder(df::job *job);
|
||||
|
||||
DFHACK_EXPORT bool linkJobIntoWorld(df::job *job, bool new_id = true);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,86 +1,38 @@
|
||||
#pragma once
|
||||
#ifndef CL_MOD_VERMIN
|
||||
#define CL_MOD_VERMIN
|
||||
/**
|
||||
* \defgroup grp_vermin Wild vermin (ants, bees, etc)
|
||||
* @ingroup grp_vermin
|
||||
*/
|
||||
#include "Export.h"
|
||||
#include "Module.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace DFHack
|
||||
namespace DFHack { namespace Simple { namespace Vermin
|
||||
{
|
||||
#endif
|
||||
/**
|
||||
* Structure for holding a read DF vermin spawn point object
|
||||
* \ingroup grp_vermin
|
||||
*/
|
||||
struct t_spawnPoint
|
||||
struct t_vermin
|
||||
{
|
||||
uint32_t origin;
|
||||
void * origin;
|
||||
int16_t race;
|
||||
uint16_t type;
|
||||
int16_t caste;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
bool in_use;
|
||||
uint8_t unknown;
|
||||
uint32_t countdown;
|
||||
bool visible:1;
|
||||
bool is_colony:1; /// Is vermin object a colony?
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
class DFContextShared;
|
||||
class SpawnPoints;
|
||||
|
||||
static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
|
||||
/**
|
||||
* The Vermin module - allows reading DF vermin
|
||||
* \ingroup grp_modules
|
||||
* \ingroup grp_vermin
|
||||
* Get number of vermin objects
|
||||
*/
|
||||
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
|
||||
DFHACK_EXPORT uint32_t getNumVermin();
|
||||
/**
|
||||
* Read from vermin object
|
||||
*/
|
||||
DFHACK_EXPORT bool Read (const uint32_t index, t_vermin & point);
|
||||
/**
|
||||
* Write into vermin object
|
||||
*/
|
||||
DFHACK_EXPORT bool Write (const uint32_t index, t_vermin & point);
|
||||
} } } // end DFHack::Simple::Vermin
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 7a730830c515fea701ff73b33cb604f48a4531fc
|
||||
Subproject commit d5abec61f72f113e023219fed19c4022363de953
|
@ -1,158 +1,114 @@
|
||||
// De-ramp. All ramps marked for removal are replaced with given tile (presently, normal floor).
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
using namespace std;
|
||||
#include "Core.h"
|
||||
#include <Console.h>
|
||||
#include <Export.h>
|
||||
#include <PluginManager.h>
|
||||
#include <modules/Maps.h>
|
||||
#include <TileTypes.h>
|
||||
using namespace DFHack;
|
||||
#include "Console.h"
|
||||
#include "Export.h"
|
||||
#include "PluginManager.h"
|
||||
|
||||
DFhackCExport command_result df_deramp (Core * c, vector <string> & parameters);
|
||||
#include "DataDefs.h"
|
||||
#include "df/world.h"
|
||||
#include "df/map_block.h"
|
||||
#include "df/tile_dig_designation.h"
|
||||
#include "TileTypes.h"
|
||||
|
||||
DFhackCExport const char * plugin_name ( void )
|
||||
{
|
||||
return "deramp";
|
||||
}
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using namespace DFHack;
|
||||
|
||||
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.clear();
|
||||
commands.push_back(PluginCommand("deramp",
|
||||
"De-ramp. All ramps marked for removal are replaced with floors.",
|
||||
df_deramp));
|
||||
return CR_OK;
|
||||
}
|
||||
using df::global::world;
|
||||
using namespace DFHack;
|
||||
|
||||
DFhackCExport command_result plugin_shutdown ( Core * c )
|
||||
// This is slightly different from what's in the Maps module - it takes tile coordinates rather than block coordinates
|
||||
df::map_block *getBlock (int32_t x, int32_t y, int32_t z)
|
||||
{
|
||||
return CR_OK;
|
||||
if ((x < 0) || (y < 0) || (z < 0))
|
||||
return NULL;
|
||||
if ((x >= world->map.x_count) || (y >= world->map.y_count) || (z >= world->map.z_count))
|
||||
return NULL;
|
||||
return world->map.block_index[x >> 4][y >> 4][z];
|
||||
}
|
||||
|
||||
DFhackCExport command_result df_deramp (Core * c, vector <string> & parameters)
|
||||
{
|
||||
uint32_t x_max,y_max,z_max;
|
||||
uint32_t num_blocks = 0;
|
||||
uint32_t bytes_read = 0;
|
||||
DFHack::designations40d designations;
|
||||
DFHack::tiletypes40d tiles;
|
||||
DFHack::tiletypes40d tilesAbove;
|
||||
|
||||
//DFHack::TileRow *ptile;
|
||||
int32_t oldT, newT;
|
||||
|
||||
bool dirty= false;
|
||||
int count=0;
|
||||
int countbad=0;
|
||||
for(int i = 0; i < parameters.size();i++)
|
||||
{
|
||||
if(parameters[i] == "help" || parameters[i] == "?")
|
||||
{
|
||||
c->con.print("This command does two things:\n"
|
||||
"If there are any ramps designated for removal, they will be instantly removed.\n"
|
||||
"Any ramps that don't have their counterpart will be removed (fixes bugs with caveins)\n"
|
||||
);
|
||||
"If there are any ramps designated for removal, they will be instantly removed.\n"
|
||||
"Any ramps that don't have their counterpart will be removed (fixes bugs with caveins)\n"
|
||||
);
|
||||
return CR_OK;
|
||||
}
|
||||
}
|
||||
c->Suspend();
|
||||
DFHack::Maps *Mapz = c->getMaps();
|
||||
|
||||
// init the map
|
||||
if (!Mapz->Start())
|
||||
{
|
||||
c->con.printerr("Can't init map.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
CoreSuspender suspend(c);
|
||||
|
||||
Mapz->getSize(x_max,y_max,z_max);
|
||||
int count = 0;
|
||||
int countbad = 0;
|
||||
|
||||
uint8_t zeroes [16][16] = {0};
|
||||
|
||||
// walk the map
|
||||
for (uint32_t x = 0; x< x_max;x++)
|
||||
int num_blocks = 0, blocks_total = world->map.map_blocks.size();
|
||||
for (int i = 0; i < blocks_total; i++)
|
||||
{
|
||||
for (uint32_t y = 0; y< y_max;y++)
|
||||
df::map_block *block = world->map.map_blocks[i];
|
||||
df::map_block *above = getBlock(block->map_pos.x, block->map_pos.y, block->map_pos.z + 1);
|
||||
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (uint32_t z = 0; z< z_max;z++)
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
if (Mapz->getBlock(x,y,z))
|
||||
int16_t oldT = block->tiletype[x][y];
|
||||
if ((tileShape(oldT) == RAMP) &&
|
||||
(block->designation[x][y].bits.dig == df::tile_dig_designation::Default))
|
||||
{
|
||||
dirty= false;
|
||||
Mapz->ReadDesignations(x,y,z, &designations);
|
||||
Mapz->ReadTileTypes(x,y,z, &tiles);
|
||||
if (Mapz->getBlock(x,y,z+1))
|
||||
{
|
||||
Mapz->ReadTileTypes(x,y,z+1, &tilesAbove);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&tilesAbove,0,sizeof(tilesAbove));
|
||||
}
|
||||
// Current tile is a ramp.
|
||||
// Set current tile, as accurately as can be expected
|
||||
int16_t newT = findSimilarTileType(oldT, FLOOR);
|
||||
|
||||
for (uint32_t ty=0;ty<16;++ty)
|
||||
{
|
||||
for (uint32_t tx=0;tx<16;++tx)
|
||||
{
|
||||
//Only the remove ramp designation (ignore channel designation, etc)
|
||||
oldT = tiles[tx][ty];
|
||||
if ( DFHack::designation_default == designations[tx][ty].bits.dig
|
||||
&& DFHack::RAMP==DFHack::tileShape(oldT))
|
||||
{
|
||||
//Current tile is a ramp.
|
||||
//Set current tile, as accurately as can be expected
|
||||
newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR);
|
||||
// If no change, skip it (couldn't find a good tile type)
|
||||
if (oldT == newT)
|
||||
continue;
|
||||
// Set new tile type, clear designation
|
||||
block->tiletype[x][y] = newT;
|
||||
block->designation[x][y].bits.dig = df::tile_dig_designation::No;
|
||||
|
||||
//If no change, skip it (couldn't find a good tile type)
|
||||
if ( oldT == newT) continue;
|
||||
//Set new tile type, clear designation
|
||||
tiles[tx][ty] = newT;
|
||||
designations[tx][ty].bits.dig = DFHack::designation_no;
|
||||
|
||||
//Check the tile above this one, in case a downward slope needs to be removed.
|
||||
if ( DFHack::RAMP_TOP == DFHack::tileShape(tilesAbove[tx][ty]) )
|
||||
{
|
||||
tilesAbove[tx][ty] = 32;
|
||||
}
|
||||
dirty= true;
|
||||
++count;
|
||||
}
|
||||
// ramp fixer
|
||||
else if(DFHack::RAMP!=DFHack::tileShape(oldT) && DFHack::RAMP_TOP == DFHack::tileShape(tilesAbove[tx][ty]))
|
||||
{
|
||||
tilesAbove[tx][ty] = 32;
|
||||
countbad++;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//If anything was changed, write it all.
|
||||
if (dirty)
|
||||
{
|
||||
Mapz->WriteDesignations(x,y,z, &designations);
|
||||
Mapz->WriteTileTypes(x,y,z, &tiles);
|
||||
if (Mapz->getBlock(x,y,z+1))
|
||||
{
|
||||
Mapz->WriteTileTypes(x,y,z+1, &tilesAbove);
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
// Check the tile above this one, in case a downward slope needs to be removed.
|
||||
if ((above) && (tileShape(above->tiletype[x][y]) == RAMP_TOP))
|
||||
above->tiletype[x][y] = 32; // open space
|
||||
count++;
|
||||
}
|
||||
// ramp fixer
|
||||
else if ((tileShape(oldT) != RAMP)
|
||||
&& (above) && (tileShape(above->tiletype[x][y]) == RAMP_TOP))
|
||||
{
|
||||
above->tiletype[x][y] = 32; // open space
|
||||
countbad++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c->Resume();
|
||||
if(count)
|
||||
c->con.print("Found and changed %d tiles.\n",count);
|
||||
if(countbad)
|
||||
c->con.print("Fixed %d bad down ramps.\n",countbad);
|
||||
if (count)
|
||||
c->con.print("Found and changed %d tiles.\n", count);
|
||||
if (countbad)
|
||||
c->con.print("Fixed %d bad down ramps.\n", countbad);
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport const char * plugin_name ( void )
|
||||
{
|
||||
return "deramp";
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.clear();
|
||||
commands.push_back(PluginCommand("deramp",
|
||||
"De-ramp. All ramps marked for removal are replaced with floors.",
|
||||
df_deramp));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown ( Core * c )
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 355674a508d72349983455f04791b4481b6c1515
|
||||
Subproject commit c114ec5f995aec69631187212254309464f82775
|
@ -0,0 +1,416 @@
|
||||
#include "Core.h"
|
||||
#include "Console.h"
|
||||
#include "Export.h"
|
||||
#include "PluginManager.h"
|
||||
#include "MiscUtils.h"
|
||||
|
||||
#include "modules/Materials.h"
|
||||
#include "modules/Items.h"
|
||||
#include "modules/Gui.h"
|
||||
#include "modules/Job.h"
|
||||
|
||||
#include "DataDefs.h"
|
||||
#include "df/world.h"
|
||||
#include "df/ui.h"
|
||||
#include "df/ui_build_selector.h"
|
||||
#include "df/ui_build_item_req.h"
|
||||
#include "df/build_req_choice_genst.h"
|
||||
#include "df/build_req_choice_specst.h"
|
||||
#include "df/building_workshopst.h"
|
||||
#include "df/building_furnacest.h"
|
||||
#include "df/job.h"
|
||||
#include "df/job_item.h"
|
||||
#include "df/job_list_link.h"
|
||||
#include "df/item.h"
|
||||
#include "df/tool_uses.h"
|
||||
#include "df/general_ref.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::endl;
|
||||
using namespace DFHack;
|
||||
using namespace df::enums;
|
||||
|
||||
using df::global::world;
|
||||
using df::global::ui;
|
||||
using df::global::ui_build_selector;
|
||||
using df::global::ui_workshop_job_cursor;
|
||||
using df::global::job_next_id;
|
||||
|
||||
/* Plugin registration */
|
||||
|
||||
static bool job_material_hotkey(Core *c, df::viewscreen *top);
|
||||
|
||||
static command_result job_material(Core *c, vector <string> & parameters);
|
||||
static command_result job_duplicate(Core *c, vector <string> & parameters);
|
||||
static command_result job_cmd(Core *c, vector <string> & parameters);
|
||||
|
||||
DFhackCExport const char * plugin_name ( void )
|
||||
{
|
||||
return "jobutils";
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.clear();
|
||||
if (!world || !ui)
|
||||
return CR_FAILURE;
|
||||
|
||||
commands.push_back(
|
||||
PluginCommand(
|
||||
"job", "General job query and manipulation.",
|
||||
job_cmd, false,
|
||||
" job [query]\n"
|
||||
" Print details of the current job.\n"
|
||||
" job list\n"
|
||||
" Print details of all jobs in the workshop.\n"
|
||||
" job item-material <item-idx> <material[:subtoken]>\n"
|
||||
" Replace the exact material id in the job item.\n"
|
||||
" job item-type <item-idx> <type[:subtype]>\n"
|
||||
" Replace the exact item type id in the job item.\n"
|
||||
)
|
||||
);
|
||||
|
||||
if (ui_workshop_job_cursor || ui_build_selector) {
|
||||
commands.push_back(
|
||||
PluginCommand(
|
||||
"job-material", "Alter the material of the selected job.",
|
||||
job_material, job_material_hotkey,
|
||||
" job-material <inorganic-token>\n"
|
||||
"Intended to be used as a keybinding:\n"
|
||||
" - In 'q' mode, when a job is highlighted within a workshop\n"
|
||||
" or furnace, changes the material of the job.\n"
|
||||
" - In 'b' mode, during selection of building components\n"
|
||||
" positions the cursor over the first available choice\n"
|
||||
" with the matching material.\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (ui_workshop_job_cursor && job_next_id) {
|
||||
commands.push_back(
|
||||
PluginCommand(
|
||||
"job-duplicate", "Duplicate the selected job in a workshop.",
|
||||
job_duplicate, workshop_job_hotkey,
|
||||
" - In 'q' mode, when a job is highlighted within a workshop\n"
|
||||
" or furnace building, instantly duplicates the job.\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown ( Core * c )
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
/* UI state guards */
|
||||
|
||||
static bool job_material_hotkey(Core *c, df::viewscreen *top)
|
||||
{
|
||||
return workshop_job_hotkey(c, top) ||
|
||||
build_selector_hotkey(c, top);
|
||||
}
|
||||
|
||||
/* job-material implementation */
|
||||
|
||||
static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
|
||||
{
|
||||
df::job *job = getSelectedWorkshopJob(c);
|
||||
if (!job)
|
||||
return CR_FAILURE;
|
||||
|
||||
if (!new_mat.isValid() || new_mat.type != 0)
|
||||
{
|
||||
c->con.printerr("New job material isn't inorganic: %s\n",
|
||||
new_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
MaterialInfo cur_mat(job);
|
||||
|
||||
if (!cur_mat.isValid() || cur_mat.type != 0)
|
||||
{
|
||||
c->con.printerr("Current job material isn't inorganic: %s\n",
|
||||
cur_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
df::craft_material_class old_class = cur_mat.getCraftClass();
|
||||
if (old_class == craft_material_class::None)
|
||||
{
|
||||
c->con.printerr("Unexpected current material type: %s\n",
|
||||
cur_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
if (new_mat.getCraftClass() != old_class)
|
||||
{
|
||||
c->con.printerr("New material %s does not satisfy requirement: %s\n",
|
||||
new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class));
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < job->job_items.size(); i++)
|
||||
{
|
||||
df::job_item *item = job->job_items[i];
|
||||
MaterialInfo item_mat(item);
|
||||
|
||||
if (item_mat != cur_mat)
|
||||
{
|
||||
c->con.printerr("Job item %d has different material: %s\n",
|
||||
i, item_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
if (!new_mat.matches(*item))
|
||||
{
|
||||
c->con.printerr("Job item %d requirements not satisfied by %s.\n",
|
||||
i, new_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the substitution
|
||||
job->mat_type = new_mat.type;
|
||||
job->mat_index = new_mat.index;
|
||||
|
||||
for (unsigned i = 0; i < job->job_items.size(); i++)
|
||||
{
|
||||
df::job_item *item = job->job_items[i];
|
||||
item->mat_type = new_mat.type;
|
||||
item->mat_index = new_mat.index;
|
||||
}
|
||||
|
||||
c->con << "Applied material '" << new_mat.toString()
|
||||
<< "' to job " << ENUM_KEY_STR(job_type,job->job_type) << endl;
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choicest *choice,
|
||||
MaterialInfo &new_mat, bool ignore_select)
|
||||
{
|
||||
if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice))
|
||||
{
|
||||
if (gen->mat_type == new_mat.type &&
|
||||
gen->mat_index == new_mat.index &&
|
||||
(ignore_select || gen->used_count < gen->candidates.size()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (VIRTUAL_CAST_VAR(spec, df::build_req_choice_specst, choice))
|
||||
{
|
||||
if (spec->candidate &&
|
||||
spec->candidate->getActualMaterial() == new_mat.type &&
|
||||
spec->candidate->getActualMaterialIndex() == new_mat.index &&
|
||||
(ignore_select || !req->candidate_selected[spec->candidate_id]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static command_result job_material_in_build(Core *c, MaterialInfo &new_mat)
|
||||
{
|
||||
df::ui_build_selector *sel = ui_build_selector;
|
||||
df::ui_build_item_req *req = sel->requirements[ui_build_selector->req_index];
|
||||
|
||||
// Loop through matching choices
|
||||
bool matches = build_choice_matches(req, sel->choices[sel->sel_index], new_mat, true);
|
||||
|
||||
int size = sel->choices.size();
|
||||
int base = (matches ? sel->sel_index + 1 : 0);
|
||||
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
int idx = (base + i) % size;
|
||||
|
||||
if (build_choice_matches(req, sel->choices[idx], new_mat, false))
|
||||
{
|
||||
sel->sel_index = idx;
|
||||
return CR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
c->con.printerr("Could not find material in list: %s\n", new_mat.toString().c_str());
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
static command_result job_material(Core * c, vector <string> & parameters)
|
||||
{
|
||||
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
|
||||
|
||||
MaterialInfo new_mat;
|
||||
if (parameters.size() == 1)
|
||||
{
|
||||
if (!new_mat.find(parameters[0])) {
|
||||
c->con.printerr("Could not find material: %s\n", parameters[0].c_str());
|
||||
return CR_WRONG_USAGE;
|
||||
}
|
||||
}
|
||||
else
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
if (ui->main.mode == ui_sidebar_mode::QueryBuilding)
|
||||
return job_material_in_job(c, new_mat);
|
||||
if (ui->main.mode == ui_sidebar_mode::Build)
|
||||
return job_material_in_build(c, new_mat);
|
||||
|
||||
return CR_WRONG_USAGE;
|
||||
}
|
||||
|
||||
/* job-duplicate implementation */
|
||||
|
||||
static command_result job_duplicate(Core * c, vector <string> & parameters)
|
||||
{
|
||||
if (!parameters.empty())
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
df::job *job = getSelectedWorkshopJob(c);
|
||||
if (!job)
|
||||
return CR_FAILURE;
|
||||
|
||||
if (!job->misc_links.empty() ||
|
||||
(job->job_items.empty() &&
|
||||
job->job_type != job_type::CollectSand &&
|
||||
job->job_type != job_type::CollectClay))
|
||||
{
|
||||
c->con.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type));
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
df::building *building = world->selected_building;
|
||||
if (building->jobs.size() >= 10)
|
||||
{
|
||||
c->con.printerr("Job list is already full.\n");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
// Actually clone
|
||||
df::job *pnew = cloneJobStruct(job);
|
||||
|
||||
linkJobIntoWorld(pnew);
|
||||
vector_insert_at(building->jobs, ++*ui_workshop_job_cursor, pnew);
|
||||
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
/* Main job command implementation */
|
||||
|
||||
static df::job_item *getJobItem(Core *c, df::job *job, std::string idx)
|
||||
{
|
||||
if (!job)
|
||||
return NULL;
|
||||
|
||||
int v = atoi(idx.c_str());
|
||||
if (v < 1 || v > job->job_items.size()) {
|
||||
c->con.printerr("Invalid item index.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return job->job_items[v-1];
|
||||
}
|
||||
|
||||
static command_result job_cmd(Core * c, vector <string> & parameters)
|
||||
{
|
||||
CoreSuspender suspend(c);
|
||||
|
||||
std::string cmd = (parameters.empty() ? "query" : parameters[0]);
|
||||
if (cmd == "query" || cmd == "list")
|
||||
{
|
||||
df::job *job = getSelectedWorkshopJob(c);
|
||||
if (!job)
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
if (cmd == "query") {
|
||||
printJobDetails(c, job);
|
||||
} else {
|
||||
df::building *selected = world->selected_building;
|
||||
for (unsigned i = 0; i < selected->jobs.size(); i++)
|
||||
printJobDetails(c, selected->jobs[i]);
|
||||
}
|
||||
}
|
||||
else if (cmd == "item-material")
|
||||
{
|
||||
if (parameters.size() != 3)
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
df::job *job = getSelectedWorkshopJob(c);
|
||||
df::job_item *item = getJobItem(c, job, parameters[1]);
|
||||
if (!item)
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
ItemTypeInfo iinfo(item);
|
||||
MaterialInfo minfo;
|
||||
|
||||
if (!minfo.find(parameters[2])) {
|
||||
c->con.printerr("Could not find the specified material.\n");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
if (minfo.isValid() && !iinfo.matches(*item, &minfo)) {
|
||||
c->con.printerr("Material does not match the requirements.\n");
|
||||
printJobDetails(c, job);
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
if (job->mat_type != -1 &&
|
||||
job->mat_type == item->mat_type &&
|
||||
job->mat_index == item->mat_index)
|
||||
{
|
||||
job->mat_type = minfo.type;
|
||||
job->mat_index = minfo.index;
|
||||
}
|
||||
|
||||
item->mat_type = minfo.type;
|
||||
item->mat_index = minfo.index;
|
||||
|
||||
c->con << "Job item updated." << endl;
|
||||
|
||||
if (item->item_type < 0 && minfo.isValid())
|
||||
c->con.printerr("WARNING: Due to a probable bug, creature & plant material subtype\n"
|
||||
" is ignored unless the item type is also specified.\n");
|
||||
|
||||
printJobDetails(c, job);
|
||||
return CR_OK;
|
||||
}
|
||||
else if (cmd == "item-type")
|
||||
{
|
||||
if (parameters.size() != 3)
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
df::job *job = getSelectedWorkshopJob(c);
|
||||
df::job_item *item = getJobItem(c, job, parameters[1]);
|
||||
if (!item)
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
ItemTypeInfo iinfo;
|
||||
MaterialInfo minfo(item);
|
||||
|
||||
if (!iinfo.find(parameters[2])) {
|
||||
c->con.printerr("Could not find the specified item type.\n");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
if (iinfo.isValid() && !iinfo.matches(*item, &minfo)) {
|
||||
c->con.printerr("Item type does not match the requirements.\n");
|
||||
printJobDetails(c, job);
|
||||
return CR_FAILURE;
|
||||
}
|
||||
|
||||
item->item_type = iinfo.type;
|
||||
item->item_subtype = iinfo.subtype;
|
||||
|
||||
c->con << "Job item updated." << endl;
|
||||
printJobDetails(c, job);
|
||||
return CR_OK;
|
||||
}
|
||||
else
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
return CR_OK;
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
// All above-ground soil not covered by buildings will be covered with grass.
|
||||
// Necessary for worlds generated prior to version 0.31.19 - otherwise, outdoor shrubs and trees no longer grow.
|
||||
|
||||
#include "Core.h"
|
||||
#include "Console.h"
|
||||
#include "Export.h"
|
||||
#include "PluginManager.h"
|
||||
|
||||
#include "DataDefs.h"
|
||||
#include "df/world.h"
|
||||
#include "df/map_block.h"
|
||||
#include "TileTypes.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using namespace DFHack;
|
||||
|
||||
using df::global::world;
|
||||
|
||||
DFhackCExport command_result df_regrass (Core * c, vector <string> & parameters)
|
||||
{
|
||||
if (!parameters.empty())
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
CoreSuspender suspend(c);
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < world->map.map_blocks.size(); i++)
|
||||
{
|
||||
df::map_block *cur = world->map.map_blocks[i];
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
if (DFHack::tileShape(cur->tiletype[x][y]) != DFHack::FLOOR)
|
||||
continue;
|
||||
if (DFHack::tileMaterial(cur->tiletype[x][y]) != DFHack::SOIL)
|
||||
continue;
|
||||
if (cur->designation[x][y].bits.subterranean)
|
||||
continue;
|
||||
if (cur->occupancy[x][y].bits.building)
|
||||
continue;
|
||||
|
||||
switch (rand() % 8)
|
||||
{
|
||||
// light grass
|
||||
case 0: cur->tiletype[x][y] = 0x015C; break;
|
||||
case 1: cur->tiletype[x][y] = 0x015D; break;
|
||||
case 2: cur->tiletype[x][y] = 0x015E; break;
|
||||
case 3: cur->tiletype[x][y] = 0x015F; break;
|
||||
// dark grass
|
||||
case 4: cur->tiletype[x][y] = 0x018E; break;
|
||||
case 5: cur->tiletype[x][y] = 0x018F; break;
|
||||
case 6: cur->tiletype[x][y] = 0x0190; break;
|
||||
case 7: cur->tiletype[x][y] = 0x0191; break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
c->con.print("Regrew %d tiles of grass.\n", count);
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport const char *plugin_name ( void )
|
||||
{
|
||||
return "regrass";
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_init (Core *c, std::vector<PluginCommand> &commands)
|
||||
{
|
||||
commands.clear();
|
||||
commands.push_back(PluginCommand("regrass", "Regrows all surface grass, restoring outdoor plant growth for pre-0.31.19 worlds.", df_regrass));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown ( Core * c )
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit 1b28039e2c93daa3c2f69f5e2a000ff8c96ee1f8
|
||||
Subproject commit 92627e39cb3502812cd5a131716d3d1da8ef625a
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue