|
|
@ -18,6 +18,7 @@
|
|
|
|
#include "df/buildings_other_id.h"
|
|
|
|
#include "df/buildings_other_id.h"
|
|
|
|
#include "df/coord.h"
|
|
|
|
#include "df/coord.h"
|
|
|
|
#include "df/tile_building_occ.h"
|
|
|
|
#include "df/tile_building_occ.h"
|
|
|
|
|
|
|
|
#include "df/building_drawbuffer.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
|
@ -26,6 +27,13 @@ using namespace df::enums;
|
|
|
|
using df::global::world;
|
|
|
|
using df::global::world;
|
|
|
|
|
|
|
|
|
|
|
|
DFHACK_PLUGIN("building-hacks");
|
|
|
|
DFHACK_PLUGIN("building-hacks");
|
|
|
|
|
|
|
|
struct graphic_tile //could do just 31x31 and be done, but it's nicer to have flexible imho.
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int16_t tile; //originally uint8_t but we need to indicate non-animated tiles
|
|
|
|
|
|
|
|
int8_t fore;
|
|
|
|
|
|
|
|
int8_t back;
|
|
|
|
|
|
|
|
int8_t bright;
|
|
|
|
|
|
|
|
};
|
|
|
|
struct workshop_hack_data
|
|
|
|
struct workshop_hack_data
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int32_t myType;
|
|
|
|
int32_t myType;
|
|
|
@ -33,13 +41,22 @@ struct workshop_hack_data
|
|
|
|
df::machine_tile_set connections;
|
|
|
|
df::machine_tile_set connections;
|
|
|
|
df::power_info powerInfo;
|
|
|
|
df::power_info powerInfo;
|
|
|
|
//animation
|
|
|
|
//animation
|
|
|
|
std::vector<std::vector<int> > frames;
|
|
|
|
std::vector<std::vector<graphic_tile> > frames;
|
|
|
|
bool machine_timing; //with machine timing only 4 frames are possible
|
|
|
|
bool machine_timing; //6 frames used in vanilla
|
|
|
|
|
|
|
|
int frame_skip; // e.g. 2 means have to ticks between frames
|
|
|
|
|
|
|
|
//updateCallback:
|
|
|
|
|
|
|
|
int skip_updates;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
typedef std::map<int32_t,workshop_hack_data> workshops_data_t;
|
|
|
|
typedef std::map<int32_t,workshop_hack_data> workshops_data_t;
|
|
|
|
workshops_data_t hacked_workshops;
|
|
|
|
workshops_data_t hacked_workshops;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_update_action(color_ostream &out,df::building_workshopst*){};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DEFINE_LUA_EVENT_1(onUpdateAction,handle_update_action,df::building_workshopst*);
|
|
|
|
|
|
|
|
DFHACK_PLUGIN_LUA_EVENTS {
|
|
|
|
|
|
|
|
DFHACK_LUA_EVENT(onUpdateAction),
|
|
|
|
|
|
|
|
DFHACK_LUA_END
|
|
|
|
|
|
|
|
};
|
|
|
|
struct work_hook : df::building_workshopst{
|
|
|
|
struct work_hook : df::building_workshopst{
|
|
|
|
typedef df::building_workshopst interpose_base;
|
|
|
|
typedef df::building_workshopst interpose_base;
|
|
|
|
|
|
|
|
|
|
|
@ -53,6 +70,10 @@ struct work_hook : df::building_workshopst{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool is_fully_built()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return getBuildStage() >= getMaxBuildStage();
|
|
|
|
|
|
|
|
}
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(uint32_t,getImpassableOccupancy,())
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(uint32_t,getImpassableOccupancy,())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(find_def())
|
|
|
|
if(find_def())
|
|
|
@ -137,6 +158,8 @@ struct work_hook : df::building_workshopst{
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (auto def = find_def())
|
|
|
|
if (auto def = find_def())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(def->powerInfo.consumed==0)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
if(machine.machine_id==-1)
|
|
|
|
if(machine.machine_id==-1)
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
df::machine* target_machine=df::machine::find(machine.machine_id);
|
|
|
|
df::machine* target_machine=df::machine::find(machine.machine_id);
|
|
|
@ -147,6 +170,65 @@ struct work_hook : df::building_workshopst{
|
|
|
|
|
|
|
|
|
|
|
|
return INTERPOSE_NEXT(isUnpowered)();
|
|
|
|
return INTERPOSE_NEXT(isUnpowered)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(void, updateAction, ())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(auto def = find_def())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(def->skip_updates!=0 && is_fully_built())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
df::world* world = df::global::world;
|
|
|
|
|
|
|
|
if(world->frame_counter % def->skip_updates == 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
CoreSuspendClaimer suspend;
|
|
|
|
|
|
|
|
color_ostream_proxy out(Core::getInstance().getConsole());
|
|
|
|
|
|
|
|
onUpdateAction(out,this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERPOSE_NEXT(updateAction)();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_VMETHOD_INTERPOSE(void, drawBuilding, (df::building_drawbuffer *db, int16_t unk))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
INTERPOSE_NEXT(drawBuilding)(db, unk);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (auto def = find_def())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!is_fully_built() || def->frames.size()==0)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
int frame=0;
|
|
|
|
|
|
|
|
if(!def->machine_timing)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int frame_mod=def->frames.size()* def->frame_skip;
|
|
|
|
|
|
|
|
df::world* world = df::global::world;
|
|
|
|
|
|
|
|
frame=(world->frame_counter % frame_mod)/def->frame_skip;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(machine.machine_id!=-1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
df::machine* target_machine=df::machine::find(machine.machine_id);
|
|
|
|
|
|
|
|
if(target_machine)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
frame=target_machine->visual_phase % def->frames.size();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int w=db->x2-db->x1;
|
|
|
|
|
|
|
|
std::vector<graphic_tile> &cur_frame=def->frames[frame];
|
|
|
|
|
|
|
|
for(int i=0;i<cur_frame.size();i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(cur_frame[i].tile>=0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int tx=i % w;
|
|
|
|
|
|
|
|
int ty=i / w;
|
|
|
|
|
|
|
|
db->tile[tx][ty]=cur_frame[i].tile;
|
|
|
|
|
|
|
|
db->back[tx][ty]=cur_frame[i].back;
|
|
|
|
|
|
|
|
db->bright[tx][ty]=cur_frame[i].bright;
|
|
|
|
|
|
|
|
db->fore[tx][ty]=cur_frame[i].fore;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, getImpassableOccupancy);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, getImpassableOccupancy);
|
|
|
|
|
|
|
|
|
|
|
@ -157,21 +239,63 @@ IMPLEMENT_VMETHOD_INTERPOSE(work_hook, categorize);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, uncategorize);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, uncategorize);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, canConnectToMachine);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, canConnectToMachine);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, isUnpowered);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, isUnpowered);
|
|
|
|
//IMPLEMENT_VMETHOD_INTERPOSE(work_hook, updateAction);
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, updateAction);
|
|
|
|
// todo animations...
|
|
|
|
IMPLEMENT_VMETHOD_INTERPOSE(work_hook, drawBuilding);
|
|
|
|
//IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, drawBuilding);
|
|
|
|
|
|
|
|
void clear_mapping()
|
|
|
|
void clear_mapping()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
hacked_workshops.clear();
|
|
|
|
hacked_workshops.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//arguments: custom type, consumed power, produced power, list of connection points.
|
|
|
|
static void loadFrames(lua_State* L,workshop_hack_data& def,int stack_pos)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
luaL_checktype(L,stack_pos,LUA_TTABLE);
|
|
|
|
|
|
|
|
lua_pushvalue(L,stack_pos);
|
|
|
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
|
|
|
while (lua_next(L, -2) != 0) {
|
|
|
|
|
|
|
|
luaL_checktype(L,-1,LUA_TTABLE);
|
|
|
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
|
|
|
std::vector<graphic_tile> frame;
|
|
|
|
|
|
|
|
while (lua_next(L, -2) != 0) {
|
|
|
|
|
|
|
|
graphic_tile t;
|
|
|
|
|
|
|
|
lua_pushnumber(L,1);
|
|
|
|
|
|
|
|
lua_gettable(L,-2);
|
|
|
|
|
|
|
|
t.tile=lua_tonumber(L,-1);
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lua_pushnumber(L,2);
|
|
|
|
|
|
|
|
lua_gettable(L,-2);
|
|
|
|
|
|
|
|
t.fore=lua_tonumber(L,-1);
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lua_pushnumber(L,3);
|
|
|
|
|
|
|
|
lua_gettable(L,-2);
|
|
|
|
|
|
|
|
t.back=lua_tonumber(L,-1);
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lua_pushnumber(L,4);
|
|
|
|
|
|
|
|
lua_gettable(L,-2);
|
|
|
|
|
|
|
|
t.bright=lua_tonumber(L,-1);
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frame.push_back(t);
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
def.frames.push_back(frame);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
return ;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//arguments: custom type, consumed power, produced power, list of connection points, update skip(0/nil to disable)
|
|
|
|
|
|
|
|
// table of frames,frame to tick ratio (-1 for machine control)
|
|
|
|
static int addBuilding(lua_State* L)
|
|
|
|
static int addBuilding(lua_State* L)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
workshop_hack_data newDefinition;
|
|
|
|
workshop_hack_data newDefinition;
|
|
|
|
newDefinition.myType=luaL_checkint(L,1);
|
|
|
|
newDefinition.myType=luaL_checkint(L,1);
|
|
|
|
newDefinition.powerInfo.consumed=luaL_checkint(L,2);
|
|
|
|
newDefinition.powerInfo.consumed=luaL_checkint(L,2);
|
|
|
|
newDefinition.powerInfo.produced=luaL_checkint(L,3);
|
|
|
|
newDefinition.powerInfo.produced=luaL_checkint(L,3);
|
|
|
|
|
|
|
|
//table of machine connection points
|
|
|
|
luaL_checktype(L,4,LUA_TTABLE);
|
|
|
|
luaL_checktype(L,4,LUA_TTABLE);
|
|
|
|
|
|
|
|
lua_pushvalue(L,4);
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while (lua_next(L, -2) != 0) {
|
|
|
|
while (lua_next(L, -2) != 0) {
|
|
|
|
lua_getfield(L,-1,"x");
|
|
|
|
lua_getfield(L,-1,"x");
|
|
|
@ -183,10 +307,25 @@ static int addBuilding(lua_State* L)
|
|
|
|
|
|
|
|
|
|
|
|
newDefinition.connections.can_connect.push_back(-1);//TODO add this too...
|
|
|
|
newDefinition.connections.can_connect.push_back(-1);//TODO add this too...
|
|
|
|
newDefinition.connections.tiles.push_back(df::coord(x,y,0));
|
|
|
|
newDefinition.connections.tiles.push_back(df::coord(x,y,0));
|
|
|
|
hacked_workshops[newDefinition.myType]=newDefinition;
|
|
|
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
lua_pop(L,1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L,1);
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
|
|
|
//updates
|
|
|
|
|
|
|
|
newDefinition.skip_updates=luaL_optinteger(L,5,0);
|
|
|
|
|
|
|
|
//animation
|
|
|
|
|
|
|
|
if(!lua_isnil(L,6) && lua_gettop(L)>5)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
loadFrames(L,newDefinition,6);
|
|
|
|
|
|
|
|
newDefinition.frame_skip=luaL_optinteger(L,7,-1);
|
|
|
|
|
|
|
|
if(newDefinition.frame_skip==0)
|
|
|
|
|
|
|
|
newDefinition.frame_skip=1;
|
|
|
|
|
|
|
|
if(newDefinition.frame_skip<0)
|
|
|
|
|
|
|
|
newDefinition.machine_timing=true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
newDefinition.machine_timing=false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
hacked_workshops[newDefinition.myType]=newDefinition;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DFHACK_PLUGIN_LUA_COMMANDS{
|
|
|
|
DFHACK_PLUGIN_LUA_COMMANDS{
|
|
|
@ -204,6 +343,9 @@ static void enable_hooks(bool enable)
|
|
|
|
INTERPOSE_HOOK(work_hook,uncategorize).apply(enable);
|
|
|
|
INTERPOSE_HOOK(work_hook,uncategorize).apply(enable);
|
|
|
|
INTERPOSE_HOOK(work_hook,canConnectToMachine).apply(enable);
|
|
|
|
INTERPOSE_HOOK(work_hook,canConnectToMachine).apply(enable);
|
|
|
|
INTERPOSE_HOOK(work_hook,isUnpowered).apply(enable);
|
|
|
|
INTERPOSE_HOOK(work_hook,isUnpowered).apply(enable);
|
|
|
|
|
|
|
|
//update n render
|
|
|
|
|
|
|
|
INTERPOSE_HOOK(work_hook,updateAction).apply(enable);
|
|
|
|
|
|
|
|
INTERPOSE_HOOK(work_hook,drawBuilding).apply(enable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
|
|
|
|
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
|
|
|
|
{
|
|
|
|
{
|
|
|
|