home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ABUSESRC.ZIP / AbuseSrc / macabuse / src / objects.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-20  |  37.6 KB  |  1,645 lines

  1. #include "timage.hpp"
  2. #include "objects.hpp"
  3. #include "chars.hpp"
  4.  
  5. #include "game.hpp"
  6. #include "intsect.hpp"
  7. #include "ability.hpp"
  8. #include "lisp.hpp"
  9. #include "jrand.hpp"
  10. #include "light.hpp"
  11. #include "dprint.hpp"
  12. #include "clisp.hpp"
  13. #include "lisp_gc.hpp"
  14. #include "profile.hpp"
  15.  
  16. #ifdef SCADALISP
  17. #define LCAR(x)        CAR(x)
  18. #define LCDR(x)        CDR(x)
  19. #else
  20. #define LCAR(x)        (x)->car
  21. #define LCDR(x)        (x)->cdr
  22. #endif /* SCADALISP */
  23.  
  24. char **object_names;
  25. int total_objects;
  26. game_object *current_object;
  27. view *current_view;
  28.  
  29. game_object *game_object::copy()
  30. {
  31.   game_object *o=create(otype,x,y);
  32.   o->state=state;
  33.   int i=0;
  34.   for (;i<TOTAL_OBJECT_VARS;i++)
  35.     o->set_var(i,get_var(i));
  36.   memcpy(o->lvars,lvars,4*figures[otype]->tv);
  37.   for (i=0;i<total_objects();i++)
  38.     o->add_object(get_object(i));
  39.   for (i=0;i<total_lights();i++)
  40.     o->add_light(get_light(i));
  41.   return o;
  42. }
  43.  
  44. int simple_object::total_vars() { return TOTAL_OBJECT_VARS; }
  45.  
  46.  
  47. obj_desc object_descriptions[TOTAL_OBJECT_VARS]={
  48.                 {"fade_dir",      RC_C },
  49.                 {"frame_dir",     RC_C },
  50.                 {"direction",     RC_C },
  51.                 {"gravity_on",    RC_C },
  52.                 {"fade_count",    RC_C },
  53.  
  54.                 {"fade_max",      RC_C },
  55.                 {"active",        RC_C },
  56.                 {"flags",         RC_C },
  57.                 {"aitype",        RC_C },
  58.                 {"xvel",          RC_L },
  59.  
  60.                 {"fxvel",         RC_C },
  61.                 {"yvel",          RC_L },
  62.                 {"fyvel",         RC_C },
  63.                 {"xacel",         RC_L },
  64.                 {"fxacel",        RC_C },
  65.  
  66.                 {"yacel",         RC_L },
  67.                 {"fyacel",        RC_C },
  68.                 {"x",             RC_L },
  69.                 {"fx",            RC_C },
  70.                 {"y",             RC_L },
  71.  
  72.                 {"fy",            RC_C },
  73.                 {"hp",            RC_S },
  74.                 {"mp",            RC_S },
  75.                 {"fmp",           RC_S },
  76.                 {"cur_frame",     RC_S },
  77.  
  78.                 {"aistate",       RC_S },
  79.                 {"aistate_time",  RC_S },
  80.                 {"targetable",    RC_C }
  81.  
  82.                   };
  83.   
  84. long game_object::get_var_by_name(char *name, int &error)
  85. {
  86.   error=0;
  87.   int i=0;
  88.   for (;i<TOTAL_OBJECT_VARS;i++)
  89.   {
  90.     if (!strcmp(object_descriptions[i].name,name))
  91.       return get_var(i);
  92.   }
  93.  
  94.   for (i=0;i<figures[otype]->tiv;i++)
  95.   {
  96.     if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name))
  97.     {
  98.       return lvars[figures[otype]->var_index[i]];
  99. /*      lisp_object_var *cobj=(lisp_object_var *)symbol_value(figures[otype]->vars[i]);
  100.       character_type *t=figures[otype];
  101.       int number=cobj->number;
  102.       if (t->tiv<=number || !t->vars[number])
  103.       {
  104.     lbreak("access : variable does not exsist for this class\n");
  105.     return 0;
  106.       }
  107.       return lvars[t->var_index[number]];*/
  108.     }
  109.   }
  110.   error=1;
  111.   return 0;
  112. }
  113.  
  114. int game_object::set_var_by_name(char *name, long value)
  115. {
  116.   int i=0;
  117.   for (;i<TOTAL_OBJECT_VARS;i++)
  118.   {
  119.     if (!strcmp(object_descriptions[i].name,name))
  120.     {
  121.       set_var(i,value);
  122.       return 1;
  123.     }
  124.   }
  125.   for (i=0;i<figures[otype]->tiv;i++)
  126.     if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name))
  127.     {
  128.       lvars[figures[otype]->var_index[i]]=value;
  129.       return 1;
  130.     }
  131.   return 0;
  132. }
  133.  
  134.  
  135. char *simple_object::var_name(int x)
  136. {
  137.   return object_descriptions[x].name;
  138. }
  139.  
  140. int simple_object::var_type(int x)
  141. {
  142.   return object_descriptions[x].type;
  143. }
  144.  
  145.  
  146. void simple_object::set_var(int xx, ulong v)
  147. {
  148.   switch (xx)
  149.   {
  150.     case 0 : set_fade_dir(v); break;
  151.     case 1 : set_frame_dir(v); break;
  152.     case 2 : direction=v; break;
  153.     case 3 : set_gravity(v); break;
  154.     case 4 : set_fade_count(v); break;
  155.     case 5 : set_fade_max(v); break;
  156.     case 6 : active=v;break;
  157.     case 7 : set_flags(v); break;
  158.     case 8 : set_aitype(v); break;
  159.     case 9 : set_xvel(v); break;
  160.  
  161.     case 10 : set_fxvel(v); break;
  162.     case 11 : set_yvel(v); break;
  163.     case 12 : set_fyvel(v); break;
  164.     case 13 : set_xacel(v); break;
  165.     case 14 : set_fxacel(v); break;
  166.  
  167.     case 15 : set_yacel(v); break;
  168.     case 16 : set_fyacel(v); break;
  169.     case 17 : x=v; break;
  170.     case 18 : set_fx(v); break;
  171.     case 19 : y=v; break;
  172.  
  173.     case 20 : set_fy(v); break;
  174.     case 21 : set_hp(v); break;
  175.     case 22 : set_mp(v); break;
  176.     case 23 : set_fmp(v); break;
  177.  
  178.     case 24 : current_frame=v;  break;
  179.     case 25 : set_aistate(v); break;
  180.  
  181.     case 26 : set_aistate_time(v); break;
  182.     case 27 : set_targetable(v); break;
  183.   }
  184. }
  185.  
  186. long simple_object::get_var(int xx)
  187. {
  188.   switch (xx)
  189.   {
  190.     case 0 : return fade_dir(); break;
  191.     case 1 : return frame_dir(); break;
  192.     case 2 : return direction; break;
  193.     case 3 : return gravity(); break;
  194.     case 4 : return fade_count(); break;
  195.     case 5 : return fade_max(); break;
  196.     case 6 : return active; break;
  197.     case 7 : return flags(); break;
  198.     case 8 : return aitype(); break;
  199.     case 9 : return xvel(); break;
  200.     case 10 : return fxvel(); break;
  201.  
  202.     case 11 : return yvel(); break;
  203.     case 12 : return fyvel(); break;
  204.  
  205.     case 13 : return xacel(); break;
  206.     case 14 : return fxacel(); break;
  207.  
  208.     case 15 : return yacel(); break;
  209.     case 16 : return fyacel(); break;
  210.  
  211.     case 17 : return x; break;
  212.     case 18 : return fx(); break;
  213.  
  214.     case 19 : return y; break;
  215.     case 20 : return fy(); break;
  216.  
  217.     case 21 : return hp(); break;
  218.     case 22 : return mp(); break;
  219.     case 23 : return fmp(); break;
  220.  
  221.     case 24 : return current_frame;  break;
  222.     case 25 : return aistate(); break;
  223.     case 26 : return aistate_time(); break;
  224.     case 27 : return targetable();
  225.   }
  226.   return 0;
  227. }
  228.  
  229.  
  230.  
  231.  
  232. int RC_type_size(int type)
  233. {
  234.   switch (type)
  235.   {
  236.     case RC_C : 
  237.     { return 1; } break;
  238.     case RC_S : 
  239.     { return 2; } break;
  240.     case RC_L : 
  241.     { return 4; } break;
  242.   }        
  243.   CHECK(0);
  244.   return 1;
  245.  
  246. void game_object::reload_notify()
  247. {
  248.   void *ns=figures[otype]->get_fun(OFUN_RELOAD);  
  249.   if (ns)
  250.   {
  251.     game_object *o=current_object;
  252.     current_object=this;
  253.  
  254.     void *m=mark_heap(TMP_SPACE);
  255.     eval_function((lisp_symbol *)ns,NULL);
  256.     restore_heap(m,TMP_SPACE);
  257.  
  258.     current_object=o;
  259.   }
  260. }
  261.  
  262. void game_object::next_sequence()
  263. {
  264.   void *ns=figures[otype]->get_fun(OFUN_NEXT_STATE);
  265.   if (ns)
  266.   {  
  267.     current_object=this;
  268.     void *m=mark_heap(TMP_SPACE);
  269.     void *ret=eval_function((lisp_symbol *)ns,NULL);
  270.     restore_heap(m,TMP_SPACE);
  271.   } else
  272.   {
  273.     switch (state)
  274.     {
  275.       case dieing : 
  276.       { set_state(dead); } break;
  277.  
  278.       case end_run_jump :
  279.       {
  280.     set_state(running);
  281.       } break;
  282.       case dead :
  283.       case run_jump :
  284.       case run_jump_fall :
  285.       case running :
  286.       { set_state(state); } break;
  287.       case start_run_jump :
  288.       { 
  289.     set_yvel(get_ability(type(),jump_yvel));
  290.     if (xvel()>0)
  291.         set_xvel(get_ability(type(),jump_xvel));
  292.     else if (xvel()<0)
  293.         set_xvel(-get_ability(type(),jump_xvel));
  294.     set_xacel(0);
  295.     set_fxacel(0);
  296.     set_gravity(1);      
  297.     set_state(run_jump);
  298.       } break;
  299.  
  300.       case flinch_up :
  301.       case flinch_down :
  302.       {
  303.     if (gravity())
  304.     {
  305.       if (has_sequence(end_run_jump))
  306.         set_state(end_run_jump);
  307.       else set_state(stopped);
  308.     } else set_state(stopped);
  309.       } break;
  310.  
  311.       
  312.       default :
  313.       { set_state(stopped); } break;
  314.     }
  315.   }
  316.  
  317. }
  318.  
  319.  
  320.  
  321. game_object::~game_object()
  322. {
  323.   if (lvars) jfree(lvars);
  324.   clean_up();
  325. }
  326.  
  327. void game_object::add_power(int amount)  
  328.   int max_power=lnumber_value(symbol_value(l_max_power));  
  329.   int n=mp()+amount;
  330.   if (n<0) n=0;
  331.   if (n>max_power) n=max_power;
  332.   set_mp(n);
  333. }
  334.  
  335. void game_object::add_hp(int amount)
  336. {
  337.   if (controller() && controller()->god) return ;
  338.   int max_hp=lnumber_value(symbol_value(l_max_hp));  
  339.   int n=hp()+amount;
  340.   if (n<0) n=0;
  341.   if (n>max_hp)
  342.     n=max_hp;
  343.   set_hp(n);
  344. }
  345.  
  346. int game_object::can_morph_into(int type)
  347. {
  348.   if (type!=otype && mp()>=figures[type]->morph_power)
  349.     return 1;
  350.   else return 0;
  351. }
  352.  
  353. void game_object::morph_into(int type, void (*stat_fun)(int), int anneal, int frames)
  354. {
  355.   set_morph_status(new morph_char(this,type,stat_fun,anneal,frames));
  356.   otype=type;
  357.   set_state(stopped);
  358. }
  359.  
  360. void game_object::draw_above(view *v)
  361. {
  362.   long x1,y1,x2,y2,sy1,sy2,sx,i;
  363.   picture_space(x1,y1,x2,y2);    
  364.  
  365.   the_game->game_to_mouse(x1,y1,v,sx,sy2);
  366.   if (sy2>=v->cy1)
  367.   {
  368.     long draw_to=y1-(sy2-v->cy1),tmp=x;
  369.     current_level->foreground_intersect(x,y1,tmp,draw_to);     
  370.     the_game->game_to_mouse(x1,draw_to,v,i,sy1);     // calculate sy1
  371.  
  372.     sy1=max(v->cy1,sy1);
  373.     sy2=min(v->cy2,sy2);
  374.     trans_image *p=picture();
  375.     
  376.     for (i=sy1;i<=sy2;i++)
  377.       p->put_scan_line(screen,sx,i,0);  
  378.   }  
  379. }
  380.  
  381. int game_object::push_range()
  382. {
  383.   return get_ability(otype,push_xrange);
  384. }
  385.  
  386. int game_object::decide()
  387. {
  388.   if (figures[otype]->get_fun(OFUN_AI))
  389.   {
  390.     int old_aistate;
  391.     old_aistate=aistate();
  392.  
  393.     current_object=this;
  394.     void *m=mark_heap(TMP_SPACE);
  395.  
  396.     time_marker *prof1;
  397.     if (profiling())
  398.       prof1=new time_marker;
  399.  
  400.     Cell *ret=(Cell *)eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_AI),NULL);
  401.     if (profiling())
  402.     {
  403.       time_marker now;
  404.       profile_add_time(this->otype,now.diff_time(prof1));
  405.       delete prof1;
  406.     }
  407.  
  408.     restore_heap(m,TMP_SPACE);
  409.  
  410.     if (keep_ai_info())
  411.     {
  412.       if (aistate()!=old_aistate)
  413.       set_aistate_time(0);
  414.       else set_aistate_time(aistate_time()+1);    
  415.     }
  416.     if (!NILP(ret)) return 1;
  417.     else return 0;
  418.   }
  419.   else move(0,0,0);
  420.   return 1;
  421. }
  422.  
  423. int game_object::can_hurt(game_object *who)     // collision checking will ask first to see if you
  424. {
  425.   int is_attacker=current_level->is_attacker(this);  
  426.   // it's you against them!  Damage only if it you are attacking or they are attacking you
  427.   // I.E. don't let them hurt themselves, this can change if you over-ride this virtual function
  428.  
  429.   if (who->hurtable() && (is_attacker || current_level->is_attacker(who) || hurt_all()))
  430.     return 1;
  431.   else return 0;  
  432. }
  433.  
  434. void game_object::note_attack(game_object *whom)
  435. {
  436.   return ;   // nevermind
  437. }
  438.  
  439. void game_object::do_flinch(game_object *from)
  440. {
  441.   if (jrandom(2) && has_sequence(flinch_down))
  442.     set_state(flinch_down);
  443.   else if (has_sequence(flinch_up))
  444.     set_state(flinch_up);
  445. }
  446.  
  447.    
  448. void game_object::do_damage(int amount, game_object *from, long hitx, long hity, 
  449.                 long push_xvel, long push_yvel) 
  450. {
  451.  
  452.   void *d=figures[otype]->get_fun(OFUN_DAMAGE);  
  453.   if (d)
  454.   {
  455.     void    *am, *frm, *hx, *hy, *px, *py;  
  456.     game_object *o=current_object;
  457.     current_object=this;
  458.  
  459.     void *m=mark_heap(TMP_SPACE);
  460.  
  461.     am=new_cons_cell();
  462.     l_ptr_stack.push(&am);
  463.  
  464.     ((cons_cell *)am)->car=new_lisp_number(amount);   
  465.  
  466.     frm=new_cons_cell();
  467.     l_ptr_stack.push(&frm);
  468.  
  469.     ((cons_cell *)frm)->car=new_lisp_pointer(from);
  470.  
  471.     hx=new_cons_cell();
  472.     l_ptr_stack.push(&hx);
  473.  
  474.     ((cons_cell *)hx)->car=new_lisp_number(hitx);
  475.  
  476.     hy=new_cons_cell();
  477.     l_ptr_stack.push(&hy);
  478.     ((cons_cell *)hy)->car=new_lisp_number(hity);
  479.  
  480.     px=new_cons_cell();
  481.     l_ptr_stack.push(&px);
  482.     ((cons_cell *)px)->car=new_lisp_number(push_xvel);
  483.  
  484.     py=new_cons_cell();
  485.     l_ptr_stack.push(&py);
  486.     ((cons_cell *)py)->car=new_lisp_number(push_yvel);
  487.  
  488.  
  489.     ((cons_cell *)am)->cdr=frm;
  490.     ((cons_cell *)frm)->cdr=hx;
  491.     ((cons_cell *)hx)->cdr=hy;
  492.     ((cons_cell *)hy)->cdr=px;
  493.     ((cons_cell *)px)->cdr=py;
  494.  
  495.     time_marker *prof1;
  496.     if (profiling())
  497.       prof1=new time_marker;
  498.  
  499.     eval_user_fun((lisp_symbol *)d,am);
  500.     if (profiling())
  501.     {
  502.       time_marker now;
  503.       profile_add_time(this->otype,now.diff_time(prof1));
  504.       delete prof1;
  505.     }
  506.  
  507.  
  508.     l_ptr_stack.pop(6);
  509.    
  510.     restore_heap(m,TMP_SPACE);
  511.  
  512.     current_object=o;
  513.   } else damage_fun(amount,from,hitx,hity,push_xvel,push_yvel);
  514. #ifdef SCADALISP
  515.   ENDLOCAL();
  516. #endif
  517. }
  518.  
  519. void game_object::damage_fun(int amount, game_object *from, long hitx, long hity, 
  520.                 long push_xvel, long push_yvel) 
  521.   if (!hurtable() || !alive()) return ;
  522.  
  523.   add_hp(-amount);
  524.   set_flags(flags()|FLAG_JUST_HIT);
  525.   do_flinch(from);
  526.  
  527.   
  528.   set_xvel(xvel()+push_xvel);
  529.   if (push_yvel<0 && !gravity())
  530.     set_gravity(1);
  531.   set_yvel(yvel()+push_yvel);
  532.  
  533.   view *c=controller();
  534.   if (c && hp()<=0)
  535.   {
  536.     view *v=from->controller();
  537.     if (v) v->kills++;                       // attack from another player?
  538.     else if (from->total_objects()>0)
  539.     {
  540.       v=from->get_object(0)->controller();   // weapon from another player?
  541.       if (v && v!=c) v->kills++;
  542.       else
  543.       {
  544.     v=c;                                 // sucide
  545.     if (v) v->kills--;
  546.       }
  547.     }
  548.   }
  549. }
  550.      
  551.  
  552.  
  553. int game_object::facing_attacker(int attackerx)
  554.   return ((attackerx<x && direction<0) || (attackerx>=x && direction>0)); 
  555.  
  556. }
  557.  
  558.  
  559. void game_object::picture_space(long &x1, long &y1,long &x2, long &y2)
  560. {
  561.   int xc=x_center(),w=picture()->width(),h=picture()->height();  
  562.   if (direction>0)
  563.     x1=x-xc;  
  564.   else x1=x-(w-xc-1);  
  565.   x2=x1+w-1;
  566.   y1=y-h+1;
  567.   y2=y;  
  568. }
  569.  
  570.  
  571. int game_object::next_picture()
  572. {
  573.   int ret=1;
  574.   if (frame_dir()>0)
  575.   {
  576.     if (!current_sequence()->next_frame(current_frame))
  577.     {
  578.       next_sequence();
  579.       ret=0;
  580.     }
  581.   }
  582.   else 
  583.   {
  584.     if (!current_sequence()->last_frame(current_frame))
  585.     {
  586.       next_sequence();
  587.       ret=0;
  588.     }
  589.   }
  590.   frame_advance();
  591.   return ret;
  592. }
  593.  
  594.  
  595. long game_object::x_center()
  596. {
  597.   return current_sequence()->x_center(current_frame);   
  598. }
  599.  
  600.  
  601. void game_object::draw()
  602. {
  603.   if (figures[otype]->get_fun(OFUN_DRAW))
  604.   {
  605.     current_object=this;
  606.  
  607.     void *m=mark_heap(TMP_SPACE);
  608.     time_marker *prof1;
  609.     if (profiling())
  610.       prof1=new time_marker;
  611.  
  612.     eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_DRAW),NULL);
  613.     if (profiling())
  614.     {
  615.       time_marker now;
  616.       profile_add_time(this->otype,now.diff_time(prof1));
  617.       delete prof1;
  618.     }
  619.  
  620.  
  621.  
  622.     restore_heap(m,TMP_SPACE);
  623.  
  624.   } else drawer();
  625. }
  626.  
  627.  
  628. void game_object::map_draw()
  629. {
  630.   if (figures[otype]->get_fun(OFUN_MAP_DRAW))
  631.   {
  632.     current_object=this;
  633.  
  634.     void *m=mark_heap(TMP_SPACE);
  635.     time_marker *prof1;
  636.     if (profiling())
  637.       prof1=new time_marker;
  638.  
  639.     eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MAP_DRAW),NULL);
  640.     if (profiling())
  641.     {
  642.       time_marker now;
  643.       profile_add_time(this->otype,now.diff_time(prof1));
  644.       delete prof1;
  645.     }
  646.  
  647.     restore_heap(m,TMP_SPACE);
  648.  
  649.   }
  650. }
  651.  
  652. void game_object::draw_trans(int count, int max)
  653. {
  654.   trans_image *cpict=picture();
  655.   cpict->put_fade(screen,
  656.           (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  657.           y-cpict->height()+1-current_vyadd,
  658.           count,max,
  659.           color_table,the_game->current_palette());
  660. }
  661.  
  662.  
  663. void game_object::draw_tint(int tint_id)
  664. {
  665.   trans_image *cpict=picture();
  666.   if (fade_count())      
  667.     cpict->put_fade_tint(screen,
  668.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  669.                y-cpict->height()+1-current_vyadd,
  670.                fade_count(),fade_max(),
  671.                cash.ctint(tint_id)->data,
  672.                color_table,the_game->current_palette());
  673.  
  674.  
  675.   else
  676.     cpict->put_remaped(screen,
  677.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  678.                y-cpict->height()+1-current_vyadd,
  679.                cash.ctint(tint_id)->data);
  680. }
  681.  
  682.  
  683. void game_object::draw_double_tint(int tint_id, int tint2)
  684. {
  685.   trans_image *cpict=picture();
  686.   if (fade_count())      
  687.     cpict->put_fade_tint(screen,
  688.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  689.                y-cpict->height()+1-current_vyadd,
  690.                fade_count(),fade_max(),
  691.                cash.ctint(tint_id)->data,
  692.                color_table,the_game->current_palette());
  693.  
  694.  
  695.   else
  696.     cpict->put_double_remaped(screen,
  697.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  698.                y-cpict->height()+1-current_vyadd,
  699.                cash.ctint(tint_id)->data,
  700.                cash.ctint(tint2)->data);
  701. }
  702.  
  703.  
  704.  
  705. void game_object::draw_predator()
  706. {
  707.   trans_image *cpict=picture();
  708.   cpict->put_predator(screen,
  709.              (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  710.              y-cpict->height()+1-current_vyadd);
  711.             
  712. }
  713.  
  714. void game_object::drawer()
  715. {
  716.   trans_image *cpict;
  717.  
  718.   if (morph_status())
  719.   {
  720.     morph_status()->draw(this,current_view);
  721.     if (morph_status()->frames_left()<1)
  722.       set_morph_status(NULL);
  723.   }
  724.   else
  725.   {
  726.     view *v=controller();
  727.  
  728.     if (fade_count())      
  729.       draw_trans(fade_count(),fade_max());
  730.     else
  731.     {
  732.       trans_image *cpict=picture();
  733.       cpict->put_image(screen,
  734.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  735.                y-cpict->height()+1-current_vyadd);
  736.     }
  737.   }
  738. }
  739.  
  740. game_object *game_object::try_move(long x, long y, long &xv, long &yv, int checks)
  741. {
  742.   if (xv || yv)  // make sure they are suggesting movement
  743.   {    
  744.     game_object *who1=NULL,*who2=NULL;      // who did we intersect?  
  745.     long x2,y2,h;  
  746.  
  747.     if (checks&1)
  748.     {      
  749.       x2=x+xv;
  750.       y2=y+yv;    
  751.       if (xv==0)
  752.         current_level->vforeground_intersect(x,y,y2);
  753.       else
  754.         current_level->foreground_intersect(x,y,x2,y2);
  755.       if (!stoppable())
  756.         who1=current_level->boundary_setback(this,x,y,x2,y2);
  757.       else
  758.         who1=current_level->all_boundary_setback(this,x,y,x2,y2);  
  759.       xv=x2-x;
  760.       yv=y2-y;
  761.     }
  762.     
  763.  
  764.     if (checks&2)
  765.     {      
  766.       h=picture()->height();    
  767.       x2=x+xv;    
  768.       y2=y-h+1+yv; 
  769.       if (xv==0)
  770.         current_level->vforeground_intersect(x,y-h+1,y2);
  771.       else
  772.         current_level->foreground_intersect(x,y-h+1,x2,y2);
  773.       if (!stoppable())
  774.         who2=current_level->all_boundary_setback(this,x,y-h+1,x2,y2);    
  775.       else
  776.         who2=current_level->boundary_setback(this,x,y-h+1,x2,y2);
  777.       xv=x2-x;
  778.       yv=y2-y+h-1;  
  779.     }
  780.         
  781.     if (who2) return who2;
  782.     else return who1;
  783.   }
  784.   else return NULL;  
  785. }
  786.  
  787. void *game_object::float_tick()  // returns 1 if you hit something, 0 otherwise
  788. {
  789.   long ret=0;
  790.   if (hp()<=0)
  791.   {
  792.     if (state!=dead)
  793.     {
  794.       set_xacel(0);
  795.       set_fxacel(0);
  796.  
  797.       if (has_sequence(dieing))
  798.       {      
  799.     if (state!=dieing)
  800.     {
  801.       set_state(dieing);
  802.       set_xvel(0);
  803.     }
  804.       } else 
  805.       { set_xvel(0); 
  806.     set_fxvel(0);
  807.     if (has_sequence(dead))
  808.           set_state(dead); 
  809.     else return 0;
  810.       }
  811.     } 
  812.   }
  813.  
  814.   long fxv=sfxvel()+sfxacel(),fyv=sfyvel()+sfyacel();
  815.   long xv=xvel()+xacel()+(fxv>>8),yv=yvel()+yacel()+(fyv>>8);
  816.  
  817.   if (xv!=xvel() || yv!=yvel())   // only store vel's if changed so we don't increase object size
  818.   {
  819.     set_xvel(xv);
  820.     set_yvel(yv);
  821.   }
  822.  
  823.   if (fxv!=sfxvel() || fyv!=sfyvel())
  824.   {
  825.     set_fxvel(fxv&0xff);
  826.     set_fyvel(fyv&0xff);
  827.   }
  828.  
  829.  
  830.   if (fxv || fyv || xv || yv)   // don't even try if there is no velocity
  831.   {
  832.     long nx=x,ny=y;
  833.     long ffx=fx()+sfxvel(),ffy=fy()+sfyvel();
  834.     long nxv=xvel()+(ffx>>8);
  835.     long nyv=yvel()+(ffy>>8);
  836.     set_fx(ffx&0xff);
  837.     set_fy(ffy&0xff);
  838.     
  839.     long old_nxv=nxv,old_nyv=nyv;
  840.     game_object *hit_object=try_move(x,y,nxv,nyv,3);   // now find out what velocity is safe to use
  841.     
  842. /*    if (get_cflag(CFLAG_STOPPABLE))
  843.     {
  844.       game_object *r=current_level->boundary_setback(exclude,x,y,nxv,nyv,1);
  845.       if (r) hit_object=r;
  846.     }*/
  847.  
  848.     x+=nxv;
  849.     y+=nyv;
  850.     if (old_nxv!=nxv || old_nyv!=nyv)
  851.     {
  852.       long lx=last_tile_hit_x,ly=last_tile_hit_y;
  853.       stop();
  854.       if (old_nxv==0)
  855.       {
  856.     if (old_nyv>0) ret|=BLOCKED_DOWN;
  857.     else if (old_nyv<0) ret|=BLOCKED_UP;
  858.       } else if (old_nyv==0)
  859.       {
  860.     if (old_nxv>0) ret|=BLOCKED_RIGHT;
  861.     else if (old_nxv<0) ret|=BLOCKED_LEFT;
  862.       } else
  863.       {
  864.     long tx=(old_nxv>0 ? 1 : -1),ty=0;
  865.     try_move(x,y,tx,ty,3);
  866.     if (!tx)     
  867.       ret|=(old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT);    
  868.     else tx=0;
  869.  
  870.     ty=(old_nyv>0 ? 1 : -1);
  871.     try_move(x,y,tx,ty,3);
  872.     if (!ty)     
  873.       ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP);
  874.     
  875.     if (!ret)
  876.       ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP) | (old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT);
  877.  
  878.       }
  879.  
  880.       void *rlist=NULL;   // return list
  881.       p_ref r1(rlist);
  882.  
  883.       if (hit_object)
  884.       {
  885.     push_onto_list(new_lisp_pointer(hit_object),rlist);
  886.     push_onto_list(l_object,rlist);
  887.       } else
  888.       {
  889.     push_onto_list(new_lisp_number(ly),rlist);
  890.     push_onto_list(new_lisp_number(lx),rlist);
  891.     push_onto_list(l_tile,rlist);
  892.       }
  893.       push_onto_list(new_lisp_number(ret),rlist);
  894.  
  895.       return rlist;
  896.     } else return true_symbol;
  897.   }
  898.   return true_symbol;
  899. }
  900.  
  901. int game_object::tick()      // returns blocked status
  902. {
  903.   int blocked=0;
  904.  
  905.   /*  long xt=0,yt=2;
  906.   try_move(x,y-2,xt,yt,1);    // make sure we are not falling through the floor
  907.   y=y-2+yt; */
  908.   
  909.   if (flags()&FLAG_JUST_BLOCKED)
  910.     set_flags(flags()-FLAG_JUST_BLOCKED);
  911.  
  912.   if (gravity() && !floating())
  913.   {
  914.     int fya;
  915.     if (yacel()>=0)
  916.       fya=sfyacel()+200;
  917.     else
  918.       fya=sfyacel()-200;
  919.  
  920.     set_yacel(yacel()+(fya>>8));
  921.     set_fyacel(fya&255);
  922.   }
  923.   
  924.   // first let's move the guy acording to his physics
  925.   long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel();
  926.   if (xa || ya || fxa || fya)
  927.   {
  928.     int fxv=sfxvel(),fyv=sfyvel();
  929.     fxv+=fxa;  fyv+=fya;    
  930.     long xv=xvel()+xa+(fxv>>8); 
  931.     set_xvel(xvel()+xa+(fxv>>8));
  932.     set_yvel(yvel()+ya+(fyv>>8));
  933.     set_fxvel(fxv&0xff);
  934.     set_fyvel(fyv&0xff);
  935.   }
  936.   
  937.   // check to see if this advancement causes him to collide with objects
  938.   long old_vy=yvel(),old_vx=xvel();  // save the correct veloicties
  939.  
  940.   if (old_vx || old_vy)
  941.   {
  942.     int up=0;
  943.     if (yvel()<=0)  // if we are going up or a strait across check up and down
  944.     up=2;
  945.     long xv=xvel(),yv=yvel();
  946.     game_object *h=try_move(x,y,xv,yv,1|up);       // now find out what velocity is safe to use
  947.     set_xvel(xv);
  948.     set_yvel(yv);
  949.     x+=xv;
  950.     y+=yv;
  951.  
  952.     if (h && stoppable()) return BLOCKED_LEFT|BLOCKED_RIGHT;
  953.  
  954.     if (xv!=old_vx || yv!=old_vy)     // he collided with something
  955.     {          
  956.       if (gravity())                         // was he going up or down?
  957.       {                           
  958.     long fall_xv=0,old_fall_vy,fall_vy;
  959.     old_fall_vy=fall_vy=old_vy-yvel();             // make sure he gets all of his yvel
  960.     try_move(x,y,fall_xv,fall_vy,1|up);
  961.     if (old_vy>0 && fall_vy<old_fall_vy)       // he was trying to fall, but he hit the ground
  962.     {
  963.       if (old_vy>0)    
  964.       {
  965.         blocked|=BLOCKED_DOWN;
  966.         
  967.         if (!xvel() && has_sequence(end_run_jump))      
  968.         {
  969.           set_xvel(old_vx);
  970.           set_state(end_run_jump);
  971.         }
  972.         else set_state(stopped);      
  973.       }
  974.       else blocked|=BLOCKED_UP;
  975.  
  976.  
  977.       if (state==run_jump_fall)
  978.       {
  979.         if (has_sequence(running))
  980.         set_state(running);
  981.         else
  982.         {
  983.           stop_x();
  984.           set_state(stopped);
  985.         }
  986.       }
  987.       else
  988.       {
  989.         set_yacel(0);
  990.         set_fyacel(0);
  991.         set_yvel(0);
  992.         set_fyvel(0);
  993.         set_gravity(0);
  994.       }
  995.  
  996.     } else 
  997.     {
  998.       if (old_vy!=0)
  999.       {
  1000.         long testx=old_vx<0 ? -1 : 1,testy=0;    // see if we were stopped left/right
  1001.                                                      // or just up down
  1002.         try_move(x,y,testx,testy,1|up);
  1003.         if (testx==0)                           // blocked left/right, set flag
  1004.         {
  1005.           if (old_vx<0)
  1006.             blocked|=BLOCKED_LEFT;
  1007.           else
  1008.             blocked|=BLOCKED_RIGHT;
  1009.         }
  1010.         else if (old_vy<0)
  1011.           blocked|=BLOCKED_UP;
  1012.         else if (old_vy>0)
  1013.           blocked|=BLOCKED_DOWN;
  1014.  
  1015.       } else if (old_vx<0)   // we can skip left/right test because player wasn't moving up/down
  1016.             blocked|=BLOCKED_LEFT;
  1017.       else
  1018.             blocked|=BLOCKED_RIGHT;
  1019.  
  1020.       set_xvel(0);
  1021.       set_fxvel(0);
  1022.       if (old_vy<0 && fall_vy>0)        
  1023.       {
  1024.         set_yvel(yvel()+fall_vy);
  1025.       } else set_yvel(yvel()+fall_vy);
  1026.     }      
  1027.     y+=fall_vy;            
  1028.       }    
  1029.       else                  // see if we can make him 'climb' the hill
  1030.       {
  1031.     long ox=x,oy=y;       // rember orginal position in case climb doesn't work
  1032.  
  1033.     long climb_xvel=0,climb_yvel=-5;        // try to move up one pixel to step over the 
  1034.     try_move(x,y,climb_xvel,climb_yvel,3);  // jutting polygon line
  1035.     y+=climb_yvel;
  1036.  
  1037.     climb_xvel=old_vx-xvel();
  1038.     climb_yvel=-(abs(climb_xvel));        // now try 45 degree slope
  1039.     try_move(x,y,climb_xvel,climb_yvel,3);
  1040.  
  1041.     if (abs(climb_xvel)>0)  // see if he got further by climbing
  1042.     {
  1043.       blocked=blocked&(~(BLOCKED_LEFT|BLOCKED_RIGHT));
  1044.       x+=climb_xvel;
  1045.       y+=climb_yvel;
  1046.  
  1047.       set_xvel(xvel()+climb_xvel);
  1048.       set_yvel(0);          
  1049.       set_fyvel(0);
  1050.       
  1051.       // now put him back on the ground          
  1052.       climb_yvel=abs(climb_xvel)+5;               // plus one to put him back on the ground
  1053.       climb_xvel=0;
  1054.       try_move(x,y,climb_xvel,climb_yvel,1);
  1055.       if (climb_yvel)
  1056.           y+=climb_yvel;
  1057.     }
  1058.     else             
  1059.     {    
  1060.       if (old_vx<0)
  1061.           blocked|=BLOCKED_LEFT;
  1062.       else
  1063.           blocked|=BLOCKED_RIGHT;
  1064.       set_state(stopped);      // nope, musta hit a wall, stop the poor fella
  1065.       x=ox;
  1066.       y=oy;    
  1067.     }
  1068.     
  1069.       }
  1070.       
  1071.       if (xvel()!=old_vx && state!=run_jump_fall && state!=end_run_jump)
  1072.       {
  1073.     set_xacel(0); 
  1074.     set_fxacel(0);
  1075.       }
  1076.     }
  1077.   }
  1078.      
  1079.   if (yacel()==0 && !gravity())       // he is not falling, make sure he can't
  1080.   {
  1081.     long nvx=0,nvy=yvel()+12;  // check three pixels below for ground
  1082.     try_move(x,y,nvx,nvy,1); 
  1083.     if (nvy>11)                    // if he falls more than 2 pixels, then he falls
  1084.     {
  1085.       if (state!=run_jump_fall)      // make him fall
  1086.       {       
  1087.         if (has_sequence(run_jump_fall))
  1088.           set_state(run_jump_fall);
  1089.         set_gravity(1);
  1090.       }
  1091.     } else if (nvy)   // if he fells less than 3 pixels then let him descend 'hills'
  1092.     {      
  1093.       y+=nvy;
  1094.       blocked|=BLOCKED_DOWN;      
  1095.     }    
  1096.   }
  1097.   return blocked;
  1098. }
  1099.  
  1100. void game_object::defaults()
  1101. {
  1102.   set_state(state);
  1103.   if (otype!=0xffff)
  1104.   {
  1105.     int s=get_ability(otype,start_hp);
  1106.     if (s!=default_simple.hp())
  1107.       set_hp(s);
  1108.   }
  1109. }
  1110.  
  1111. void game_object::frame_advance()
  1112. {
  1113.   int ad=current_sequence()->get_advance(current_frame);
  1114.   if (ad && current_level)
  1115.   {
  1116.     long xv;
  1117.     if (direction>0) xv=ad; else xv=-ad;
  1118.     long yv=0;
  1119.     try_move(x,y,xv,yv,3);
  1120.     x+=xv;
  1121.   }   
  1122. }
  1123.  
  1124. void game_object::set_state(character_state s, int frame_direction)
  1125. {
  1126.   if (has_sequence(s))
  1127.     state=s;
  1128.   else state=stopped;
  1129.  
  1130.   current_frame=0;  
  1131.   if (frame_direction!=1)
  1132.     set_frame_dir(frame_direction); 
  1133.  
  1134.   frame_advance();
  1135. }
  1136.  
  1137.  
  1138. game_object *create(int type, long x, long y, int skip_constructor, int aitype)
  1139. {
  1140.   game_object *g=new game_object(type,skip_constructor);
  1141.   g->x=x; g->y=y; g->last_x=x; g->last_y=y;
  1142.   if (aitype)
  1143.     g->set_aitype(aitype);
  1144.   if (figures[type]->get_fun(OFUN_CONSTRUCTOR) && !skip_constructor)
  1145.   {
  1146.     game_object *o=current_object;
  1147.     current_object=g;    
  1148.  
  1149.     void *m=mark_heap(TMP_SPACE);
  1150.  
  1151.     time_marker *prof1;
  1152.     if (profiling())
  1153.       prof1=new time_marker;
  1154.  
  1155.     eval_function((lisp_symbol *)figures[type]->get_fun(OFUN_CONSTRUCTOR),NULL);
  1156.     if (profiling())
  1157.     {
  1158.       time_marker now;
  1159.       profile_add_time(type,now.diff_time(prof1));
  1160.       delete prof1;
  1161.     }
  1162.  
  1163.  
  1164.  
  1165.     restore_heap(m,TMP_SPACE);
  1166.  
  1167.     current_object=o;
  1168.   }
  1169.   return g;
  1170. }
  1171.  
  1172. int base_size()
  1173. {
  1174.   return 1+  
  1175.          1*8+
  1176.      2*5+
  1177.      4*7;
  1178. }
  1179.  
  1180. int game_object::size()
  1181. {
  1182.   return base_size();
  1183. }
  1184.  
  1185.  
  1186.  
  1187. int game_object::move(int cx, int cy, int button)
  1188. {  
  1189.   int ret=0;
  1190.  
  1191.   if (figures[otype]->get_fun(OFUN_MOVER))      // is a lisp move function defined?
  1192.   {
  1193.     void *lcx,*lcy,*lb;
  1194.  
  1195.     game_object *o=current_object;
  1196.     current_object=this;
  1197.  
  1198.  
  1199.     // make a list of the parameters, and call the lisp function
  1200.     lcx=new_cons_cell();
  1201.     l_ptr_stack.push(&lcx);
  1202.     ((cons_cell *)lcx)->car=new_lisp_number(cx);
  1203.  
  1204.     lcy=new_cons_cell();
  1205.     l_ptr_stack.push(&lcy);
  1206.     ((cons_cell *)lcy)->car=new_lisp_number(cy);
  1207.  
  1208.     lb=new_cons_cell();
  1209.     l_ptr_stack.push(&lb);
  1210.     ((cons_cell *)lb)->car=new_lisp_number(button);
  1211.  
  1212.  
  1213.     ((cons_cell *)lcx)->cdr=lcy;
  1214.     ((cons_cell *)lcy)->cdr=lb;
  1215.  
  1216.     void *m=mark_heap(TMP_SPACE);
  1217.  
  1218.     time_marker *prof1;
  1219.     if (profiling())
  1220.       prof1=new time_marker;
  1221.  
  1222.     void *r=eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MOVER),
  1223.               (void *)lcx);
  1224.     if (profiling())
  1225.     {
  1226.       time_marker now;
  1227.       profile_add_time(this->otype,now.diff_time(prof1));
  1228.       delete prof1;
  1229.     }
  1230.  
  1231.     restore_heap(m,TMP_SPACE);
  1232.  
  1233.     l_ptr_stack.pop(3);
  1234.     if (item_type(r)!=L_NUMBER)
  1235.     {
  1236.       lprint(r);
  1237.       lbreak("Object %s did not return a number from it's mover function!\n"
  1238.          "It should return a number to indicate it's blocked status to the\n"
  1239.          "ai function.",object_names[otype]);    
  1240.     }
  1241.     ret|=lnumber_value(r);
  1242.     current_object=o;
  1243.   }
  1244.   else ret|=mover(cx,cy,button);    
  1245.  
  1246.   return ret;
  1247. }
  1248.  
  1249. int game_object::mover(int cx, int cy, int button)  // return false if the route is blocked
  1250. {
  1251.   if (hp()<=0) 
  1252.     return tick();
  1253.  
  1254.   if (flinch_state(state))                    // flinching? don't move
  1255.     cx=cy=button=0;
  1256.     
  1257.  
  1258.   if (cx)          // x movement suggested?
  1259.   {      
  1260.     if (state==stopped)   // see if started moving
  1261.     {   
  1262.       if (has_sequence(running))
  1263.       {
  1264.     if (cx>0)
  1265.     {
  1266.       direction=1;
  1267.           set_xvel(get_ability(type(),run_top_speed));
  1268.     }
  1269.     else
  1270.     {
  1271.       direction=-1;
  1272.       set_xacel(-get_ability(type(),run_top_speed));
  1273.     }
  1274.     set_state(running);
  1275.       }
  1276.     } else if (state==run_jump || state==run_jump_fall)
  1277.     {
  1278.       if (cx>0)
  1279.       {
  1280.     direction=1;
  1281.     set_xacel(get_ability(type(),start_accel));           // set the appropriate accel
  1282.       } else
  1283.       {
  1284.     direction=-1;
  1285.     set_xacel(-get_ability(type(),start_accel));           // set the appropriate accel
  1286.       }      
  1287.     }
  1288.     else 
  1289.     {
  1290.       // turn him around if he pressed the other way, he is not walking so a fast turn
  1291.       // is needed, don't go through the turn sequence
  1292.       if ((cx>0  && direction<0) || (cx<0 && direction>0))
  1293.         direction=-direction;      
  1294.     } 
  1295.   }         // not pressing left or right, so slow down or stop
  1296.   else if (!gravity() && state!=start_run_jump)
  1297.   {    
  1298.     long stop_acel;
  1299.     if (xvel()<0)                                    // he was going left
  1300.     {
  1301.       stop_acel=get_ability(type(),stop_accel);    // find out how fast he can slow down
  1302.       if (xvel()+stop_acel>=0)                       // if this acceleration is enough to stop him
  1303.       {
  1304.     stop_x();
  1305.     if (!gravity())    
  1306.       set_state(stopped);      
  1307.       } else { set_xacel(stop_acel); }
  1308.     } else if (xvel()>0)
  1309.     {
  1310.       stop_acel=-get_ability(type(),stop_accel);
  1311.       if (xvel()+stop_acel<=0)
  1312.       {
  1313.     stop_x();
  1314.     if (!gravity())
  1315.       set_state(stopped);
  1316.       } else set_xacel(stop_acel);
  1317.     } else if (!gravity())                // don't stop in the air
  1318.     { 
  1319.       set_xacel(0);
  1320.       set_fxacel(0);
  1321.       // Check to see if we should go to stop state 
  1322.       if (state==running)
  1323.         set_state(stopped);
  1324.     }   
  1325.   }    
  1326.   
  1327.  
  1328. /*  if (state==still_jump || state==still_jump_fall || state==end_still_jump)
  1329.   {
  1330.     set_xacel(0);
  1331.     set_fxacel(0);
  1332.     if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed));
  1333.     else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed));
  1334.   } else if (state==run_jump || state==run_jump_fall || state==end_run_jump)
  1335.   {
  1336.     set_xacel(0);
  1337.     set_fxacel(0);
  1338.     if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed));
  1339.     else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed));
  1340.   } */
  1341.   
  1342.   // see if the user said to jump
  1343.   if (cy<0 && !floating() && !gravity())
  1344.   {
  1345.     set_gravity(1);      
  1346.     set_yvel(get_ability(type(),jump_yvel));
  1347. //    if (cx && has_sequence(run_jump))
  1348.       set_state(run_jump);
  1349.     if (xvel()!=0)
  1350.       if (direction>0)
  1351.         set_xvel(get_ability(type(),jump_top_speed));
  1352.       else
  1353.         set_xvel(-get_ability(type(),jump_top_speed));
  1354.     set_xacel(0);
  1355.  
  1356.  
  1357. /*    if (state==stopped)  
  1358.     {
  1359.       if (cx && has_sequence(start_run_jump))
  1360.         set_state(start_run_jump);
  1361.       else if (has_sequence(start_still_jump))
  1362.         set_state(start_still_jump);                
  1363.       else 
  1364.       {
  1365.  
  1366.       }
  1367.     }
  1368.     else if (state==running && has_sequence(run_jump))
  1369.     {
  1370.       set_state(run_jump);
  1371.       set_yvel(get_ability(type(),jump_yvel));
  1372.       set_gravity(1);      
  1373.     }    
  1374.     else if (state==walking || state==turn_around)  // if walking check to see if has a
  1375.     {
  1376.       if (has_sequence(start_still_jump))
  1377.         set_state(start_still_jump);    
  1378.       else
  1379.       {
  1380.         set_yvel(get_ability(type(),jump_yvel));
  1381.         set_gravity(1);      
  1382.         if (has_sequence(run_jump))
  1383.           set_state(run_jump);
  1384.       }
  1385.     }    */
  1386.   }
  1387.  
  1388.  
  1389.  
  1390.   if (state==run_jump && yvel()>0)
  1391.     set_state(run_jump_fall);
  1392.     
  1393.  
  1394.  
  1395. //  if (state!=end_still_jump && state!=end_run_jump)
  1396.   {    
  1397.     if (cx>0)
  1398.       set_xacel(get_ability(type(),start_accel));
  1399.     else if (cx<0)
  1400.       set_xacel(-get_ability(type(),start_accel));
  1401.   }  
  1402.   
  1403.   // make sure they are not going faster than their maximum speed
  1404.   int top_speed;
  1405.   if (state==stopped || state==end_run_jump)
  1406.     top_speed=get_ability(type(),walk_top_speed);
  1407.   else if (state==running)
  1408.     top_speed=get_ability(type(),run_top_speed);    
  1409.   else if (state==run_jump || state==run_jump_fall || state==start_run_jump)
  1410.   {
  1411.     top_speed=get_ability(type(),jump_top_speed);      
  1412.     if (!cx) top_speed=0;
  1413.   }
  1414.   else top_speed=1000;
  1415.     
  1416.       
  1417.   if (abs(xvel()+xacel())>top_speed)
  1418.   {    
  1419.     if (xacel()<0) set_xacel(-top_speed-xvel());
  1420.     else set_xacel(top_speed-xvel());
  1421.   }  
  1422.     
  1423.   character_state old_state=state;
  1424.   int old_frame=current_frame;    
  1425.   int tick_stat=tick();
  1426.  
  1427.   // if he started to jump and slammed into a wall then make sure he stays in this state
  1428.   // so he can finish the jump
  1429.   if (!tick_stat && (old_state==start_run_jump))
  1430.   {
  1431.     set_state(old_state);
  1432.     current_frame=old_frame;
  1433.     next_picture();    
  1434.   }
  1435.     
  1436.   return tick_stat;
  1437.     
  1438. }
  1439.  
  1440.  
  1441.  
  1442.  
  1443. game_object *game_object::bmove(int &whit, game_object *exclude)
  1444. {
  1445.  
  1446.   // first let's move the guy acording to his physics
  1447.   long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel();
  1448.   if (xa || ya || fxa || fya)
  1449.   {
  1450.     int fxv=sfxvel(),fyv=sfyvel();
  1451.     fxv+=fxa;  fyv+=fya;    
  1452.     long xv=xvel()+xa+(fxv>>8); 
  1453.     set_xvel(xvel()+xa+(fxv>>8));
  1454.     set_yvel(yvel()+ya+(fyv>>8));
  1455.     set_fxvel(fxv&0xff);
  1456.     set_fyvel(fyv&0xff);
  1457.   }
  1458.   
  1459.   long ox2,oy2;
  1460.  
  1461.   long nx=x+xvel(),nfx=fx()+fxvel(),ny=y+yvel(),nfy=fy()+fyvel();
  1462.   nx+=nfx>>8;
  1463.   ny+=nfy>>8;
  1464.  
  1465.  
  1466.   // check to see if this advancement causes him to collide with objects
  1467.   ox2=nx;
  1468.   oy2=ny;  // save the correct veloicties
  1469.   
  1470.   if (nx==x)
  1471.     current_level->vforeground_intersect(x,y,ny); 
  1472.   else
  1473.     current_level->foreground_intersect(x,y,nx,ny);  // first see how far we can travel
  1474.   game_object *ret=current_level->all_boundary_setback(exclude,x,y,nx,ny);
  1475.   x=nx;
  1476.   y=ny;
  1477.   set_fx(nfx&0xff);
  1478.   set_fy(nfy&0xff);
  1479.   if (ret)
  1480.   {
  1481.     if (!ret->hurtable())   // object is not hurtable, return as if hit wall.
  1482.     { whit=1;
  1483.       return NULL;
  1484.     } else
  1485.     return ret;
  1486.   }
  1487.   else
  1488.   {
  1489.     whit=(nx!=ox2 || ny!=oy2);
  1490.     return NULL;
  1491.   }
  1492. }
  1493.  
  1494.  
  1495.  
  1496. int object_to_number_in_list(game_object *who, object_node *list)
  1497. {
  1498.   int x=1;
  1499.   while (list) 
  1500.   { 
  1501.     if (who==list->me) return x; 
  1502.     else list=list->next;
  1503.     x++;
  1504.   }
  1505.   return 0;
  1506. }
  1507.  
  1508. game_object *number_to_object_in_list(long x, object_node *list)
  1509. {
  1510.   if (!x) return NULL; x--;
  1511.   while (x && list) { list=list->next; x--; }
  1512.   if (list) return list->me;
  1513.   else return NULL;
  1514. }
  1515.  
  1516.  
  1517. void delete_object_list(object_node *first)
  1518. {
  1519.   while (first)
  1520.   {
  1521.     object_node *n=first;
  1522.     first=first->next;
  1523.     delete n;
  1524.   }
  1525. }
  1526.  
  1527.  
  1528. long object_list_length(object_node *list)
  1529. {
  1530.   long x=0;
  1531.   while (list) { list=list->next; x++; }
  1532.   return x;
  1533.   
  1534. }
  1535.  
  1536.  
  1537.  
  1538. game_object::game_object(int Type, int load) 
  1539.   if (Type<0xffff)
  1540.   {
  1541.     int t=figures[Type]->tv;
  1542.     if (t)
  1543.     {
  1544.       lvars=(long *)jmalloc(t*4,"object vars");
  1545.       memset(lvars,0,t*4);
  1546.     }
  1547.     else lvars=NULL;
  1548.   } else lvars=NULL;
  1549.  
  1550.   otype=Type; 
  1551.   if (!load) defaults(); 
  1552. }
  1553.  
  1554.  
  1555. int game_object::reduced_state()
  1556. {
  1557.   long x=0;
  1558.   for (int i=0;i<figures[otype]->ts;i++)
  1559.   {
  1560.     if (i==state) return x;
  1561.       else
  1562.     if (figures[otype]->seq[i]) x++;
  1563.   }
  1564.   return 0;
  1565. }
  1566.  
  1567.  
  1568. void game_object::change_aitype(int new_type)
  1569. {
  1570.   set_aitype(new_type);
  1571.   if (otype<0xffff)
  1572.   {
  1573.     void *f=figures[otype]->get_fun(OFUN_CHANGE_TYPE);  
  1574.     if (f) 
  1575.     {
  1576.       game_object *o=current_object;
  1577.       current_object=(game_object *)this;
  1578.  
  1579.       time_marker *prof1;
  1580.       if (profiling())
  1581.         prof1=new time_marker;
  1582.  
  1583.       eval_user_fun((lisp_symbol *)f,NULL);
  1584.  
  1585.       if (profiling())
  1586.       {
  1587.     time_marker now;
  1588.     profile_add_time(this->otype,now.diff_time(prof1));
  1589.     delete prof1;
  1590.       }
  1591.  
  1592.  
  1593.       current_object=o;
  1594.     }
  1595.   }
  1596. }
  1597.  
  1598.  
  1599. void game_object::change_type(int new_type)
  1600. {
  1601.   if (lvars) jfree(lvars);     // free old variable
  1602.  
  1603.   if (otype<0xffff)
  1604.   {
  1605.     int t=figures[new_type]->tv;
  1606.     if (t)
  1607.     {
  1608.       lvars=(long *)jmalloc(t*4,"object vars");
  1609.       memset(lvars,0,t*4);
  1610.     }
  1611.     else lvars=NULL;
  1612.   } else return;
  1613.   otype=new_type;
  1614.  
  1615.   if (figures[new_type]->get_fun(OFUN_CONSTRUCTOR))
  1616.   {
  1617.     game_object *o=current_object;
  1618.     current_object=this;    
  1619.  
  1620.     void *m=mark_heap(TMP_SPACE);
  1621.  
  1622.     time_marker *prof1;
  1623.     if (profiling())
  1624.       prof1=new time_marker;
  1625.  
  1626.     eval_function((lisp_symbol *)figures[new_type]->get_fun(OFUN_CONSTRUCTOR),NULL);
  1627.     if (profiling())
  1628.     {
  1629.       time_marker now;
  1630.       profile_add_time(otype,now.diff_time(prof1));
  1631.       delete prof1;
  1632.     }
  1633.  
  1634.  
  1635.     restore_heap(m,TMP_SPACE);
  1636.  
  1637.     current_object=o;
  1638.   }  
  1639. }
  1640.