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

Last change on this file since 555 was 555, checked in by Sam Hocevar, 11 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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