155 lines
3.4 KiB
C
155 lines
3.4 KiB
C
#include <malloc.h>
|
|
#include <string.h>
|
|
|
|
#include "log.h"
|
|
#include "lephisto.h"
|
|
#include "hook.h"
|
|
|
|
// The hook.
|
|
typedef struct Hook_ {
|
|
int id; // Unique id.
|
|
unsigned int parent; // Mission it's connected to.
|
|
char* func; // Function returned.
|
|
char* stack; // Stack it's a part of.
|
|
|
|
int delete; // Indicates it should be deleted when possible.
|
|
} Hook;
|
|
|
|
// The stack.
|
|
static unsigned int hook_id = 0; // Unique hook id.
|
|
static Hook* hook_stack = NULL;
|
|
static int hook_mstack = 0;
|
|
static int hook_nstack = 0;
|
|
static int hook_runningstack = 0; // Check if stack is running.
|
|
|
|
// Extern.
|
|
extern int misn_run(Mission* misn, char* func);
|
|
// Intern.
|
|
static int hook_run(Hook* hook);
|
|
|
|
static int hook_run(Hook* hook) {
|
|
int i;
|
|
Mission* misn;
|
|
|
|
if(hook->delete) return 0; // Hook should be deleted not run.
|
|
|
|
// Locate the mission.
|
|
for(i = 0; i < MISSION_MAX; i++)
|
|
if(player_missions[i].id == hook->parent)
|
|
break;
|
|
if(i >= MISSION_MAX) {
|
|
WARN("Trying to run hook with parent not in player mission stack!");
|
|
return -1;
|
|
}
|
|
misn = &player_missions[i];
|
|
|
|
if(misn_run(misn, hook->func))
|
|
// Error has accured.
|
|
WARN("Hook [%s] '%d' -> '%s' failed", hook->stack,
|
|
hook->id, hook->func);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Add/Remove hooks.
|
|
int hook_add(unsigned int parent, char* func, char* stack) {
|
|
Hook* new_hook;
|
|
|
|
// If the memory must grow.
|
|
if(hook_nstack+1 > hook_mstack) {
|
|
hook_mstack += 5;
|
|
hook_stack = realloc(hook_stack, hook_mstack*sizeof(Hook));
|
|
}
|
|
|
|
// Create the new hook.
|
|
new_hook = &hook_stack[hook_nstack];
|
|
new_hook->id = ++hook_id;
|
|
new_hook->parent = parent;
|
|
new_hook->func = func;
|
|
new_hook->stack = stack;
|
|
new_hook->delete = 0;
|
|
|
|
hook_nstack++;
|
|
|
|
return new_hook->id;
|
|
}
|
|
|
|
void hook_rm(int id) {
|
|
int l, m, h;
|
|
l = 0;
|
|
h = hook_nstack-1;
|
|
|
|
while(l <= h) {
|
|
m = (l+h)/2;
|
|
if(hook_stack[m].id > id) h = m-1;
|
|
else if(hook_stack[m].id < id) l = m+1;
|
|
else break;
|
|
}
|
|
|
|
if(hook_runningstack) {
|
|
hook_stack[m].delete = 1;
|
|
return;
|
|
}
|
|
|
|
// Last hook, just clip the stack.
|
|
if(m == (hook_nstack-1)) {
|
|
hook_nstack--;
|
|
return;
|
|
}
|
|
|
|
// Move it!
|
|
memmove(&hook_stack[m], &hook_stack[m], sizeof(Hook)*(hook_nstack-(m+1)));
|
|
hook_nstack--;
|
|
}
|
|
|
|
void hook_rmParent(unsigned int parent) {
|
|
int i;
|
|
for(i = 0; i < hook_nstack; i++)
|
|
if(parent == hook_stack[i].parent) {
|
|
hook_rm(hook_stack[i].id);
|
|
if(!hook_runningstack) i--;
|
|
}
|
|
}
|
|
|
|
// Run all hooks off the stack.
|
|
int hooks_run(char* stack) {
|
|
int i;
|
|
|
|
hook_runningstack = 1; // Running hooks.
|
|
for(i = 0; i < hook_nstack; i++)
|
|
if((strcmp(stack, hook_stack[i].stack)==0) && !hook_stack[i].delete) {
|
|
hook_run(&hook_stack[i]);
|
|
}
|
|
hook_runningstack = 0; // Not running hooks anymore.
|
|
|
|
for(i = 0; i < hook_nstack; i++)
|
|
if((strcmp(stack, hook_stack[i].stack)==0) && hook_stack[i].delete) {
|
|
hook_rm(hook_stack[i].id);
|
|
i--;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Run a single hook by id.
|
|
void hook_runID(int id) {
|
|
int i;
|
|
|
|
for(i = 0; i < hook_nstack; i++)
|
|
if(hook_stack[i].id == id) {
|
|
hook_run(&hook_stack[i]);
|
|
return;
|
|
}
|
|
DEBUG("Attempting to run hook of id '%d' which is not in the stack", id);
|
|
}
|
|
|
|
// Clean upi after ourselves.
|
|
void hook_cleanup(void) {
|
|
free(hook_stack);
|
|
hook_stack = NULL;
|
|
// Sane defaults just in case.
|
|
hook_nstack = 0;
|
|
hook_mstack = 0;
|
|
}
|
|
|