source: abuse/trunk/src/objects.cpp

Last change on this file was 682, checked in by Sam Hocevar, 8 years ago

core: rename vec2i to ivec2 and update matrix.h from Lol Engine.

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