Replace fixdiplomats, fixmerchants with scripts

develop
PeridexisErrant 2016-04-20 11:08:02 +10:00
parent 50f2851772
commit acac839371
6 changed files with 197 additions and 257 deletions

@ -112,6 +112,8 @@ Misc Improvements
- `createitem`: Can now create items anywhere without specifying a unit, as long as a unit exists on the map
- `devel/export-dt-ini`: Updated for 0.42.06
- `devel/find-offsets`: Automated several more scans
- `fix/diplomats`: replaces ``fixdiplomats``
- `fix/merchants`: replaces ``fixmerchants``
- `gui/gm-editor`: Now supports finding some items with a numeric ID (with ``i``)
- `lua`: Now supports some built-in variables like `gui/gm-editor`, e.g. ``unit``, ``screen``
- `remotefortressreader`: Can now trigger keyboard events

@ -180,18 +180,6 @@ Bugfixes
.. contents::
:local:
fixdiplomats
============
Adds a Diplomat position to all Elven civilizations, allowing them to negotiate
tree cutting quotas - and you to violate them and start wars.
This was vanilla behaviour until ``0.31.12``, in which the "bug" was "fixed".
fixmerchants
============
Adds the Guild Representative position to all Human civilizations,
allowing them to make trade agreements. This was the default behaviour in
``0.28.181.40d`` and earlier.
.. _fix-unit-occupancy:
fix-unit-occupancy

@ -99,7 +99,6 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(fastdwarf fastdwarf.cpp)
DFHACK_PLUGIN(filltraffic filltraffic.cpp)
DFHACK_PLUGIN(fix-armory fix-armory.cpp)
DFHACK_PLUGIN(fixpositions fixpositions.cpp)
DFHACK_PLUGIN(fix-unit-occupancy fix-unit-occupancy.cpp)
DFHACK_PLUGIN(fixveins fixveins.cpp)
DFHACK_PLUGIN(flows flows.cpp)

