Added animation and on update callback.

develop
Warmist 2014-01-02 15:19:46 +02:00
parent 94b5961372
commit b1e7356e63
1 changed files with 149 additions and 7 deletions

@ -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)
{ {