source: abuse/tags/pd/macabuse/src/objects.c @ 49

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