@ -1,244 +0,0 @@
// Fix Entity Positions - make sure Elves have diplomats and Humans have guild representatives
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <DataDefs.h>
#include "df/world.h"
#include "df/historical_entity.h"
#include "df/entity_raw.h"
#include "df/entity_position.h"
#include "df/entity_position_responsibility.h"
#include "df/entity_position_assignment.h"
using std::string;
using std::vector;
using namespace DFHack;
using namespace df::enums;
DFHACK_PLUGIN("fixpositions");
REQUIRE_GLOBAL(world);
command_result df_fixdiplomats (color_ostream &out, vector<string> &parameters)
{
if (!parameters.empty())
return CR_WRONG_USAGE;
CoreSuspender suspend;
int checked = 0, fixed = 0;
for (int i = 0; i < world->entities.all.size(); i++)
{
df::historical_entity *ent = world->entities.all[i];
// only work with civilizations - ignore groups and religions
if (ent->type != 0)
continue;
// only add diplomats for tree cap diplomacy
if (!ent->entity_raw->flags.is_set(entity_raw_flags::TREE_CAP_DIPLOMACY))
continue;
checked++;
bool update = true;
df::entity_position *pos = NULL;
// see if we need to add a new position or modify an existing one
for (int j = 0; j < ent->positions.own.size(); j++)
{
pos = ent->positions.own[j];
if (pos->responsibilities[entity_position_responsibility::MAKE_INTRODUCTIONS] &&
pos->responsibilities[entity_position_responsibility::MAKE_PEACE_AGREEMENTS] &&
pos->responsibilities[entity_position_responsibility::MAKE_TOPIC_AGREEMENTS])
{
// a diplomat position exists with the proper responsibilities - skip to the end
update = false;
break;
}
// Diplomat position already exists, but has the wrong options - modify it instead of creating a new one
if (pos->code == "DIPLOMAT")
break;
pos = NULL;
}
if (update)
{
// either there's no diplomat, or there is one and it's got the wrong responsibilities
if (!pos)
{
// there was no diplomat - create it
pos = new df::entity_position;
ent->positions.own.push_back(pos);
pos->code = "DIPLOMAT";
pos->id = ent->positions.next_position_id++;
pos->flags.set(entity_position_flags::DO_NOT_CULL);
pos->flags.set(entity_position_flags::MENIAL_WORK_EXEMPTION);
pos->flags.set(entity_position_flags::SLEEP_PRETENSION);
pos->flags.set(entity_position_flags::PUNISHMENT_EXEMPTION);
pos->flags.set(entity_position_flags::ACCOUNT_EXEMPT);
pos->flags.set(entity_position_flags::DUTY_BOUND);
pos->flags.set(entity_position_flags::COLOR);
pos->flags.set(entity_position_flags::HAS_RESPONSIBILITIES);
pos->flags.set(entity_position_flags::IS_DIPLOMAT);
pos->flags.set(entity_position_flags::IS_LEADER);
// not sure what these flags do, but the game sets them for a valid diplomat
pos->flags.set(entity_position_flags::unk_12);
pos->flags.set(entity_position_flags::unk_1a);
pos->flags.set(entity_position_flags::unk_1b);
pos->name[0] = "Diplomat";
pos->name[1] = "Diplomats";
pos->precedence = 70;
pos->color[0] = 7;
pos->color[1] = 0;
pos->color[2] = 1;
}
// assign responsibilities
pos->responsibilities[entity_position_responsibility::MAKE_INTRODUCTIONS] = true;
pos->responsibilities[entity_position_responsibility::MAKE_PEACE_AGREEMENTS] = true;
pos->responsibilities[entity_position_responsibility::MAKE_TOPIC_AGREEMENTS] = true;
}
// make sure the diplomat position, whether we created it or not, is set up for proper assignment
bool assign = true;
for (int j = 0; j < ent->positions.assignments.size(); j++)
{
if (ent->positions.assignments[j]->position_id == pos->id)
{
// it is - nothing more to do here
assign = false;
break;
}
}
if (assign)
{
// it isn't - set it up
df::entity_position_assignment *asn = new df::entity_position_assignment;
ent->positions.assignments.push_back(asn);
asn->id = ent->positions.next_assignment_id++;
asn->position_id = pos->id;
asn->flags.extend(0x1F); // make room for 32 flags
asn->flags.set(0); // and set the first one
}
if (update || assign)
fixed++;
}
out.print("Fixed %d of %d civilizations to enable tree cap diplomacy.\n", fixed, checked);
return CR_OK;
}
command_result df_fixmerchants (color_ostream &out, vector<string> &parameters)
{
if (!parameters.empty())
return CR_WRONG_USAGE;
CoreSuspender suspend;
int checked = 0, fixed = 0;
for (int i = 0; i < world->entities.all.size(); i++)
{
df::historical_entity *ent = world->entities.all[i];
// only work with civilizations - ignore groups and religions
if (ent->type != 0)
continue;
// only add guild reps for merchant nobility
if (!ent->entity_raw->flags.is_set(entity_raw_flags::MERCHANT_NOBILITY))
continue;
checked++;
bool update = true;
df::entity_position *pos = NULL;
// see if we need to add a new position or modify an existing one
for (int j = 0; j < ent->positions.own.size(); j++)
{
pos = ent->positions.own[j];
if (pos->responsibilities[entity_position_responsibility::TRADE])
{
// a guild rep exists with the proper responsibilities - skip to the end
update = false;
break;
}
// Guild Representative position already exists, but has the wrong options - modify it instead of creating a new one
if (pos->code == "GUILD_REPRESENTATIVE")
break;
pos = NULL;
}
if (update)
{
// either there's no guild rep, or there is one and it's got the wrong responsibilities
if (!pos)
{
// there was no guild rep - create it
pos = new df::entity_position;
ent->positions.own.push_back(pos);
pos->code = "GUILD_REPRESENTATIVE";
pos->id = ent->positions.next_position_id++;
pos->flags.set(entity_position_flags::DO_NOT_CULL);
pos->flags.set(entity_position_flags::MENIAL_WORK_EXEMPTION);
pos->flags.set(entity_position_flags::SLEEP_PRETENSION);
pos->flags.set(entity_position_flags::PUNISHMENT_EXEMPTION);
pos->flags.set(entity_position_flags::ACCOUNT_EXEMPT);
pos->flags.set(entity_position_flags::DUTY_BOUND);
pos->flags.set(entity_position_flags::COLOR);
pos->flags.set(entity_position_flags::HAS_RESPONSIBILITIES);
pos->flags.set(entity_position_flags::IS_DIPLOMAT);
pos->flags.set(entity_position_flags::IS_LEADER);
// not sure what these flags do, but the game sets them for a valid guild rep
pos->flags.set(entity_position_flags::unk_12);
pos->flags.set(entity_position_flags::unk_1a);
pos->flags.set(entity_position_flags::unk_1b);
pos->name[0] = "Guild Representative";
pos->name[1] = "Guild Representatives";
pos->precedence = 40;
pos->color[0] = 7;
pos->color[1] = 0;
pos->color[2] = 1;
}
// assign responsibilities
pos->responsibilities[entity_position_responsibility::TRADE] = true;
}
// make sure the guild rep position, whether we created it or not, is set up for proper assignment
bool assign = true;
for (int j = 0; j < ent->positions.assignments.size(); j++)
{
if (ent->positions.assignments[j]->position_id == pos->id)
{
// it is - nothing more to do here
assign = false;
break;
}
}
if (assign)
{
// it isn't - set it up
df::entity_position_assignment *asn = new df::entity_position_assignment;
ent->positions.assignments.push_back(asn);
asn->id = ent->positions.next_assignment_id++;
asn->position_id = pos->id;
asn->flags.extend(0x1F); // make room for 32 flags
asn->flags.set(0); // and set the first one
}
if (update || assign)
fixed++;
}
out.print("Fixed %d of %d civilizations to enable merchant nobility.\n", fixed, checked);
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"fixdiplomats", "Add Diplomat position to Elven civilizations for tree cap diplomacy.",
df_fixdiplomats, false));
commands.push_back(PluginCommand(
"fixmerchants", "Add Guild Representative position to Human civilizations for merchant nobility.",
df_fixmerchants, false));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}

