source: abuse/trunk/src/objects.cpp @ 2

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