Merge branch 'develop' of https://github.com/DFHack/dfhack into develop

develop
Japa 2016-03-05 17:30:54 +05:30
commit 5ec03774b5
22 changed files with 408 additions and 111 deletions

@ -105,7 +105,7 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac
endif()
# set up versioning.
set(DF_VERSION "0.42.05")
set(DF_VERSION "0.42.06")
SET(DFHACK_RELEASE "alpha1")
SET(DFHACK_PRERELEASE TRUE)

@ -70,11 +70,31 @@ New Features
Fixes
-----
- More plugins should recognize non-dwarf citizens
- Fixed a possible crash from cloning jobs
- `confirm` note-delete: No longer interferes with name entry
- `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42
- `gaydar`: Fixed text display on OS X/Linux and failure with soul-less creatures
- `manipulator`:
- allowed editing of non-dwarf citizens
- stopped ghosts and visitors from being editable
- fixed applying last custom profession
- `modtools/create-unit`: Stopped making units without civs historical figures
- `modtools/force`:
- Removed siege option
- Prevented a crash resulting from a bad civilization option
- `showmood`: Fixed name display on OS X/Linux
Misc Improvements
-----------------
- `autolabor`, `autohauler`, `manipulator`: Added support for new jobs/labors/skills
- `devel/export-dt-ini`: Updated for 0.42.06
- `lua`: Now supports some built-in variables like `gui/gm-editor`, e.g. ``unit``, ``screen``
- `stockflow`: Now offers better control over individual craft jobs
- `weather`: now implemented by a script

@ -0,0 +1,6 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2010
cd VC2010
echo generating a build folder
cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1

@ -1,8 +1,6 @@
#define NO_DFHACK_VERSION_MACROS
#include "DFHackVersion.h"
#include "git-describe.h"
#include "Export.h"
#include <string>
namespace DFHack {
namespace Version {
const char *dfhack_version()

@ -1521,6 +1521,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, isDwarf),
WRAPM(Units, isCitizen),
WRAPM(Units, getAge),
WRAPM(Units, getKillCount),
WRAPM(Units, getNominalSkill),
WRAPM(Units, getEffectiveSkill),
WRAPM(Units, getExperience),
@ -1531,10 +1532,12 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getCasteProfessionName),
WRAPM(Units, getProfessionColor),
WRAPM(Units, getCasteProfessionColor),
WRAPM(Units, getSquadName),
WRAPM(Units, isWar),
WRAPM(Units, isHunter),
WRAPM(Units, isAvailableForAdoption),
WRAPM(Units, isOwnCiv),
WRAPM(Units, isOwnGroup),
WRAPM(Units, isOwnRace),
WRAPM(Units, getRaceName),
WRAPM(Units, getRaceNamePlural),

@ -527,3 +527,96 @@ namespace DFHack {namespace Lua {
name##_event.invoke(out, 7); \
} \
}
//No handler versions useful for vmethod events, when we already have a place to put code at triggering
#define DEFINE_LUA_EVENT_NH_0(name) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out) { \
if (name##_event.state_if_count()) { \
name##_event.invoke(out, 0); \
} \
}
#define DEFINE_LUA_EVENT_NH_1(name, arg_type1) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
name##_event.invoke(out, 1); \
} \
}
#define DEFINE_LUA_EVENT_NH_2(name, arg_type1, arg_type2) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
name##_event.invoke(out, 2); \
} \
}
#define DEFINE_LUA_EVENT_NH_3(name, arg_type1, arg_type2, arg_type3) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
name##_event.invoke(out, 3); \
} \
}
#define DEFINE_LUA_EVENT_NH_4(name, arg_type1, arg_type2, arg_type3, arg_type4) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
DFHack::Lua::Push(state, arg4); \
name##_event.invoke(out, 4); \
} \
}
#define DEFINE_LUA_EVENT_NH_5(name, arg_type1, arg_type2, arg_type3, arg_type4, arg_type5) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4, arg_type5 arg5) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
DFHack::Lua::Push(state, arg4); \
DFHack::Lua::Push(state, arg5); \
name##_event.invoke(out, 5); \
} \
}
#define DEFINE_LUA_EVENT_NH_6(name, arg_type1, arg_type2, arg_type3, arg_type4, arg_type5,arg_type6) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4,arg_type5 arg5, arg_type6 arg6) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
DFHack::Lua::Push(state, arg4); \
DFHack::Lua::Push(state, arg5); \
DFHack::Lua::Push(state, arg6); \
name##_event.invoke(out, 6); \
} \
}
#define DEFINE_LUA_EVENT_NH_7(name, arg_type1, arg_type2, arg_type3, arg_type4, arg_type5,arg_type6,arg_type7) \
static DFHack::Lua::Notification name##_event; \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4,arg_type5 arg5, arg_type6 arg6, arg_type7 arg7) { \
if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
DFHack::Lua::Push(state, arg4); \
DFHack::Lua::Push(state, arg5); \
DFHack::Lua::Push(state, arg6); \
DFHack::Lua::Push(state, arg7); \
name##_event.invoke(out, 7); \
} \
}

@ -240,6 +240,7 @@ DFHACK_EXPORT bool isWar(df::unit* unit);
DFHACK_EXPORT bool isHunter(df::unit* unit);
DFHACK_EXPORT bool isAvailableForAdoption(df::unit* unit);
DFHACK_EXPORT bool isOwnCiv(df::unit* unit);
DFHACK_EXPORT bool isOwnGroup(df::unit* unit);
DFHACK_EXPORT bool isOwnRace(df::unit* unit);
DFHACK_EXPORT std::string getRaceNameById(int32_t race_id);
@ -267,6 +268,7 @@ DFHACK_EXPORT bool isForest(df::unit* unit);
DFHACK_EXPORT bool isMarkedForSlaughter(df::unit* unit);
DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false);
DFHACK_EXPORT int getKillCount(df::unit *unit);
DFHACK_EXPORT int getNominalSkill(df::unit *unit, df::job_skill skill_id, bool use_rust = false);
DFHACK_EXPORT int getEffectiveSkill(df::unit *unit, df::job_skill skill_id);

@ -71,6 +71,7 @@ df::job *DFHack::Job::cloneJobStruct(df::job *job, bool keepEverything)
pnew->flags.bits.suspend = job->flags.bits.suspend;
pnew->completion_timer = -1;
pnew->posting_index = -1;
}
pnew->list_link = NULL;

@ -31,6 +31,7 @@ distribution.
#include <map>
#include <cstring>
#include <algorithm>
#include <numeric>
using namespace std;
#include "VersionInfo.h"
@ -47,29 +48,31 @@ using namespace std;
#include "Core.h"
#include "MiscUtils.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/job.h"
#include "df/unit_inventory_item.h"
#include "df/unit_soul.h"
#include "df/nemesis_record.h"
#include "df/historical_entity.h"
#include "df/burrow.h"
#include "df/caste_raw.h"
#include "df/creature_raw.h"
#include "df/curse_attr_change.h"
#include "df/entity_position.h"
#include "df/entity_position_assignment.h"
#include "df/entity_raw.h"
#include "df/entity_raw_flags.h"
#include "df/game_mode.h"
#include "df/histfig_entity_link_positionst.h"
#include "df/historical_entity.h"
#include "df/historical_figure.h"
#include "df/historical_figure_info.h"
#include "df/entity_position.h"
#include "df/entity_position_assignment.h"
#include "df/histfig_entity_link_positionst.h"
#include "df/historical_kills.h"
#include "df/history_event_hist_figure_diedst.h"
#include "df/identity.h"
#include "df/burrow.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
#include "df/game_mode.h"
#include "df/job.h"
#include "df/nemesis_record.h"
#include "df/squad.h"
#include "df/ui.h"
#include "df/unit_inventory_item.h"
#include "df/unit_misc_trait.h"
#include "df/unit_skill.h"
#include "df/curse_attr_change.h"
#include "df/squad.h"
#include "df/unit_soul.h"
#include "df/world.h"
using namespace DFHack;
using namespace df::enums;
@ -815,26 +818,22 @@ bool Units::isCitizen(df::unit *unit)
// except that the game appears to let melancholy/raving
// dwarves count as citizens.
if (!isDwarf(unit) || !isSane(unit))
return false;
if (unit->flags1.bits.marauder ||
unit->flags1.bits.invader_origin ||
unit->flags1.bits.active_invader ||
unit->flags1.bits.forest ||
unit->flags1.bits.merchant ||
unit->flags1.bits.diplomat)
unit->flags1.bits.diplomat ||
unit->flags2.bits.visitor ||
unit->flags2.bits.visitor_uninvited ||
unit->flags2.bits.underworld ||
unit->flags2.bits.resident)
return false;
if (unit->flags1.bits.tame)
return true;
if (!isSane(unit))
return false;
return unit->civ_id == ui->civ_id &&
unit->civ_id != -1 &&
!unit->flags2.bits.underworld &&
!unit->flags2.bits.resident &&
!unit->flags2.bits.visitor_uninvited &&
!unit->flags2.bits.visitor;
return isOwnGroup(unit);
}
bool Units::isDwarf(df::unit *unit)
@ -888,6 +887,22 @@ bool Units::isOwnCiv(df::unit* unit)
return unit->civ_id == ui->civ_id;
}
// check if creature belongs to the player's group
bool Units::isOwnGroup(df::unit* unit)
{
CHECK_NULL_POINTER(unit);
auto histfig = df::historical_figure::find(unit->hist_figure_id);
if (!histfig)
return false;
for (size_t i = 0; i < histfig->entity_links.size(); i++)
{
auto link = histfig->entity_links[i];
if (link->entity_id == ui->group_id && link->getType() == df::histfig_entity_link_type::MEMBER)
return true;
}
return false;
}
// check if creature belongs to the player's race
// (in combination with check for civ helps to filter out own dwarves)
bool Units::isOwnRace(df::unit* unit)
@ -1084,6 +1099,25 @@ double Units::getAge(df::unit *unit, bool true_age)
return cur_time - birth_time;
}
int Units::getKillCount(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
auto histfig = df::historical_figure::find(unit->hist_figure_id);
int count = 0;
if (histfig && histfig->info->kills)
{
auto kills = histfig->info->kills;
count += std::accumulate(kills->killed_count.begin(), kills->killed_count.end(), 0);
for (auto it = kills->events.begin(); it != kills->events.end(); ++it)
{
if (virtual_cast<df::history_event_hist_figure_diedst>(df::history_event::find(*it)))
++count;
}
}
return count;
}
inline void adjust_skill_rating(int &rating, bool is_adventure, int value, int dwarf3_4, int dwarf1_2, int adv9_10, int adv3_4, int adv1_2)
{
if (is_adventure)
@ -1783,6 +1817,7 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid)
std::string Units::getSquadName(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
if (unit->military.squad_id == -1)
return "";
df::squad *squad = df::squad::find(unit->military.squad_id);

@ -1 +1 @@
Subproject commit dd3e9e7f47a7991e91d5188546be107fdb61015b
Subproject commit 49e1324f415056f3ae39cb32328e3351a3a2b383

@ -107,6 +107,23 @@ void add_tasks(gem_map &gem_types, df::building_workshopst *workshop) {
}
}
bool valid_gem(df::item* item) {
if (item->getType() != item_type::ROUGH) return false;
if (item->getMaterial() != builtin_mats::INORGANIC) return false;
if (item->flags.bits.in_job) return false;
if (item->flags.bits.forbid) return false;
if (item->flags.bits.dump) return false;
if (item->flags.bits.owned) return false;
if (item->flags.bits.trader) return false;
if (item->flags.bits.hostile) return false;
if (item->flags.bits.removed) return false;
if (item->flags.bits.encased) return false;
if (item->flags.bits.construction) return false;
if (item->flags.bits.garbage_collect) return false;
if (item->flags.bits.in_building) return false;
return true;
}
void create_jobs() {
// Creates jobs in Jeweler's Workshops as necessary.
// Todo: Consider path availability?
@ -137,7 +154,7 @@ void create_jobs() {
Buildings::StockpileIterator stored;
for (stored.begin(stockpile); !stored.done(); ++stored) {
auto item = *stored;
if (item->getType() == item_type::ROUGH && item->getMaterial() == builtin_mats::INORGANIC) {
if (valid_gem(item)) {
stockpiled.insert(item->id);
piled[item->getMaterialIndex()] += 1;
}
@ -182,8 +199,7 @@ void create_jobs() {
auto gems = world->items.other[items_other_id::ROUGH];
for (auto g = gems.begin(); g != gems.end(); ++g) {
auto item = *g;
// ROUGH also includes raw glass; the INORGANIC check filters that out.
if (item->getMaterial() == builtin_mats::INORGANIC && !stockpiled.count(item->id)) {
if (valid_gem(item) && !stockpiled.count(item->id)) {
available[item->getMaterialIndex()] += 1;
}
}
@ -268,7 +284,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
if (enabled && World::isFortressMode()) {
// Determine whether auto gem cutting has been disabled for this fort.
auto config = World::GetPersistentData(CONFIG_KEY);
running = !(config.isValid() && config.ival(0));
running = config.isValid() && !config.ival(0);
last_frame_count = world->frame_counter;
}
} else if (event == DFHack::SC_MAP_UNLOADED) {
@ -286,9 +302,9 @@ DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) {
}
enabled = enable;
running = enabled && World::isFortressMode();
}
running = enabled && World::isFortressMode();
return CR_OK;
}

@ -365,7 +365,15 @@ static const dwarf_state dwarf_states[] = {
BUSY /* PushTrackVehicle */,
BUSY /* PlaceTrackVehicle */,
BUSY /* StoreItemInVehicle */,
BUSY /* GeldAnimal */
BUSY /* GeldAnimal */,
BUSY /* MakeFigurine */,
BUSY /* MakeAmulet */,
BUSY /* MakeScepter */,
BUSY /* MakeCrown */,
BUSY /* MakeRing */,
BUSY /* MakeEarring */,
BUSY /* MakeBracelet */,
BUSY /* MakeGem */
};
struct labor_info

@ -360,7 +360,16 @@ static const dwarf_state dwarf_states[] = {
BUSY /* CarveTrack */,
BUSY /* PushTrackVehicle */,
BUSY /* PlaceTrackVehicle */,
BUSY /* StoreItemInVehicle */
BUSY /* StoreItemInVehicle */,
BUSY /* GeldAnimal */,
BUSY /* MakeFigurine */,
BUSY /* MakeAmulet */,
BUSY /* MakeScepter */,
BUSY /* MakeCrown */,
BUSY /* MakeRing */,
BUSY /* MakeEarring */,
BUSY /* MakeBracelet */,
BUSY /* MakeGem */
};
struct labor_info
@ -1328,6 +1337,15 @@ public:
job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE);
job_to_labor_table[df::job_type::GeldAnimal] = jlf_const(df::unit_labor::GELD);
job_to_labor_table[df::job_type::MakeFigurine] = jlf_make_object;
job_to_labor_table[df::job_type::MakeAmulet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeScepter] = jlf_make_object;
job_to_labor_table[df::job_type::MakeCrown] = jlf_make_object;
job_to_labor_table[df::job_type::MakeRing] = jlf_make_object;
job_to_labor_table[df::job_type::MakeEarring] = jlf_make_object;
job_to_labor_table[df::job_type::MakeBracelet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeGem] = jlf_make_object;
};
df::unit_labor find_job_labor(df::job* j)

@ -92,51 +92,32 @@ static bool is_lua_hook(const std::string &name)
/*
* Hooks
*/
static void handle_fillsidebar(color_ostream &out,df::building_actual*,bool *call_native){};
static void handle_postfillsidebar(color_ostream &out,df::building_actual*){};
static void handle_reaction_done(color_ostream &out,df::reaction*, df::reaction_product_itemst*, df::unit *unit, std::vector<df::item*> *in_items,std::vector<df::reaction_reagent*> *in_reag
, std::vector<df::item*> *out_items,bool *call_native){};
static void handle_contaminate_wound(color_ostream &out,df::item_actual*,df::unit* unit, df::unit_wound* wound, uint8_t a1, int16_t a2){};
static void handle_projitem_ci(color_ostream &out,df::proj_itemst*,bool){};
static void handle_projitem_cm(color_ostream &out,df::proj_itemst*){};
static void handle_projunit_ci(color_ostream &out,df::proj_unitst*,bool){};
static void handle_projunit_cm(color_ostream &out,df::proj_unitst*){};
DEFINE_LUA_EVENT_2(onWorkshopFillSidebarMenu, handle_fillsidebar, df::building_actual*,bool* );
DEFINE_LUA_EVENT_1(postWorkshopFillSidebarMenu, handle_postfillsidebar, df::building_actual*);
DEFINE_LUA_EVENT_7(onReactionComplete, handle_reaction_done,df::reaction*, df::reaction_product_itemst*, df::unit *, std::vector<df::item*> *,std::vector<df::reaction_reagent*> *,std::vector<df::item*> *,bool *);
DEFINE_LUA_EVENT_5(onItemContaminateWound, handle_contaminate_wound, df::item_actual*,df::unit* , df::unit_wound* , uint8_t , int16_t );
DEFINE_LUA_EVENT_NH_2(onWorkshopFillSidebarMenu, df::building_actual*, bool*);
DEFINE_LUA_EVENT_NH_1(postWorkshopFillSidebarMenu, df::building_actual*);
DEFINE_LUA_EVENT_NH_7(onReactionComplete, df::reaction*, df::reaction_product_itemst*, df::unit *, std::vector<df::item*> *, std::vector<df::reaction_reagent*> *, std::vector<df::item*> *, bool *);
DEFINE_LUA_EVENT_NH_5(onItemContaminateWound, df::item_actual*, df::unit*, df::unit_wound*, uint8_t, int16_t);
//projectiles
DEFINE_LUA_EVENT_2(onProjItemCheckImpact, handle_projitem_ci, df::proj_itemst*,bool );
DEFINE_LUA_EVENT_1(onProjItemCheckMovement, handle_projitem_cm, df::proj_itemst*);
DEFINE_LUA_EVENT_2(onProjUnitCheckImpact, handle_projunit_ci, df::proj_unitst*,bool );
DEFINE_LUA_EVENT_1(onProjUnitCheckMovement, handle_projunit_cm, df::proj_unitst* );
DEFINE_LUA_EVENT_NH_2(onProjItemCheckImpact, df::proj_itemst*, bool);
DEFINE_LUA_EVENT_NH_1(onProjItemCheckMovement, df::proj_itemst*);
DEFINE_LUA_EVENT_NH_2(onProjUnitCheckImpact, df::proj_unitst*, bool);
DEFINE_LUA_EVENT_NH_1(onProjUnitCheckMovement, df::proj_unitst*);
//event manager
static void handle_int32t(color_ostream &out,int32_t){}; //we don't use this so why not use it everywhere
static void handle_job_init(color_ostream &out,df::job*){};
static void handle_job_complete(color_ostream &out,df::job*){};
static void handle_constructions(color_ostream &out,df::construction*){};
static void handle_syndrome(color_ostream &out,int32_t,int32_t){};
static void handle_inventory_change(color_ostream& out,int32_t,int32_t,df::unit_inventory_item*,df::unit_inventory_item*){};
static void handle_report(color_ostream& out,int32_t){};
static void handle_unitAttack(color_ostream& out,int32_t,int32_t,int32_t){};
static void handle_unload(color_ostream& out){};
static void handle_interaction(color_ostream& out, std::string, std::string, int32_t, int32_t, int32_t, int32_t){};
DEFINE_LUA_EVENT_1(onBuildingCreatedDestroyed, handle_int32t, int32_t);
DEFINE_LUA_EVENT_1(onJobInitiated,handle_job_init,df::job*);
DEFINE_LUA_EVENT_1(onJobCompleted,handle_job_complete,df::job*);
DEFINE_LUA_EVENT_1(onUnitDeath,handle_int32t,int32_t);
DEFINE_LUA_EVENT_1(onItemCreated,handle_int32t,int32_t);
DEFINE_LUA_EVENT_1(onConstructionCreatedDestroyed, handle_constructions, df::construction*);
DEFINE_LUA_EVENT_2(onSyndrome, handle_syndrome, int32_t,int32_t);
DEFINE_LUA_EVENT_1(onInvasion,handle_int32t,int32_t);
DEFINE_LUA_EVENT_4(onInventoryChange,handle_inventory_change,int32_t,int32_t,df::unit_inventory_item*,df::unit_inventory_item*);
DEFINE_LUA_EVENT_1(onReport,handle_report,int32_t);
DEFINE_LUA_EVENT_3(onUnitAttack,handle_unitAttack,int32_t,int32_t,int32_t);
DEFINE_LUA_EVENT_0(onUnload,handle_unload);
DEFINE_LUA_EVENT_6(onInteraction,handle_interaction, std::string, std::string, int32_t, int32_t, int32_t, int32_t);
DEFINE_LUA_EVENT_NH_1(onBuildingCreatedDestroyed, int32_t);
DEFINE_LUA_EVENT_NH_1(onJobInitiated, df::job*);
DEFINE_LUA_EVENT_NH_1(onJobCompleted, df::job*);
DEFINE_LUA_EVENT_NH_1(onUnitDeath, int32_t);
DEFINE_LUA_EVENT_NH_1(onItemCreated, int32_t);
DEFINE_LUA_EVENT_NH_1(onConstructionCreatedDestroyed, df::construction*);
DEFINE_LUA_EVENT_NH_2(onSyndrome, int32_t, int32_t);
DEFINE_LUA_EVENT_NH_1(onInvasion, int32_t);
DEFINE_LUA_EVENT_NH_4(onInventoryChange, int32_t, int32_t, df::unit_inventory_item*, df::unit_inventory_item*);
DEFINE_LUA_EVENT_NH_1(onReport, int32_t);
DEFINE_LUA_EVENT_NH_3(onUnitAttack, int32_t, int32_t, int32_t);
DEFINE_LUA_EVENT_NH_0(onUnload);
DEFINE_LUA_EVENT_NH_6(onInteraction, std::string, std::string, int32_t, int32_t, int32_t, int32_t);
DFHACK_PLUGIN_LUA_EVENTS {
DFHACK_LUA_EVENT(onWorkshopFillSidebarMenu),
DFHACK_LUA_EVENT(postWorkshopFillSidebarMenu),
@ -306,7 +287,7 @@ IMPLEMENT_VMETHOD_INTERPOSE(furnace_hook, fillSidebarMenu);
struct product_hook : item_product {
typedef item_product interpose_base;
DEFINE_VMETHOD_INTERPOSE(
void, produce,
(df::unit *unit,
@ -417,8 +398,6 @@ static bool find_reactions(color_ostream &out)
for (size_t i = 0; i < rlist.size(); i++)
{
//if (!is_lua_hook(rlist[i]->code))
// continue;
reactions[rlist[i]->code].react = rlist[i];
}
@ -460,7 +439,6 @@ static void world_specific_hooks(color_ostream &out,bool enable)
{
if(enable && find_reactions(out))
{
//out.print("Detected reaction hooks - enabling plugin.\n");
INTERPOSE_HOOK(product_hook, produce).apply(true);
}
else

@ -272,6 +272,8 @@ function collect_reactions()
materials.wood.adjective = "wooden"
materials.tooth.adjective = "ivory/tooth"
materials.leather.clothing_flag = "LEATHER"
materials.shell.short = true
materials.pearl.short = true
-- Collection and Entrapment
reaction_entry(result, job_types.CollectWebs)
@ -360,6 +362,7 @@ function collect_reactions()
local cloth_mats = {materials.cloth, materials.silk, materials.yarn, materials.leather}
for _, material in ipairs(cloth_mats) do
material_reactions(result, {{job_types.SewImage, "Sew", "Image"}}, material)
material.cloth = true
end
for _, spec in ipairs{materials.bone, materials.shell, materials.tooth, materials.horn, materials.pearl} do
@ -527,6 +530,14 @@ function collect_reactions()
{job_types.MakeFlask, "Forge", "Flask"},
{job_types.MakeChain, "Forge", "Chain"},
{job_types.MakeCrafts, "Make", "Crafts"},
{job_types.MakeFigurine, "Make", "Figurine"},
{job_types.MakeAmulet, "Make", "Amulet"},
{job_types.MakeScepter, "Make", "Scepter"},
{job_types.MakeCrown, "Make", "Crown"},
{job_types.MakeRing, "Make", "Ring"},
{job_types.MakeEarring, "Make", "Earring"},
{job_types.MakeBracelet, "Make", "Bracelet"},
{job_types.MakeGem, "Make Large", "Gem"},
}, mat_flags)
end
@ -719,6 +730,7 @@ function collect_reactions()
end
end
-- Crafts
for _, mat in ipairs{
materials.wood,
materials.rock,
@ -732,7 +744,27 @@ function collect_reactions()
materials.pearl,
materials.yarn,
} do
material_reactions(result, {{job_types.MakeCrafts, "Make", "Crafts"}}, mat)
material_reactions(result, {
{job_types.MakeCrafts, "Make", "Crafts"},
{job_types.MakeAmulet, "Make", "Amulet"},
{job_types.MakeBracelet, "Make", "Bracelet"},
{job_types.MakeEarring, "Make", "Earring"},
}, mat)
if not mat.cloth then
material_reactions(result, {
{job_types.MakeCrown, "Make", "Crown"},
{job_types.MakeFigurine, "Make", "Figurine"},
{job_types.MakeRing, "Make", "Ring"},
{job_types.MakeGem, "Make Large", "Gem"},
}, mat)
if not mat.short then
material_reactions(result, {
{job_types.MakeScepter, "Make", "Scepter"},
}, mat)
end
end
end
-- Siege engine parts

@ -256,10 +256,26 @@ const SkillColumn columns[] = {
{19, 6, profession::NONE, unit_labor::NONE, job_skill::POETRY, "Po"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::READING, "Rd"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::SPEAKING, "Sp"},
{20, 5, profession::NONE, unit_labor::NONE, job_skill::MILITARY_TACTICS, "MT"},
{20, 5, profession::NONE, unit_labor::NONE, job_skill::TRACKING, "Tr"},
{20, 5, profession::NONE, unit_labor::NONE, job_skill::MAGIC_NATURE, "Dr"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::DANCE, "Dn"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::MAKE_MUSIC, "MM"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::SING_MUSIC, "SM"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_KEYBOARD_INSTRUMENT, "PK"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_STRINGED_INSTRUMENT, "PS"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_WIND_INSTRUMENT, "PW"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_PERCUSSION_INSTRUMENT, "PP"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::CRITICAL_THINKING, "CT"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::LOGIC, "Lo"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::MATHEMATICS, "Ma"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::ASTRONOMY, "As"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::CHEMISTRY, "Ch"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::GEOGRAPHY, "Ge"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::OPTICS_ENGINEER, "OE"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::FLUID_ENGINEER, "FE"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::MILITARY_TACTICS, "MT"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::TRACKING, "Tr"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::MAGIC_NATURE, "Dr"},
};
struct UnitInfo
@ -992,7 +1008,7 @@ public:
}
void select_profession(size_t selected)
{
if (selected >= manager.templates.size())
if (selected > manager.templates.size())
return;
ProfessionTemplate prof = manager.templates[selected - 1];
@ -1127,15 +1143,21 @@ viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector<df::unit*> &src, int cur
cur->selected = false;
cur->active_index = active_idx[unit];
if (!Units::isOwnRace(unit))
if (!Units::isOwnCiv(unit))
cur->allowEdit = false;
if (!Units::isOwnCiv(unit))
if (!Units::isOwnGroup(unit))
cur->allowEdit = false;
if (unit->flags1.bits.dead)
cur->allowEdit = false;
if (unit->flags2.bits.visitor)
cur->allowEdit = false;
if (unit->flags3.bits.ghostly)
cur->allowEdit = false;
if (!ENUM_ATTR(profession, can_assign_labor, unit->profession))
cur->allowEdit = false;

@ -179,6 +179,7 @@ address('shearable_tissues_vector',df.caste_raw,'shearable_tissue_layer')
address('extracts',df.caste_raw,'extracts','extract_matidx')
header('hist_entity_offsets')
address('histfigs',df.historical_entity,'histfig_ids')
address('beliefs',df.historical_entity,'resources','values')
address('squads',df.historical_entity,'squads')
address('positions',df.historical_entity,'positions','own')
@ -300,6 +301,7 @@ address('race',df.unit,'race')
address('flags1',df.unit,'flags1')
address('flags2',df.unit,'flags2')
address('flags3',df.unit,'flags3')
address('meeting',df.unit,'meeting')
address('caste',df.unit,'caste')
address('sex',df.unit,'sex')
address('id',df.unit,'id')
@ -432,7 +434,7 @@ address('uniform_item_filter',df.squad_uniform_spec,'item_filter')
address('uniform_indiv_choice',df.squad_uniform_spec,'indiv_choice')
header('activity_offsets')
address('activity_type',df.activity_entry,'id')
address('activity_type',df.activity_entry,'type')
address('events',df.activity_entry,'events')
address('participants',df.activity_event_combat_trainingst,'participants')
address('sq_lead',df.activity_event_skill_demonstrationst,'hist_figure_id')

@ -87,6 +87,7 @@ versions = {
[1533] = "0.42.03",
[1534] = "0.42.04",
[1537] = "0.42.05",
[1542] = "0.42.06",
}
min_version = math.huge

@ -56,6 +56,10 @@ orientation filters:
return
end
function dfprint(s)
print(dfhack.df2console(s))
end
function getSexString(sex)
local sexStr
if sex==0 then
@ -69,11 +73,11 @@ function getSexString(sex)
end
local function determineorientation(unit)
if unit.sex~=-1 then
if unit.sex~=-1 and unit.status.current_soul then
local return_string=''
local orientation=unit.status.current_soul.orientation_flags
if orientation.indeterminate then
return 'indeterminate (probably adventurer)'
return ' indeterminate (probably adventurer)'
end
local male_interested,asexual=false,true
if orientation.romance_male then
@ -105,7 +109,7 @@ local function determineorientation(unit)
end
return return_string
else
return "is not biologically capable of sex"
return " is not biologically capable of sex"
end
end
@ -139,7 +143,7 @@ elseif args.named then
else
local unit=dfhack.gui.getSelectedUnit(true)
local name,ok=nameOrSpeciesAndNumber(unit)
print(name..determineorientation(unit))
dfprint(name..determineorientation(unit))
return
end
@ -169,35 +173,35 @@ end
if args.notStraight then
local totalNotShown=0
for k,v in ipairs(orientations) do
if isNotStraight(v) then print(v) else totalNotShown=totalNotShown+1 end
if isNotStraight(v) then dfprint(v) else totalNotShown=totalNotShown+1 end
end
print('Total not shown: '..totalNotShown)
elseif args.gayOnly then
local totalNotShown=0
for k,v in ipairs(orientations) do
if isGay(v) then print(v) else totalNotShown=totalNotShown+1 end
if isGay(v) then dfprint(v) else totalNotShown=totalNotShown+1 end
end
print('Total not shown: '..totalNotShown)
elseif args.asexualOnly then
local totalNotShown=0
for k,v in ipairs(orientations) do
if isAsexual(v) then print(v) else totalNotShown=totalNotShown+1 end
if isAsexual(v) then dfprint(v) else totalNotShown=totalNotShown+1 end
end
print('Total not shown: '..totalNotShown)
elseif args.straightOnly then
local totalNotShown=0
for k,v in ipairs(orientations) do
if not isNotStraight(v) then print(v) else totalNotShown=totalNotShown+1 end
if not isNotStraight(v) then dfprint(v) else totalNotShown=totalNotShown+1 end
end
print('Total not shown: '..totalNotShown)
elseif args.biOnly then
local totalNotShown=0
for k,v in ipairs(orientations) do
if isBi(v) then print(v) else totalNotShown=totalNotShown+1 end
if isBi(v) then dfprint(v) else totalNotShown=totalNotShown+1 end
end
print('Total not shown: '..totalNotShown)
else
for k,v in ipairs(orientations) do
print(v)
dfprint(v)
end
end

@ -27,6 +27,25 @@ There are the following ways to invoke this command:
local args={...}
local cmd = args[1]
env = env or {}
setmetatable(env, {__index = function(self, k)
if k == 'scr' or k == 'screen' then
return dfhack.gui.getCurViewscreen()
elseif k == 'bld' or k == 'building' then
return dfhack.gui.getSelectedBuilding()
elseif k == 'item' then
return dfhack.gui.getSelectedItem()
elseif k == 'job' then
return dfhack.gui.getSelectedJob()
elseif k == 'wsjob' or k == 'workshop_job' then
return dfhack.gui.getSelectedWorkshopJob()
elseif k == 'unit' then
return dfhack.gui.getSelectedUnit()
else
return _G[k]
end
end})
if cmd=="--file" or cmd=="-f" then
local f,err=loadfile (args[2])
if f==nil then
@ -68,5 +87,5 @@ elseif cmd~=nil then
end
end
else
dfhack.interpreter("lua","lua.history")
dfhack.interpreter("lua","lua.history",env)
end

@ -1,8 +1,10 @@
-- create-unit.lua
-- Originally created by warmist, edited by Putnam for the dragon ball mod to be used in reactions, modified by Dirst for use in The Earth Strikes Back mod, incorporating fixes discovered by Boltgun then Mifiki wrote the bit where it switches to arena mode briefly to do some of the messy work, then Expwnent combined that with the old script to make it function for histfigs
-- version 0.5
-- version 0.51
-- This is a beta version. Use at your own risk.
-- Modifications from 0.5: civ -1 creates are NOT historical figures, mitigated screen-movement bug in createUnit()
--[[
TODO
children and babies: set child/baby job
@ -30,6 +32,10 @@ end
local utils=require 'utils'
function createUnit(race_id, caste_id)
local view_x = df.global.window_x
local view_y = df.global.window_y
local view_z = df.global.window_z
local curViewscreen = dfhack.gui.getCurViewscreen()
local dwarfmodeScreen = df.viewscreen_dwarfmodest:new()
curViewscreen.child = dwarfmodeScreen
@ -64,6 +70,11 @@ function createUnit(race_id, caste_id)
df.global.ui.main.mode = oldMode
local id = df.global.unit_next_id-1
df.global.window_x = view_x
df.global.window_y = view_y
df.global.window_z = view_z
return id
end
@ -261,6 +272,22 @@ function domesticate(uid, group_id)
end
end
function wild(uid)
local u = df.unit.find(uid)
local caste=df.creature_raw.find(u.race).caste[u.caste]
-- x = df.global.world.world_data.active_site[0].pos.x
-- y = df.global.world.world_data.active_site[0].pos.y
-- region = df.global.map.map_blocks[df.global.map.x_count_block*x+y]
if not(caste.flags.CAN_SPEAK and caste.flags.CAN_LEARN) then
u.animal.population.region_x = 1
u.animal.population.region_y = 1
u.animal.population.unk_28 = -1
u.animal.population.population_idx = 1
u.animal.population.depth = 0
end
end
function nameUnit(id, entityRawName, civ_id)
--pick a random appropriate name
--choose three random words in the appropriate things
@ -448,10 +475,17 @@ elseif args.groupId and tonumber(args.groupId) then
group_id = tonumber(args.groupId)
end
local unitId = createUnitInCiv(raceIndex, casteIndex, civ_id, group_id)
local unitId
if civ_id == -1 then
unitId = createUnit(raceIndex, casteIndex)
else
unitId = createUnitInCiv(raceIndex, casteIndex, civ_id, group_id)
end
if args.domesticate then
domesticate(unitId, group_id)
else
wild(unitId)
end
if age or age == 0 then

@ -6,7 +6,7 @@
modtools/force
==============
This tool triggers events like megabeasts, caravans, invaders, and migrants.
This tool triggers events like megabeasts, caravans, and migrants.
=end]]
local utils = require 'utils'
@ -44,7 +44,6 @@ arguments:
WildlifeCurious
WildlifeMischievous
WildlifeFlier
CivAttack
NightCreature
-civ entity
specify the civ of the event, if applicable
@ -54,7 +53,7 @@ arguments:
EVIL
28
]])
print('force: -eventType [Megabeast, Migrants, Caravan, Diplomat, WildlifeCurious, WildlifeMischievous, WildlifeFlier, CivAttack, NightCreature] -civ [player,ENTITY_ID]')
print('force: -eventType [Megabeast, Migrants, Caravan, Diplomat, WildlifeCurious, WildlifeMischievous, WildlifeFlier, NightCreature] -civ [player,ENTITY_ID]')
return
end
@ -67,7 +66,13 @@ end
if args.civ == 'player' then
args.civ = df.historical_entity.find(df.global.ui.civ_id)
elseif args.civ then
local civ = args.civ
args.civ = findCiv(args.civ)
if not args.civ then
error('Invalid civ: ' .. civ)
end
elseif args.eventType == 'Caravan' or args.eventType == 'Diplomat' then
error('Specify civ for this eventType')
end
if args.eventType == 'Migrants' then