@ -0,0 +1,100 @@
-- Add Elven diplomats to negotiate tree caps
--[[=begin
fix/diplomats
=============
Adds a Diplomat position to all Elven civilizations, allowing them to negotiate
tree cutting quotas - and you to violate them and start wars.
This was vanilla behaviour until ``0.31.12``, in which the "bug" was "fixed".
=end]]
function update_pos(pos, ent)
pos = df.entity_position:new()
ent.positions.own:insert('#', pos)
pos.code = "DIPLOMAT"
pos.id = ent.positions.next_position_id + 1
pos.flags.DO_NOT_CULL = true
pos.flags.MENIAL_WORK_EXEMPTION = true
pos.flags.SLEEP_PRETENSION = true
pos.flags.PUNISHMENT_EXEMPTION = true
pos.flags.ACCOUNT_EXEMPT = true
pos.flags.DUTY_BOUND = true
pos.flags.COLOR = true
pos.flags.HAS_RESPONSIBILITIES = true
pos.flags.IS_DIPLOMAT = true
pos.flags.IS_LEADER = true
-- not sure what these flags do, but the game sets them for a valid diplomat
pos.flags.unk_12 = true
pos.flags.unk_1a = true
pos.flags.unk_1b = true
pos.name[0] = "Diplomat"
pos.name[1] = "Diplomats"
pos.precedence = 70
pos.color[0] = 7
pos.color[1] = 0
pos.color[2] = 1
return pos
end
checked = 0
fixed = 0
for _,ent in pairs(df.global.world.entities.all) do
if ent.type == 0 and ent.entity_raw.flags.TREE_CAP_DIPLOMACY then
checked = checked + 1
update = true
-- see if we need to add a new position or modify an existing one
for _,pos in pairs(ent.positions.own) do
if pos.responsibilities.MAKE_INTRODUCTIONS and
pos.responsibilities.MAKE_PEACE_AGREEMENTS and
pos.responsibilities.MAKE_TOPIC_AGREEMENTS then
-- a diplomat position exists with the proper responsibilities - skip to the end
update = false
break
end
-- Diplomat position already exists, but has the wrong options - modify it instead of creating a new one
if pos.code == "DIPLOMAT" then break end
pos = nil
end
if update then
-- either there's no diplomat, or there is one and it's got the wrong responsibilities
if not pos then
pos = add_guild_rep(pos, ent)
end
-- assign responsibilities
pos.responsibilities.MAKE_INTRODUCTIONS = true
pos.responsibilities.MAKE_PEACE_AGREEMENTS = true
pos.responsibilities.MAKE_TOPIC_AGREEMENTS = true
end
-- make sure the diplomat position, whether we created it or not, is set up for proper assignment
assign = true
for _,p in pairs(ent.positions.assignments) do
if p.position_id == pos.id then -- it is - nothing more to do here
assign = false
break
end
end
if assign then -- it isn't - set it up
asn = df.entity_position_assignment:new()
ent.positions.assignments:insert('#', asn);
asn.id = ent.positions.next_assignment_id
ent.positions.next_assignment_id = asn.id + 1
asn.position_id = pos.id
asn.flags:resize(math.max(32, #asn.flags)) -- make room for 32 flags
asn.flags[0] = true -- and set the first one
end
if update or assign then
fixed = fixed + 1
end
end
end
print("Enabled tree cap diplomacy for "..fixed.." of "..checked.." civilizations.")

@ -0,0 +1,95 @@
-- Allow humans to make trade agreements
--[[=begin
fix/merchants
=============
Adds the Guild Representative position to all Human civilizations,
allowing them to make trade agreements. This was the default behaviour in
``0.28.181.40d`` and earlier.
=end]]
checked = 0
fixed = 0
function add_guild_rep(pos, ent)
-- there was no guild rep - create it
pos = df.entity_position:new()
ent.positions.own:insert('#', pos)
pos.code = "GUILD_REPRESENTATIVE"
pos.id = ent.positions.next_position_id + 1
pos.flags.DO_NOT_CULL = true
pos.flags.MENIAL_WORK_EXEMPTION = true
pos.flags.SLEEP_PRETENSION = true
pos.flags.PUNISHMENT_EXEMPTION = true
pos.flags.ACCOUNT_EXEMPT = true
pos.flags.DUTY_BOUND = true
pos.flags.COLOR = true
pos.flags.HAS_RESPONSIBILITIES = true
pos.flags.IS_DIPLOMAT = true
pos.flags.IS_LEADER = true
-- not sure what these flags do, but the game sets them for a valid guild rep
pos.flags.unk_12 = true
pos.flags.unk_1a = true
pos.flags.unk_1b = true
pos.name[0] = "Guild Representative"
pos.name[1] = "Guild Representatives"
pos.precedence = 40
pos.color[0] = 7
pos.color[1] = 0
pos.color[2] = 1
return pos
end
for _,ent in pairs(df.global.world.entities.all) do
if ent.type == 0 and ent.entity_raw.flags.MERCHANT_NOBILITY then
checked = checked + 1
update = true
-- see if we need to add a new position or modify an existing one
for _,pos in pairs(ent.positions.own) do
if pos.responsibilities.TRADE then
-- a guild rep exists with the proper responsibilities - skip to the end
update = false
break
end
-- Guild Representative position already exists, but has the wrong options - modify it instead of creating a new one
if pos.code == "GUILD_REPRESENTATIVE" then break end
pos = nil
end
if update then
-- either there's no guild rep, or there is one and it's got the wrong responsibilities
if not pos then
pos = add_guild_rep(pos, ent)
end
-- assign responsibilities
pos.responsibilities.ESTABLISH_COLONY_TRADE_AGREEMENTS = true
end
-- make sure the guild rep position, whether we created it or not, is set up for proper assignment
assign = true
for _,p in pairs(ent.positions.assignments) do
if p.position_id == pos.id then -- it is - nothing more to do here
assign = false
break
end
end
if assign then
-- it isn't - set it up
asn = df.entity_position_assignment:new()
ent.positions.assignments:insert('#', asn)
asn.id = ent.positions.next_assignment_id
ent.positions.next_assignment_id = asn.id + 1
asn.position_id = pos.id
asn.flags:resize(math.max(32, #asn.flags)) -- make room for 32 flags
asn.flags[0] = true -- and set the first one
end
if update or assign then
fixed = fixed + 1
end
end
end
print("Added merchant nobility for "..fixed.." of "..checked.." civilizations.")