/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "lisp/lisp.hh"
#include "objs/miscobjs.hh"
#include "g1_object.hh"
#include "lisp/li_class.hh"
#include "objs/model_id.hh"
#include "saver.hh"
#include "objs/model_draw.hh"
#include "objs/def_object.hh"
#include "li_objref.hh"
#include "lisp/li_vect.hh"
#include "lisp/li_dialog.hh"
#include "map_man.hh"
#include "map.hh"
static li_symbol *s_model_name=0, *s_mini_object=0,
*s_offset=0, *s_position=0, *s_rotation=0,
*s_object_flags=0, *s_type_flags=0;
static li_symbol *s_ofun[G1_F_TOTAL];
//////////////////// li_def_object setup code ///////////////////////////////////////
// these flag value are assigned ot their symbol names for easy ussage in script files
static w32 g1_oflag_values[]={g1_object_class::THINKING,
g1_object_class::SELECTABLE,
g1_object_class::TARGETABLE,
g1_object_class::GROUND,
g1_object_class::UNDERWATER,
g1_object_class::AERIAL,
g1_object_class::HIT_GROUND,
g1_object_class::HIT_UNDERWATER,
g1_object_class::HIT_AERIAL,
g1_object_class::BLOCKING,
g1_object_class::DANGEROUS,
g1_object_class::CAN_DRIVE_ON
};
static char *g1_oflag_names[]={"thinking",
"selectable",
"targetable",
"ground",
"underwater",
"aerial",
"hit_ground",
"hit_underwater",
"hit_aerial",
"blocking",
"dangerous",
"can_drive_on",
0};
static char *g1_ofun_names[G1_F_TOTAL]={"think",
"damage",
"notify_damage",
"enter_range",
"draw",
"message",
"deploy_to",
"change_player_num",
"occupy_location",
"unoccupy_location"};
li_object *li_def_object(li_object *o, li_environment *env);
li_object *li_def_buildings(li_object *o, li_environment *env)
{
for (; o; o=li_cdr(o,env))
g1_create_deco_object(li_string::get(li_eval(li_car(o,env), env),env)->value());
return 0;
}
class g1_create_object_init : public i4_init_class
{
public:
void init()
{
int i=0;
for (char **a=g1_oflag_names; *a; a++)
li_set_value(*a, new li_int(g1_oflag_values[i++]));
for (i=0; i *minis;
li_type_number var_class;
w32 flags;
g1_object_def_struct()
{
name=0;
minis=0;
var_class=0;
flags=0;
}
} ;
///////////////////////////// Dynamic object code ///////////////////////////////
void g1_mini_object_def::assign_to(g1_mini_object *m)
{
m->offset=offset;
m->x=m->lx=position.x;
m->y=m->ly=position.y;
m->h=m->lh=position.z;
m->rotation=m->lrotation=rotation;
m->defmodeltype=defmodeltype;
m->frame=0;
m->animation=0;
}
g1_dynamic_object_type_class::g1_dynamic_object_type_class(li_symbol *sym)
: g1_object_definition_class(sym->name()->value()),
minis(0,1)
{
obj_flags=g1_object_class::CAN_DRIVE_ON;
var_class=0;
flags |= TO_DYNAMIC_OBJECT;
memset(&funs, 0, sizeof(funs));
}
li_object *g1_dynamic_object_class::message(li_symbol *name, li_object *params, li_environment *env)
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_MESSAGE])
{
li_class_context context(vars);
li_g1_ref _me(global_id);
li_list *p=(li_list *)params;
li_push(p, name);
li_push(p, &_me);
return t->funs[G1_F_MESSAGE](p , env);
}
return 0;
}
g1_draw_context_class *g1_draw_context;
// called when the object is on a map cell that is drawn
void g1_dynamic_object_class::draw(g1_draw_context_class *context)
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_DRAW])
{
g1_draw_context=context;
li_class_context context(vars);
li_g1_ref _me(global_id);
t->funs[G1_F_DRAW](li_make_list(&_me,0),0);
}
else
{
g1_model_draw_parameters mp;
mp.model=get_type()->model;
g1_model_draw(this, mp, context);
}
}
// void g1_dynamic_object_class::note_enter_range(g1_object_class *who, g1_fire_range_type range)
// {
// g1_dynamic_object_type_class *t=get_type();
// if (t->funs[G1_F_ENTER_RANGE])
// {
// li_class_context context(vars);
// t->funs[G1_F_ENTER_RANGE](li_make_list(new li_g1_ref(global_id),
// new li_g1_ref(who->global_id),
// new li_int(range), 0), 0);
// }
// }
void g1_dynamic_object_class::damage(g1_object_class *obj, int hp, i4_3d_vector damage_dir)
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_DAMAGE])
{
li_class_context context(vars);
t->funs[G1_F_DAMAGE](li_make_list(new li_g1_ref(global_id),
new li_g1_ref(obj->global_id),
new li_int(hp),
new li_vect(damage_dir), 0),0);
}
else
request_think();
}
void g1_dynamic_object_class::notify_damage(g1_object_class *obj, int hp, w32 notes)
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_NOTIFY_DAMAGE])
{
li_class_context context(vars);
t->funs[G1_F_NOTIFY_DAMAGE](li_make_list(new li_g1_ref(global_id),
new li_g1_ref(obj->global_id),
new li_int(hp),
new li_int(notes), 0),0);
}
else
g1_object_class::notify_damage(obj, hp);
}
void g1_dynamic_object_class::think()
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_THINK])
{
li_class_context context(vars);
t->funs[G1_F_THINK](li_make_list(new li_g1_ref(global_id), 0), 0);
}
}
static li_float_class_member dest_x("dest_x"), dest_y("dest_y");
i4_bool g1_dynamic_object_class::deploy_to(float x, float y)
{
g1_dynamic_object_type_class *t=get_type();
li_class_context context(vars);
if (t->funs[G1_F_DEPLOY_TO])
t->funs[G1_F_DEPLOY_TO](li_make_list(new li_g1_ref(global_id),
new li_float(x),
new li_float(y),0), 0);
else
{
if (vars && vars->member_offset(dest_x)!=-1)
{
dest_x()=x;
dest_y()=y;
}
}
return 0;
}
void g1_dynamic_object_class::change_player_num(int new_player)
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_CHANGE_TEAMS])
{
li_class_context context(vars);
t->funs[G1_F_CHANGE_TEAMS](li_make_list(new li_g1_ref(global_id),
new li_int(new_player), 0), 0);
}
else
g1_object_class::change_player_num(new_player);
}
i4_bool g1_dynamic_object_class::occupy_location()
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_OCCUPY_LOCATION])
{
li_class_context context(vars);
if (t->funs[G1_F_OCCUPY_LOCATION](li_make_list(new li_g1_ref(global_id),0), 0))
return i4_T;
else return i4_F;
}
else
return g1_object_class::occupy_location();
}
void g1_dynamic_object_class::unoccupy_location()
{
g1_dynamic_object_type_class *t=get_type();
if (t->funs[G1_F_UNOCCUPY_LOCATION])
{
li_class_context context(vars);
t->funs[G1_F_UNOCCUPY_LOCATION](li_make_list(new li_g1_ref(global_id), 0), 0);
}
else
g1_object_class::unoccupy_location();
}
g1_dynamic_object_class::g1_dynamic_object_class(g1_object_type type, g1_loader_class *fp)
: g1_object_class(type, fp)
{
g1_dynamic_object_type_class *dtype=get_type();
if (dtype->minis.size())
{
allocate_mini_objects(dtype->minis.size(), "");
for (int i=0; iminis.size(); i++)
dtype->minis[i].assign_to(mini_objects+i);
}
if (fp && fp->read_16()==VERSION)
{
int old_minis=fp->read_8(), i;
int old_mini_disk_size=fp->read_32();
if (old_minis==dtype->minis.size())
{
g1_mini_object *m=mini_objects;
for (i=0; iminis.size(); i++)
{
fp->read_format("fffffffff",
&m->offset.x, &m->offset.y, &m->offset.z,
&m->x, &m->y, &m->h,
&m->rotation.x, &m->rotation.y, &m->rotation.z);
}
}
else
fp->seek(fp->tell() + old_mini_disk_size);
}
flags = get_type()->obj_flags;
grab_old();
}
void g1_dynamic_object_class::save(g1_saver_class *fp)
{
g1_object_class::save(fp);
fp->write_16(VERSION);
fp->write_8(num_mini_objects);
int han=fp->mark_size();
g1_mini_object *m=mini_objects;
for (int i=0; iwrite_format("fffffffff",
&m->offset.x, &m->offset.y, &m->offset.z,
&m->x, &m->y, &m->h,
&m->rotation.x, &m->rotation.y, &m->rotation.z);
}
fp->end_mark_size(han);
}
////////////////// dynamic object type functions ///////////////////////////////
g1_object_class *g1_dynamic_object_type_class::create_object(g1_object_type type,
g1_loader_class *fp)
{
g1_object_class *o=new g1_dynamic_object_class(type, fp);
o->init();
return o;
}
static void read_vect(i4_3d_vector &v, li_object *o, li_environment *env)
{
v.x=li_get_float(li_eval(li_car(o,env), env),env); o=li_cdr(o,env);
v.y=li_get_float(li_eval(li_car(o,env), env),env); o=li_cdr(o,env);
v.z=li_get_float(li_eval(li_car(o,env), env),env);
}
static li_function_type get_function(li_object *o, li_environment *env)
{
li_object *fun=li_get_fun(li_symbol::get(o,env),env);
if (!fun)
li_error(env, "no registered function %O", o);
return li_function::get(fun,env)->value();
}
li_object *li_def_object(li_object *o, li_environment *env)
{
li_symbol *sym=li_symbol::get(li_car(o,env),env);
g1_dynamic_object_type_class *type=new g1_dynamic_object_type_class(sym);
for (li_object *l=li_cdr(o,env); l; l=li_cdr(l,env))
{
li_object *prop=li_car(l,env);
li_symbol *sym=li_symbol::get(li_car(prop,env),env);
prop=li_cdr(prop,env);
if (sym==li_get_symbol("model_name", s_model_name))
{
int id=g1_model_list_man.find_handle(li_string::get(li_car(prop,env),env)->value());
type->model=g1_model_list_man.get_model(id);
}
else if (sym==li_get_symbol("mini_object", s_mini_object))
{
g1_mini_object_def mo;
mo.init();
char *name=0;
for (;prop; prop=li_cdr(prop,env)) // prop = ((offset 0 0 0.1) (center 0 0 0) "gunport_barrel")
{
li_object *sub=li_car(prop,env);
sym=li_symbol::get(li_car(sub,env),env); sub=li_cdr(sub,env);
if (sym==li_get_symbol("offset", s_offset))
read_vect(mo.offset, sub, env);
else if (sym==li_get_symbol("position", s_position))
read_vect(mo.position, sub, env);
else if (sym==li_get_symbol("rotation", s_rotation))
read_vect(mo.rotation, sub, env);
else if (sym==li_get_symbol("model_name", s_model_name))
{
char *n=li_string::get(li_eval(li_car(sub,env), env),env)->value();
mo.defmodeltype=g1_model_list_man.find_handle(n);
}
else li_error(env,"%O should be (offset/position/rotation x y z)",sym);
}
type->minis.add(mo);
}
else if (sym==li_get_symbol("object_flags", s_object_flags))
{
for (;prop; prop=li_cdr(prop,env))
type->obj_flags |= li_int::get(li_eval(li_car(prop,env),env),env)->value();
}
else if (sym==li_get_symbol("type_flags", s_type_flags))
{
for (;prop; prop=li_cdr(prop,env))
type->flags |= li_int::get(li_eval(li_car(prop,env),env),env)->value();
}
else
{
int found=0;
for (int i=0; ifuns[i]=get_function(li_car(prop,env),env);
found=1;
}
if (!found)
li_error(env,"unknown object property %O", sym);
}
}
// if functions were not filled in see if we can find defaults
for (int i=0; ifuns[i]==0)
{
char buf[200];
sprintf(buf, "%s_%s", type->name(), g1_ofun_names[i]);
li_symbol *sym=li_find_symbol(buf);
if (sym)
{
li_function *fun=li_function::get(sym->fun(), env);
if (fun)
type->funs[i]=li_function::get(fun, env)->value();
}
}
type->flags|=g1_object_definition_class::DELETE_WITH_LEVEL;
return 0;
}