#include "timage.hpp" #include "objects.hpp" #include "chars.hpp" #include "game.hpp" #include "intsect.hpp" #include "ability.hpp" #include "lisp.hpp" #include "jrand.hpp" #include "light.hpp" #include "dprint.hpp" #include "clisp.hpp" #include "lisp_gc.hpp" #include "profile.hpp" #ifdef SCADALISP #define LCAR(x) CAR(x) #define LCDR(x) CDR(x) #else #define LCAR(x) (x)->car #define LCDR(x) (x)->cdr #endif /* SCADALISP */ char **object_names; int total_objects; game_object *current_object; view *current_view; game_object *game_object::copy() { game_object *o=create(otype,x,y); o->state=state; int i=0; for (;iset_var(i,get_var(i)); memcpy(o->lvars,lvars,4*figures[otype]->tv); for (i=0;iadd_object(get_object(i)); for (i=0;iadd_light(get_light(i)); return o; } int simple_object::total_vars() { return TOTAL_OBJECT_VARS; } obj_desc object_descriptions[TOTAL_OBJECT_VARS]={ {"fade_dir", RC_C }, {"frame_dir", RC_C }, {"direction", RC_C }, {"gravity_on", RC_C }, {"fade_count", RC_C }, {"fade_max", RC_C }, {"active", RC_C }, {"flags", RC_C }, {"aitype", RC_C }, {"xvel", RC_L }, {"fxvel", RC_C }, {"yvel", RC_L }, {"fyvel", RC_C }, {"xacel", RC_L }, {"fxacel", RC_C }, {"yacel", RC_L }, {"fyacel", RC_C }, {"x", RC_L }, {"fx", RC_C }, {"y", RC_L }, {"fy", RC_C }, {"hp", RC_S }, {"mp", RC_S }, {"fmp", RC_S }, {"cur_frame", RC_S }, {"aistate", RC_S }, {"aistate_time", RC_S }, {"targetable", RC_C } }; long game_object::get_var_by_name(char *name, int &error) { error=0; int i=0; for (;itiv;i++) { if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name)) { return lvars[figures[otype]->var_index[i]]; /* lisp_object_var *cobj=(lisp_object_var *)symbol_value(figures[otype]->vars[i]); character_type *t=figures[otype]; int number=cobj->number; if (t->tiv<=number || !t->vars[number]) { lbreak("access : variable does not exsist for this class\n"); return 0; } return lvars[t->var_index[number]];*/ } } error=1; return 0; } int game_object::set_var_by_name(char *name, long value) { int i=0; for (;itiv;i++) if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name)) { lvars[figures[otype]->var_index[i]]=value; return 1; } return 0; } char *simple_object::var_name(int x) { return object_descriptions[x].name; } int simple_object::var_type(int x) { return object_descriptions[x].type; } void simple_object::set_var(int xx, ulong v) { switch (xx) { case 0 : set_fade_dir(v); break; case 1 : set_frame_dir(v); break; case 2 : direction=v; break; case 3 : set_gravity(v); break; case 4 : set_fade_count(v); break; case 5 : set_fade_max(v); break; case 6 : active=v;break; case 7 : set_flags(v); break; case 8 : set_aitype(v); break; case 9 : set_xvel(v); break; case 10 : set_fxvel(v); break; case 11 : set_yvel(v); break; case 12 : set_fyvel(v); break; case 13 : set_xacel(v); break; case 14 : set_fxacel(v); break; case 15 : set_yacel(v); break; case 16 : set_fyacel(v); break; case 17 : x=v; break; case 18 : set_fx(v); break; case 19 : y=v; break; case 20 : set_fy(v); break; case 21 : set_hp(v); break; case 22 : set_mp(v); break; case 23 : set_fmp(v); break; case 24 : current_frame=v; break; case 25 : set_aistate(v); break; case 26 : set_aistate_time(v); break; case 27 : set_targetable(v); break; } } long simple_object::get_var(int xx) { switch (xx) { case 0 : return fade_dir(); break; case 1 : return frame_dir(); break; case 2 : return direction; break; case 3 : return gravity(); break; case 4 : return fade_count(); break; case 5 : return fade_max(); break; case 6 : return active; break; case 7 : return flags(); break; case 8 : return aitype(); break; case 9 : return xvel(); break; case 10 : return fxvel(); break; case 11 : return yvel(); break; case 12 : return fyvel(); break; case 13 : return xacel(); break; case 14 : return fxacel(); break; case 15 : return yacel(); break; case 16 : return fyacel(); break; case 17 : return x; break; case 18 : return fx(); break; case 19 : return y; break; case 20 : return fy(); break; case 21 : return hp(); break; case 22 : return mp(); break; case 23 : return fmp(); break; case 24 : return current_frame; break; case 25 : return aistate(); break; case 26 : return aistate_time(); break; case 27 : return targetable(); } return 0; } int RC_type_size(int type) { switch (type) { case RC_C : { return 1; } break; case RC_S : { return 2; } break; case RC_L : { return 4; } break; } CHECK(0); return 1; } void game_object::reload_notify() { void *ns=figures[otype]->get_fun(OFUN_RELOAD); if (ns) { game_object *o=current_object; current_object=this; void *m=mark_heap(TMP_SPACE); eval_function((lisp_symbol *)ns,NULL); restore_heap(m,TMP_SPACE); current_object=o; } } void game_object::next_sequence() { void *ns=figures[otype]->get_fun(OFUN_NEXT_STATE); if (ns) { current_object=this; void *m=mark_heap(TMP_SPACE); void *ret=eval_function((lisp_symbol *)ns,NULL); restore_heap(m,TMP_SPACE); } else { switch (state) { case dieing : { set_state(dead); } break; case end_run_jump : { set_state(running); } break; case dead : case run_jump : case run_jump_fall : case running : { set_state(state); } break; case start_run_jump : { set_yvel(get_ability(type(),jump_yvel)); if (xvel()>0) set_xvel(get_ability(type(),jump_xvel)); else if (xvel()<0) set_xvel(-get_ability(type(),jump_xvel)); set_xacel(0); set_fxacel(0); set_gravity(1); set_state(run_jump); } break; case flinch_up : case flinch_down : { if (gravity()) { if (has_sequence(end_run_jump)) set_state(end_run_jump); else set_state(stopped); } else set_state(stopped); } break; default : { set_state(stopped); } break; } } } game_object::~game_object() { if (lvars) jfree(lvars); clean_up(); } void game_object::add_power(int amount) { int max_power=lnumber_value(symbol_value(l_max_power)); int n=mp()+amount; if (n<0) n=0; if (n>max_power) n=max_power; set_mp(n); } void game_object::add_hp(int amount) { if (controller() && controller()->god) return ; int max_hp=lnumber_value(symbol_value(l_max_hp)); int n=hp()+amount; if (n<0) n=0; if (n>max_hp) n=max_hp; set_hp(n); } int game_object::can_morph_into(int type) { if (type!=otype && mp()>=figures[type]->morph_power) return 1; else return 0; } void game_object::morph_into(int type, void (*stat_fun)(int), int anneal, int frames) { set_morph_status(new morph_char(this,type,stat_fun,anneal,frames)); otype=type; set_state(stopped); } void game_object::draw_above(view *v) { long x1,y1,x2,y2,sy1,sy2,sx,i; picture_space(x1,y1,x2,y2); the_game->game_to_mouse(x1,y1,v,sx,sy2); if (sy2>=v->cy1) { long draw_to=y1-(sy2-v->cy1),tmp=x; current_level->foreground_intersect(x,y1,tmp,draw_to); the_game->game_to_mouse(x1,draw_to,v,i,sy1); // calculate sy1 sy1=max(v->cy1,sy1); sy2=min(v->cy2,sy2); trans_image *p=picture(); for (i=sy1;i<=sy2;i++) p->put_scan_line(screen,sx,i,0); } } int game_object::push_range() { return get_ability(otype,push_xrange); } int game_object::decide() { if (figures[otype]->get_fun(OFUN_AI)) { int old_aistate; old_aistate=aistate(); current_object=this; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; Cell *ret=(Cell *)eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_AI),NULL); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); if (keep_ai_info()) { if (aistate()!=old_aistate) set_aistate_time(0); else set_aistate_time(aistate_time()+1); } if (!NILP(ret)) return 1; else return 0; } else move(0,0,0); return 1; } int game_object::can_hurt(game_object *who) // collision checking will ask first to see if you { int is_attacker=current_level->is_attacker(this); // it's you against them! Damage only if it you are attacking or they are attacking you // I.E. don't let them hurt themselves, this can change if you over-ride this virtual function if (who->hurtable() && (is_attacker || current_level->is_attacker(who) || hurt_all())) return 1; else return 0; } void game_object::note_attack(game_object *whom) { return ; // nevermind } void game_object::do_flinch(game_object *from) { if (jrandom(2) && has_sequence(flinch_down)) set_state(flinch_down); else if (has_sequence(flinch_up)) set_state(flinch_up); } void game_object::do_damage(int amount, game_object *from, long hitx, long hity, long push_xvel, long push_yvel) { void *d=figures[otype]->get_fun(OFUN_DAMAGE); if (d) { void *am, *frm, *hx, *hy, *px, *py; game_object *o=current_object; current_object=this; void *m=mark_heap(TMP_SPACE); am=new_cons_cell(); l_ptr_stack.push(&am); ((cons_cell *)am)->car=new_lisp_number(amount); frm=new_cons_cell(); l_ptr_stack.push(&frm); ((cons_cell *)frm)->car=new_lisp_pointer(from); hx=new_cons_cell(); l_ptr_stack.push(&hx); ((cons_cell *)hx)->car=new_lisp_number(hitx); hy=new_cons_cell(); l_ptr_stack.push(&hy); ((cons_cell *)hy)->car=new_lisp_number(hity); px=new_cons_cell(); l_ptr_stack.push(&px); ((cons_cell *)px)->car=new_lisp_number(push_xvel); py=new_cons_cell(); l_ptr_stack.push(&py); ((cons_cell *)py)->car=new_lisp_number(push_yvel); ((cons_cell *)am)->cdr=frm; ((cons_cell *)frm)->cdr=hx; ((cons_cell *)hx)->cdr=hy; ((cons_cell *)hy)->cdr=px; ((cons_cell *)px)->cdr=py; time_marker *prof1; if (profiling()) prof1=new time_marker; eval_user_fun((lisp_symbol *)d,am); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } l_ptr_stack.pop(6); restore_heap(m,TMP_SPACE); current_object=o; } else damage_fun(amount,from,hitx,hity,push_xvel,push_yvel); #ifdef SCADALISP ENDLOCAL(); #endif } void game_object::damage_fun(int amount, game_object *from, long hitx, long hity, long push_xvel, long push_yvel) { if (!hurtable() || !alive()) return ; add_hp(-amount); set_flags(flags()|FLAG_JUST_HIT); do_flinch(from); set_xvel(xvel()+push_xvel); if (push_yvel<0 && !gravity()) set_gravity(1); set_yvel(yvel()+push_yvel); view *c=controller(); if (c && hp()<=0) { view *v=from->controller(); if (v) v->kills++; // attack from another player? else if (from->total_objects()>0) { v=from->get_object(0)->controller(); // weapon from another player? if (v && v!=c) v->kills++; else { v=c; // sucide if (v) v->kills--; } } } } int game_object::facing_attacker(int attackerx) { return ((attackerx=x && direction>0)); } void game_object::picture_space(long &x1, long &y1,long &x2, long &y2) { int xc=x_center(),w=picture()->width(),h=picture()->height(); if (direction>0) x1=x-xc; else x1=x-(w-xc-1); x2=x1+w-1; y1=y-h+1; y2=y; } int game_object::next_picture() { int ret=1; if (frame_dir()>0) { if (!current_sequence()->next_frame(current_frame)) { next_sequence(); ret=0; } } else { if (!current_sequence()->last_frame(current_frame)) { next_sequence(); ret=0; } } frame_advance(); return ret; } long game_object::x_center() { return current_sequence()->x_center(current_frame); } void game_object::draw() { if (figures[otype]->get_fun(OFUN_DRAW)) { current_object=this; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_DRAW),NULL); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); } else drawer(); } void game_object::map_draw() { if (figures[otype]->get_fun(OFUN_MAP_DRAW)) { current_object=this; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MAP_DRAW),NULL); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); } } void game_object::draw_trans(int count, int max) { trans_image *cpict=picture(); cpict->put_fade(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd, count,max, color_table,the_game->current_palette()); } void game_object::draw_tint(int tint_id) { trans_image *cpict=picture(); if (fade_count()) cpict->put_fade_tint(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd, fade_count(),fade_max(), cash.ctint(tint_id)->data, color_table,the_game->current_palette()); else cpict->put_remaped(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd, cash.ctint(tint_id)->data); } void game_object::draw_double_tint(int tint_id, int tint2) { trans_image *cpict=picture(); if (fade_count()) cpict->put_fade_tint(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd, fade_count(),fade_max(), cash.ctint(tint_id)->data, color_table,the_game->current_palette()); else cpict->put_double_remaped(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd, cash.ctint(tint_id)->data, cash.ctint(tint2)->data); } void game_object::draw_predator() { trans_image *cpict=picture(); cpict->put_predator(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd); } void game_object::drawer() { trans_image *cpict; if (morph_status()) { morph_status()->draw(this,current_view); if (morph_status()->frames_left()<1) set_morph_status(NULL); } else { view *v=controller(); if (fade_count()) draw_trans(fade_count(),fade_max()); else { trans_image *cpict=picture(); cpict->put_image(screen, (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd, y-cpict->height()+1-current_vyadd); } } } game_object *game_object::try_move(long x, long y, long &xv, long &yv, int checks) { if (xv || yv) // make sure they are suggesting movement { game_object *who1=NULL,*who2=NULL; // who did we intersect? long x2,y2,h; if (checks&1) { x2=x+xv; y2=y+yv; if (xv==0) current_level->vforeground_intersect(x,y,y2); else current_level->foreground_intersect(x,y,x2,y2); if (!stoppable()) who1=current_level->boundary_setback(this,x,y,x2,y2); else who1=current_level->all_boundary_setback(this,x,y,x2,y2); xv=x2-x; yv=y2-y; } if (checks&2) { h=picture()->height(); x2=x+xv; y2=y-h+1+yv; if (xv==0) current_level->vforeground_intersect(x,y-h+1,y2); else current_level->foreground_intersect(x,y-h+1,x2,y2); if (!stoppable()) who2=current_level->all_boundary_setback(this,x,y-h+1,x2,y2); else who2=current_level->boundary_setback(this,x,y-h+1,x2,y2); xv=x2-x; yv=y2-y+h-1; } if (who2) return who2; else return who1; } else return NULL; } void *game_object::float_tick() // returns 1 if you hit something, 0 otherwise { long ret=0; if (hp()<=0) { if (state!=dead) { set_xacel(0); set_fxacel(0); if (has_sequence(dieing)) { if (state!=dieing) { set_state(dieing); set_xvel(0); } } else { set_xvel(0); set_fxvel(0); if (has_sequence(dead)) set_state(dead); else return 0; } } } long fxv=sfxvel()+sfxacel(),fyv=sfyvel()+sfyacel(); long xv=xvel()+xacel()+(fxv>>8),yv=yvel()+yacel()+(fyv>>8); if (xv!=xvel() || yv!=yvel()) // only store vel's if changed so we don't increase object size { set_xvel(xv); set_yvel(yv); } if (fxv!=sfxvel() || fyv!=sfyvel()) { set_fxvel(fxv&0xff); set_fyvel(fyv&0xff); } if (fxv || fyv || xv || yv) // don't even try if there is no velocity { long nx=x,ny=y; long ffx=fx()+sfxvel(),ffy=fy()+sfyvel(); long nxv=xvel()+(ffx>>8); long nyv=yvel()+(ffy>>8); set_fx(ffx&0xff); set_fy(ffy&0xff); long old_nxv=nxv,old_nyv=nyv; game_object *hit_object=try_move(x,y,nxv,nyv,3); // now find out what velocity is safe to use /* if (get_cflag(CFLAG_STOPPABLE)) { game_object *r=current_level->boundary_setback(exclude,x,y,nxv,nyv,1); if (r) hit_object=r; }*/ x+=nxv; y+=nyv; if (old_nxv!=nxv || old_nyv!=nyv) { long lx=last_tile_hit_x,ly=last_tile_hit_y; stop(); if (old_nxv==0) { if (old_nyv>0) ret|=BLOCKED_DOWN; else if (old_nyv<0) ret|=BLOCKED_UP; } else if (old_nyv==0) { if (old_nxv>0) ret|=BLOCKED_RIGHT; else if (old_nxv<0) ret|=BLOCKED_LEFT; } else { long tx=(old_nxv>0 ? 1 : -1),ty=0; try_move(x,y,tx,ty,3); if (!tx) ret|=(old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT); else tx=0; ty=(old_nyv>0 ? 1 : -1); try_move(x,y,tx,ty,3); if (!ty) ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP); if (!ret) ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP) | (old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT); } void *rlist=NULL; // return list p_ref r1(rlist); if (hit_object) { push_onto_list(new_lisp_pointer(hit_object),rlist); push_onto_list(l_object,rlist); } else { push_onto_list(new_lisp_number(ly),rlist); push_onto_list(new_lisp_number(lx),rlist); push_onto_list(l_tile,rlist); } push_onto_list(new_lisp_number(ret),rlist); return rlist; } else return true_symbol; } return true_symbol; } int game_object::tick() // returns blocked status { int blocked=0; /* long xt=0,yt=2; try_move(x,y-2,xt,yt,1); // make sure we are not falling through the floor y=y-2+yt; */ if (flags()&FLAG_JUST_BLOCKED) set_flags(flags()-FLAG_JUST_BLOCKED); if (gravity() && !floating()) { int fya; if (yacel()>=0) fya=sfyacel()+200; else fya=sfyacel()-200; set_yacel(yacel()+(fya>>8)); set_fyacel(fya&255); } // first let's move the guy acording to his physics long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel(); if (xa || ya || fxa || fya) { int fxv=sfxvel(),fyv=sfyvel(); fxv+=fxa; fyv+=fya; long xv=xvel()+xa+(fxv>>8); set_xvel(xvel()+xa+(fxv>>8)); set_yvel(yvel()+ya+(fyv>>8)); set_fxvel(fxv&0xff); set_fyvel(fyv&0xff); } // check to see if this advancement causes him to collide with objects long old_vy=yvel(),old_vx=xvel(); // save the correct veloicties if (old_vx || old_vy) { int up=0; if (yvel()<=0) // if we are going up or a strait across check up and down up=2; long xv=xvel(),yv=yvel(); game_object *h=try_move(x,y,xv,yv,1|up); // now find out what velocity is safe to use set_xvel(xv); set_yvel(yv); x+=xv; y+=yv; if (h && stoppable()) return BLOCKED_LEFT|BLOCKED_RIGHT; if (xv!=old_vx || yv!=old_vy) // he collided with something { if (gravity()) // was he going up or down? { long fall_xv=0,old_fall_vy,fall_vy; old_fall_vy=fall_vy=old_vy-yvel(); // make sure he gets all of his yvel try_move(x,y,fall_xv,fall_vy,1|up); if (old_vy>0 && fall_vy0) { blocked|=BLOCKED_DOWN; if (!xvel() && has_sequence(end_run_jump)) { set_xvel(old_vx); set_state(end_run_jump); } else set_state(stopped); } else blocked|=BLOCKED_UP; if (state==run_jump_fall) { if (has_sequence(running)) set_state(running); else { stop_x(); set_state(stopped); } } else { set_yacel(0); set_fyacel(0); set_yvel(0); set_fyvel(0); set_gravity(0); } } else { if (old_vy!=0) { long testx=old_vx<0 ? -1 : 1,testy=0; // see if we were stopped left/right // or just up down try_move(x,y,testx,testy,1|up); if (testx==0) // blocked left/right, set flag { if (old_vx<0) blocked|=BLOCKED_LEFT; else blocked|=BLOCKED_RIGHT; } else if (old_vy<0) blocked|=BLOCKED_UP; else if (old_vy>0) blocked|=BLOCKED_DOWN; } else if (old_vx<0) // we can skip left/right test because player wasn't moving up/down blocked|=BLOCKED_LEFT; else blocked|=BLOCKED_RIGHT; set_xvel(0); set_fxvel(0); if (old_vy<0 && fall_vy>0) { set_yvel(yvel()+fall_vy); } else set_yvel(yvel()+fall_vy); } y+=fall_vy; } else // see if we can make him 'climb' the hill { long ox=x,oy=y; // rember orginal position in case climb doesn't work long climb_xvel=0,climb_yvel=-5; // try to move up one pixel to step over the try_move(x,y,climb_xvel,climb_yvel,3); // jutting polygon line y+=climb_yvel; climb_xvel=old_vx-xvel(); climb_yvel=-(abs(climb_xvel)); // now try 45 degree slope try_move(x,y,climb_xvel,climb_yvel,3); if (abs(climb_xvel)>0) // see if he got further by climbing { blocked=blocked&(~(BLOCKED_LEFT|BLOCKED_RIGHT)); x+=climb_xvel; y+=climb_yvel; set_xvel(xvel()+climb_xvel); set_yvel(0); set_fyvel(0); // now put him back on the ground climb_yvel=abs(climb_xvel)+5; // plus one to put him back on the ground climb_xvel=0; try_move(x,y,climb_xvel,climb_yvel,1); if (climb_yvel) y+=climb_yvel; } else { if (old_vx<0) blocked|=BLOCKED_LEFT; else blocked|=BLOCKED_RIGHT; set_state(stopped); // nope, musta hit a wall, stop the poor fella x=ox; y=oy; } } if (xvel()!=old_vx && state!=run_jump_fall && state!=end_run_jump) { set_xacel(0); set_fxacel(0); } } } if (yacel()==0 && !gravity()) // he is not falling, make sure he can't { long nvx=0,nvy=yvel()+12; // check three pixels below for ground try_move(x,y,nvx,nvy,1); if (nvy>11) // if he falls more than 2 pixels, then he falls { if (state!=run_jump_fall) // make him fall { if (has_sequence(run_jump_fall)) set_state(run_jump_fall); set_gravity(1); } } else if (nvy) // if he fells less than 3 pixels then let him descend 'hills' { y+=nvy; blocked|=BLOCKED_DOWN; } } return blocked; } void game_object::defaults() { set_state(state); if (otype!=0xffff) { int s=get_ability(otype,start_hp); if (s!=default_simple.hp()) set_hp(s); } } void game_object::frame_advance() { int ad=current_sequence()->get_advance(current_frame); if (ad && current_level) { long xv; if (direction>0) xv=ad; else xv=-ad; long yv=0; try_move(x,y,xv,yv,3); x+=xv; } } void game_object::set_state(character_state s, int frame_direction) { if (has_sequence(s)) state=s; else state=stopped; current_frame=0; if (frame_direction!=1) set_frame_dir(frame_direction); frame_advance(); } game_object *create(int type, long x, long y, int skip_constructor, int aitype) { game_object *g=new game_object(type,skip_constructor); g->x=x; g->y=y; g->last_x=x; g->last_y=y; if (aitype) g->set_aitype(aitype); if (figures[type]->get_fun(OFUN_CONSTRUCTOR) && !skip_constructor) { game_object *o=current_object; current_object=g; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; eval_function((lisp_symbol *)figures[type]->get_fun(OFUN_CONSTRUCTOR),NULL); if (profiling()) { time_marker now; profile_add_time(type,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); current_object=o; } return g; } int base_size() { return 1+ 1*8+ 2*5+ 4*7; } int game_object::size() { return base_size(); } int game_object::move(int cx, int cy, int button) { int ret=0; if (figures[otype]->get_fun(OFUN_MOVER)) // is a lisp move function defined? { void *lcx,*lcy,*lb; game_object *o=current_object; current_object=this; // make a list of the parameters, and call the lisp function lcx=new_cons_cell(); l_ptr_stack.push(&lcx); ((cons_cell *)lcx)->car=new_lisp_number(cx); lcy=new_cons_cell(); l_ptr_stack.push(&lcy); ((cons_cell *)lcy)->car=new_lisp_number(cy); lb=new_cons_cell(); l_ptr_stack.push(&lb); ((cons_cell *)lb)->car=new_lisp_number(button); ((cons_cell *)lcx)->cdr=lcy; ((cons_cell *)lcy)->cdr=lb; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; void *r=eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MOVER), (void *)lcx); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); l_ptr_stack.pop(3); if (item_type(r)!=L_NUMBER) { lprint(r); lbreak("Object %s did not return a number from it's mover function!\n" "It should return a number to indicate it's blocked status to the\n" "ai function.",object_names[otype]); } ret|=lnumber_value(r); current_object=o; } else ret|=mover(cx,cy,button); return ret; } int game_object::mover(int cx, int cy, int button) // return false if the route is blocked { if (hp()<=0) return tick(); if (flinch_state(state)) // flinching? don't move cx=cy=button=0; if (cx) // x movement suggested? { if (state==stopped) // see if started moving { if (has_sequence(running)) { if (cx>0) { direction=1; set_xvel(get_ability(type(),run_top_speed)); } else { direction=-1; set_xacel(-get_ability(type(),run_top_speed)); } set_state(running); } } else if (state==run_jump || state==run_jump_fall) { if (cx>0) { direction=1; set_xacel(get_ability(type(),start_accel)); // set the appropriate accel } else { direction=-1; set_xacel(-get_ability(type(),start_accel)); // set the appropriate accel } } else { // turn him around if he pressed the other way, he is not walking so a fast turn // is needed, don't go through the turn sequence if ((cx>0 && direction<0) || (cx<0 && direction>0)) direction=-direction; } } // not pressing left or right, so slow down or stop else if (!gravity() && state!=start_run_jump) { long stop_acel; if (xvel()<0) // he was going left { stop_acel=get_ability(type(),stop_accel); // find out how fast he can slow down if (xvel()+stop_acel>=0) // if this acceleration is enough to stop him { stop_x(); if (!gravity()) set_state(stopped); } else { set_xacel(stop_acel); } } else if (xvel()>0) { stop_acel=-get_ability(type(),stop_accel); if (xvel()+stop_acel<=0) { stop_x(); if (!gravity()) set_state(stopped); } else set_xacel(stop_acel); } else if (!gravity()) // don't stop in the air { set_xacel(0); set_fxacel(0); // Check to see if we should go to stop state if (state==running) set_state(stopped); } } /* if (state==still_jump || state==still_jump_fall || state==end_still_jump) { set_xacel(0); set_fxacel(0); if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed)); else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed)); } else if (state==run_jump || state==run_jump_fall || state==end_run_jump) { set_xacel(0); set_fxacel(0); if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed)); else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed)); } */ // see if the user said to jump if (cy<0 && !floating() && !gravity()) { set_gravity(1); set_yvel(get_ability(type(),jump_yvel)); // if (cx && has_sequence(run_jump)) set_state(run_jump); if (xvel()!=0) if (direction>0) set_xvel(get_ability(type(),jump_top_speed)); else set_xvel(-get_ability(type(),jump_top_speed)); set_xacel(0); /* if (state==stopped) { if (cx && has_sequence(start_run_jump)) set_state(start_run_jump); else if (has_sequence(start_still_jump)) set_state(start_still_jump); else { } } else if (state==running && has_sequence(run_jump)) { set_state(run_jump); set_yvel(get_ability(type(),jump_yvel)); set_gravity(1); } else if (state==walking || state==turn_around) // if walking check to see if has a { if (has_sequence(start_still_jump)) set_state(start_still_jump); else { set_yvel(get_ability(type(),jump_yvel)); set_gravity(1); if (has_sequence(run_jump)) set_state(run_jump); } } */ } if (state==run_jump && yvel()>0) set_state(run_jump_fall); // if (state!=end_still_jump && state!=end_run_jump) { if (cx>0) set_xacel(get_ability(type(),start_accel)); else if (cx<0) set_xacel(-get_ability(type(),start_accel)); } // make sure they are not going faster than their maximum speed int top_speed; if (state==stopped || state==end_run_jump) top_speed=get_ability(type(),walk_top_speed); else if (state==running) top_speed=get_ability(type(),run_top_speed); else if (state==run_jump || state==run_jump_fall || state==start_run_jump) { top_speed=get_ability(type(),jump_top_speed); if (!cx) top_speed=0; } else top_speed=1000; if (abs(xvel()+xacel())>top_speed) { if (xacel()<0) set_xacel(-top_speed-xvel()); else set_xacel(top_speed-xvel()); } character_state old_state=state; int old_frame=current_frame; int tick_stat=tick(); // if he started to jump and slammed into a wall then make sure he stays in this state // so he can finish the jump if (!tick_stat && (old_state==start_run_jump)) { set_state(old_state); current_frame=old_frame; next_picture(); } return tick_stat; } game_object *game_object::bmove(int &whit, game_object *exclude) { // first let's move the guy acording to his physics long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel(); if (xa || ya || fxa || fya) { int fxv=sfxvel(),fyv=sfyvel(); fxv+=fxa; fyv+=fya; long xv=xvel()+xa+(fxv>>8); set_xvel(xvel()+xa+(fxv>>8)); set_yvel(yvel()+ya+(fyv>>8)); set_fxvel(fxv&0xff); set_fyvel(fyv&0xff); } long ox2,oy2; long nx=x+xvel(),nfx=fx()+fxvel(),ny=y+yvel(),nfy=fy()+fyvel(); nx+=nfx>>8; ny+=nfy>>8; // check to see if this advancement causes him to collide with objects ox2=nx; oy2=ny; // save the correct veloicties if (nx==x) current_level->vforeground_intersect(x,y,ny); else current_level->foreground_intersect(x,y,nx,ny); // first see how far we can travel game_object *ret=current_level->all_boundary_setback(exclude,x,y,nx,ny); x=nx; y=ny; set_fx(nfx&0xff); set_fy(nfy&0xff); if (ret) { if (!ret->hurtable()) // object is not hurtable, return as if hit wall. { whit=1; return NULL; } else return ret; } else { whit=(nx!=ox2 || ny!=oy2); return NULL; } } int object_to_number_in_list(game_object *who, object_node *list) { int x=1; while (list) { if (who==list->me) return x; else list=list->next; x++; } return 0; } game_object *number_to_object_in_list(long x, object_node *list) { if (!x) return NULL; x--; while (x && list) { list=list->next; x--; } if (list) return list->me; else return NULL; } void delete_object_list(object_node *first) { while (first) { object_node *n=first; first=first->next; delete n; } } long object_list_length(object_node *list) { long x=0; while (list) { list=list->next; x++; } return x; } game_object::game_object(int Type, int load) { if (Type<0xffff) { int t=figures[Type]->tv; if (t) { lvars=(long *)jmalloc(t*4,"object vars"); memset(lvars,0,t*4); } else lvars=NULL; } else lvars=NULL; otype=Type; if (!load) defaults(); } int game_object::reduced_state() { long x=0; for (int i=0;its;i++) { if (i==state) return x; else if (figures[otype]->seq[i]) x++; } return 0; } void game_object::change_aitype(int new_type) { set_aitype(new_type); if (otype<0xffff) { void *f=figures[otype]->get_fun(OFUN_CHANGE_TYPE); if (f) { game_object *o=current_object; current_object=(game_object *)this; time_marker *prof1; if (profiling()) prof1=new time_marker; eval_user_fun((lisp_symbol *)f,NULL); if (profiling()) { time_marker now; profile_add_time(this->otype,now.diff_time(prof1)); delete prof1; } current_object=o; } } } void game_object::change_type(int new_type) { if (lvars) jfree(lvars); // free old variable if (otype<0xffff) { int t=figures[new_type]->tv; if (t) { lvars=(long *)jmalloc(t*4,"object vars"); memset(lvars,0,t*4); } else lvars=NULL; } else return; otype=new_type; if (figures[new_type]->get_fun(OFUN_CONSTRUCTOR)) { game_object *o=current_object; current_object=this; void *m=mark_heap(TMP_SPACE); time_marker *prof1; if (profiling()) prof1=new time_marker; eval_function((lisp_symbol *)figures[new_type]->get_fun(OFUN_CONSTRUCTOR),NULL); if (profiling()) { time_marker now; profile_add_time(otype,now.diff_time(prof1)); delete prof1; } restore_heap(m,TMP_SPACE); current_object=o; } }