source: abuse/trunk/src/chars.cpp @ 636

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

lisp: merge the Lisp and LispGC classes and improve coding style.

File size: 14.4 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
[481]17#include "chars.h"
18#include "game.h"
19#include "intsect.h"
20#include "lisp.h"
21#include "jwindow.h"
22#include "input.h"
23#include "id.h"
24#include "clisp.h"
25#include "dprint.h"
26#include "lisp_gc.h"
[2]27
28#define FADING_FRAMES 26
29#define FADING_MAX 32
30
31character_type **figures;
32
33
34
35int total_weapons=0;
36int *weapon_types=NULL;    // maps 0..total_weapons into 'real' weapon type
37
[39]38char const *state_names[MAX_STATE] =
39{
40    "dead",
41    "dieing",
42    "stopped",
43    "start_run_jump", "run_jump", "run_jump_fall", "end_run_jump",
44    "flinch_up", "flinch_down",
45    "morph_pose",
46    "running"
47};
[2]48
[124]49/*                   "start_still_jump","still_jump","still_jump_fall","end_still_jump",
[2]50
[124]51                   "morph_pose",
[494]52
[124]53                   "walking",
[2]54
[494]55
[124]56                   "weapon_draw",
57                   "weapon_put_away",
58                   "weapon_fire",
59                   "weapon_end_fire",
60                   "weapon_fire_up",
61                   "weapon_end_fire_up",
[2]62
[124]63                   "blocking",
64                   "block_recoil",
[2]65
[124]66                   "turn_around",
67                   "flinch_up","flinch_down","flinch_back",
68                   "flinch_air","flinch_ground","flinch_getup","woze",
69                   "stance"
70                 } ; */
[2]71
72
[39]73char const *cflag_names[TOTAL_CFLAGS] =
74{
75    "hurt_all", "is_weapon", "stoppable", "can_block",
76    "hurtable", "pushable", "unlistable",
77    "add_front", "cached_in", "need_cache_in", "unactive_shield"
78};
[2]79
[39]80char const *ofun_names[TOTAL_OFUNS] =
81{
82    "ai_fun", "move_fun", "draw_fun", "map_draw_fun", "damage_fun",
83    "next_state_fun", "user_fun",
84    "constructor", "reload_fun", "get_cache_list_fun",
85    "type_change_fun"
86};
87
[484]88int character_type::add_state(void *symbol) // returns index into seq to use
[2]89{
90  if (item_type(symbol)!=L_SYMBOL)
91  {
[493]92    ((LObject *)symbol)->Print();
[2]93    lbreak("is not a symbol (in def_char)");
94    exit(0);
95  }
96
97  void *val=symbol_value(symbol);
98
99  int num;
100  if (DEFINEDP(val))
101  {
102    if (item_type(val)!=L_NUMBER)
103    {
[493]104      ((LObject *)symbol)->Print();
[2]105      dprintf("expecting symbol value to be a number, instead got : ");
[493]106      ((LObject *)val)->Print();
[2]107      lbreak("");
108      exit(0);
109    }
110    num=lnumber_value(val);
[124]111  } else
[2]112  {
113    num=ts;
114    if (num<MAX_STATE) num=MAX_STATE;
[635]115    LSpace *sp = LSpace::Current;
116    LSpace::Current = &LSpace::Perm;
[492]117    ((LSymbol *)symbol)->SetNumber(num);
[635]118    LSpace::Current=sp;
[2]119  }
120
121  if (num<ts && seq[num])
122  {
[493]123    ((LObject *)symbol)->Print();
[2]124    lbreak("symbol has been assigned value %d, but value already in use by state %s\n"
[124]125       "use a different symbol for this state\n",
[492]126       lstring_value(((LSymbol *)seq_syms[num])->GetName()));
[2]127    exit(0);
128  } else if (num>=ts)
129  {
[129]130    seq=(sequence **)realloc(seq,sizeof(sequence *)*(num+1));
131    seq_syms=(void **)realloc(seq_syms,sizeof(void *)*(num+1));
[2]132
133    memset(&seq[ts],0,sizeof(sequence *)*((num+1)-ts));
134    memset(&seq_syms[ts],0,sizeof(void *)*((num+1)-ts));
135
136    ts=num+1;
137  }
138
139  seq_syms[num]=symbol;
140  return num;
141}
142
143int flinch_state(character_state state)
144{
145  if (state==flinch_up || state==flinch_down)
146    return 1;
147  else return 0;
148}
149
150int character_type::cache_in()    // returns false if out of cache memory
151{
152  int i;
153  if (get_cflag(CFLAG_CACHED_IN))
154    return 1;
155  cflags|=1<<CFLAG_CACHED_IN;
156
[494]157  for (i=0; i<ts; i++)
[2]158  {
159    if (seq[i])
160      seq[i]->cache_in();
161  }
162  return 1;
163}
164
165void character_type::add_sequence(character_state which, sequence *new_seq)
166{
167  if (seq[which])
168    delete seq[which];
[124]169  seq[which]=new_seq;
170}
[2]171
172void *l_obj_get(long number) // exten lisp function switches on number
173{
174  character_type *t=figures[current_object->otype];
175  if (t->tiv<=number || !t->vars[number])
176  {
177    lbreak("access : variable does not exsist for this class\n");
178    return 0;
179  }
[492]180  return LNumber::Create(current_object->lvars[t->var_index[number]]);
[2]181}
182
183void l_obj_set(long number, void *arg)  // exten lisp function switches on number
184{
185  character_type *t=figures[current_object->otype];
186  if (t->tiv<=number || !t->vars[number])
187  {
188    lbreak("set : variable does not exsist for this class\n");
189    return;
190  }
191  current_object->lvars[t->var_index[number]]=lnumber_value(arg);
192}
193
194void l_obj_print(long number)  // exten lisp function switches on number
195{
196  character_type *t=figures[current_object->otype];
197  if (t->tiv<=number || !t->vars[number])
198  {
199    lbreak("access : variable does not exsist for this class\n");
200    return;
201  }
[124]202  dprintf("%d",current_object->lvars[t->var_index[number]]);
[2]203}
204
205void character_type::add_var(void *symbol, void *name)
206{
207  /* First see if the variable has been defined for another object
208     if so report a conflict if any occur */
[492]209  LSymbol *s=(LSymbol *)symbol;
[636]210  if (DEFINEDP(s->m_value) && (item_type(s->m_value)!=L_OBJECT_VAR))
[2]211  {
[493]212    ((LObject *)symbol)->Print();
[2]213    lbreak("symbol already has a value, cannot instantiate an object varible");
214    exit(0);
[636]215  } else if (DEFINEDP(s->m_value))
[2]216  {
[636]217    int index = ((LObjectVar *)s->m_value)->m_index;
[2]218    if (index<tiv)
219    {
220      if (vars[index])
221      {
[124]222    lbreak("While defining object %s :\n"
223           "  var '%s' was previously defined by another\n"
224           "  with index %d, but %s has a var listed '%s' with same index\n"
225           "  try moving definition of %s before previously declared object",
[492]226           lstring_value(((LSymbol *)name)->GetName()),
227           lstring_value(((LSymbol *)symbol)->GetName()),
[124]228           index,
[492]229           lstring_value(((LSymbol *)name)->GetName()),
230           lstring_value(((LSymbol *)vars[index])->GetName()),
231           lstring_value(((LSymbol *)name)->GetName())
[124]232           );
233    exit(0);
234      } else
235      {
236    var_index[index]=tv;
237    vars[index]=symbol;
238    tv++;
[2]239      }
240    } else
241    {
242      int new_total=index+1;
[129]243      vars=(void **)realloc(vars,sizeof(void *)*new_total);
244      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
[2]245      memset(&vars[tiv],0,(new_total-tiv)*sizeof(void *));
246      memset(&var_index[tiv],0,(new_total-tiv)*sizeof(short));
247      tiv=new_total;
248
249      var_index[index]=tv;
250      vars[index]=symbol;
251      tv++;
[124]252    }
[2]253  } else  /** Nope, looks like we have to add the variable ourself and define the assesor funs */
254  {
255    /* locate a free index in the index list */
256    int free_index=tiv;
[494]257    for (int i=0; i<tiv; i++)
[2]258      if (!vars[i] && i<tiv) free_index=i;
259    if (free_index==tiv)
260    {
261      int new_total=free_index+1;
[129]262      vars=(void **)realloc(vars,sizeof(void *)*new_total);
263      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
[2]264      memset(&vars[tiv],0,(new_total-tiv)*sizeof(void *));
265      memset(&var_index[tiv],0,(new_total-tiv)*sizeof(short));
266      tiv=new_total;
267    }
268
269    /* create the var and add to var list */
[635]270    LSpace *sp = LSpace::Current;
271    LSpace::Current = &LSpace::Perm;
[2]272
273    add_c_object(symbol,free_index);
[124]274
[2]275    vars[free_index]=symbol;
276    var_index[free_index]=tv;
277    tv++;
[635]278    LSpace::Current=sp;
[2]279  }
280}
281
282
283long character_type::isa_var_name(char *name)
284{
285  int i=0;
[494]286  for (; i<TOTAL_OBJECT_VARS; i++)
[2]287  {
288    if (!strcmp(object_descriptions[i].name,name))
289      return 1;
290  }
[494]291  for (i=0; i<tiv; i++)
[492]292    if (!strcmp(lstring_value(((LSymbol *)vars[i])->GetName()),name))
[2]293      return 1;
294  return 0;
295}
296
[124]297character_type::character_type(void *args, void *name)
[2]298{
[491]299  PtrRef r2(args);
[2]300  int i;
301  ts=tv=0;
302  seq=NULL;
303  seq_syms=NULL;
304  vars=NULL;
305  var_index=NULL;
306  tiv=0;
307
[492]308  LSymbol *l_abil =   LSymbol::FindOrCreate("abilities");
309  LSymbol *l_funs =   LSymbol::FindOrCreate("funs");
310  LSymbol *l_states = LSymbol::FindOrCreate("states");
311  LSymbol *l_flags =  LSymbol::FindOrCreate("flags");
312  LSymbol *l_range =  LSymbol::FindOrCreate("range");
313  LSymbol *l_draw_range = LSymbol::FindOrCreate("draw_range");
314  LSymbol *l_fields = LSymbol::FindOrCreate("fields");
315  LSymbol *l_logo =   LSymbol::FindOrCreate("logo");
316  LSymbol *l_vars =   LSymbol::FindOrCreate("vars");
[2]317
318  memset(fun_table,0,sizeof(fun_table));     // destory all hopes of fun
319  fields=NULL;
320  cflags=0;
321  morph_mask=-1;
322  morph_power=0;
323  total_fields=0;
324  logo=-1;
325  rangex=rangey=0;
326  draw_rangex=draw_rangey=0;
327
[494]328  for (i=0; i<TOTAL_ABILITIES; i++)
[124]329    abil[i]=get_ability_default((ability)i);
[2]330  void *field=args;
[491]331  PtrRef r7(field);
[494]332  for (; field; field=CDR(field))
[2]333  {
334    void *f=CAR(CAR(field));
[491]335    PtrRef r1(f);
[124]336
[2]337    if (f==l_abil)
338    {
[636]339      LObject *l = CDR(CAR(field));
[491]340      PtrRef r4(l);
[494]341      for (i=0; i<TOTAL_ABILITIES; i++)
[2]342      {
[636]343    Cell *ab = LSymbol::FindOrCreate(ability_names[i])->Assoc(l);
[491]344    PtrRef r5(ab);
[124]345    if (!NILP(ab))
[496]346      abil[i]=lnumber_value(lcar(lcdr(ab))->Eval());
[2]347      }
348    } else if (f==l_funs)
349    {
[636]350      LObject *l = CDR(CAR(field));
[491]351      PtrRef r4(l);
[494]352      for (i=0; i<TOTAL_OFUNS; i++)
[2]353      {
[636]354    Cell *ab = LSymbol::FindOrCreate(ofun_names[i])->Assoc(l);
[491]355    PtrRef r5(ab);
[124]356    if (!NILP(ab) && lcar(lcdr(ab)))
357    fun_table[i]=lcar(lcdr(ab));
[2]358      }
359    } else if (f==l_flags)
360    {
[636]361      LObject *l = CDR(CAR(field));
[491]362      PtrRef r4(l);
[494]363      for (i=0; i<TOTAL_CFLAGS; i++)
[2]364      {
[636]365
366    Cell *ab = LSymbol::FindOrCreate(cflag_names[i])->Assoc(l);
[491]367    PtrRef r5(ab);
[496]368    if (!NILP(ab) && lcar(lcdr(ab))->Eval())
[124]369    cflags|=(1<<i);
[2]370      }
[124]371
[2]372      if (get_cflag(CFLAG_IS_WEAPON))  // if this is a weapon add to weapon array
373      {
[124]374    total_weapons++;
[129]375    weapon_types=(int *)realloc(weapon_types,sizeof(int)*total_weapons);
[124]376    weapon_types[total_weapons-1]=total_objects;
[2]377      }
378    } else if (f==l_range)
379    {
[496]380      rangex=lnumber_value(lcar(lcdr(lcar(field)))->Eval());
381      rangey=lnumber_value(lcar(lcdr(lcdr(lcar(field))))->Eval());
[2]382    } else if (f==l_draw_range)
383    {
[496]384      draw_rangex=lnumber_value(lcar(lcdr(lcar(field)))->Eval());
385      draw_rangey=lnumber_value(lcar(lcdr(lcdr(lcar(field))))->Eval());
[2]386    } else if (f==l_states)
387    {
388      void *l=CDR(CAR(field));
[491]389      PtrRef r4(l);
[2]390      char fn[100];
[496]391      strcpy(fn,lstring_value(CAR(l)->Eval())); l=CDR(l);
[2]392      while (l)
393      {
[124]394      int index;
395      void *e;
396      sequence *mem;
397      index = add_state(CAR((CAR(l))));
[496]398      e = CAR(CDR(CAR(l)))->Eval();
[124]399      mem = new sequence(fn,e,NULL);
400    seq[index]=mem;
401    l=CDR(l);
402      }
[2]403    } else if (f==l_fields)
404    {
405      void *mf=CDR(CAR(field));
[491]406      PtrRef r4(mf);
[2]407      while (!NILP(mf))
408      {
[496]409    char *real=lstring_value(lcar(lcar(mf))->Eval());
410    char *fake=lstring_value(lcar(lcdr(lcar(mf)))->Eval());
[124]411    if (!isa_var_name(real))
412    {
[493]413      ((LObject *)field)->Print();
[124]414      lbreak("fields : no such var name \"%s\"\n",name);
415      exit(0);
416    }
417    total_fields++;
[2]418
[129]419    fields=(named_field **)realloc(fields,sizeof(named_field *)*total_fields);
[124]420    fields[total_fields-1]=new named_field(real,fake);
421    mf=lcdr(mf);
[2]422      }
423    } else if (f==l_logo)
424    {
[496]425      char *fn=lstring_value(CAR(CDR(CAR(field)))->Eval());
426      char *o=lstring_value(CAR(CDR(CDR(CAR(field))))->Eval());
[123]427      logo=cache.reg(fn,o,SPEC_IMAGE,1);
[2]428    } else if (f==l_vars)
429    {
430      void *l=CDR(CAR(field));
[491]431      PtrRef r8(l);
[2]432      while (l)
433      {
[124]434    add_var(CAR(l),name);
435    l=CDR(l);
436      }
[2]437    }
438    else
439    {
[493]440      ((LObject *)lcar(field))->Print();
[4]441      lbreak("Unknown field for character definition");
[2]442      exit(0);
[124]443    }
[2]444  }
445
446  if (!seq[stopped])
447    lbreak("object (%s) has no stopped state, please define one!\n",
[492]448       lstring_value(((LSymbol *)name)->GetName()));
[2]449
450/*  char *fn=lstring_value(lcar(desc));
451  if (!fn)
452  {
453    printf("No filename given for def-character (%s)\n",name);
454    exit(0);
455  }
456  desc=lcdr(desc);  //  skip filename
457
458
[636]459  Cell *mrph = l_morph->Assoc(desc);     // check for morph info
[2]460  morph_power=0;
461  if (!NILP(mrph))
462  {
463    mrph=lcdr(mrph);
[123]464    morph_mask=cache.reg_object(fn,lcar(mrph),SPEC_IMAGE,1);
[2]465    morph_power=lnumber_value(lcar(lcdr(mrph)));
466  } else morph_mask=-1;
467
[636]468  Cell *sa = l_state_art->Assoc(desc);
[2]469  if (NILP(sa))
470  {
471    printf("missing state state art in def-character (%s)\n",name);
472    exit(0);
[124]473  }
474
[2]475  sa=lcdr(sa);   // list of state sequences
476  while (!NILP(sa))
477  {
478    int num=lnumber_value(lcar(lcar(sa)));
[124]479    if (seq[num])
[2]480      printf("Warning : state '%s' defined multiply for object %s\n"
[124]481         "          using first definition\n",state_names[num],name);
482    else
[2]483      seq[lnumber_value(lcar(lcar(sa)))]=new sequence(fn,lcar(lcdr(lcar(sa))),lcar(lcdr(lcdr(lcar(sa)))));
[124]484    sa=lcdr(sa);
[2]485  }
486
[636]487  Cell *range = l_range->Assoc(desc);
[2]488  if (!NILP(range))
489  {
490    rangex=lnumber_value(lcar(lcdr(range)));
[124]491    rangey=lnumber_value(lcar(lcdr(lcdr(range))));
492  } else
[2]493  {
494    rangex=100;
495    rangey=50;
496  }
497
498
499
500
[636]501  Cell *mf = l_fields->Assoc(desc);
[2]502  if (!NILP(mf))
503  {
504    mf=lcdr(mf);
505    total_fields=0;
506    while (!NILP(mf))
507    {
508      char *name=lstring_value(lcar(lcar(mf)));
509      int t=default_simple.total_vars(),find=-1;
[494]510      for (int i=0; find<0 && i<t; i++)
[2]511        if (!strcmp(default_simple.var_name(i),name))
[124]512      find=i;
[2]513      if (find<0)
514      {
[636]515    lprint(l_fields->Assoc(desc));
[124]516    printf("fields : no such var name \"%s\"\n",name);
517    printf("current possiblities are : \n");
[494]518    for (int i=0; i<t; i++) printf("\"%s\" ",default_simple.var_name(i));
[124]519    printf("\n");
520    exit(0);
521      }
[2]522      char *new_name=lstring_value(lcar(lcdr(lcar(mf))));
523      total_fields++;
524
[129]525      fields=(named_field **)realloc(fields,sizeof(named_field *)*total_fields);
[2]526      fields[total_fields-1]=new named_field(find,new_name);
527      mf=lcdr(mf);
528    }
529  } else total_fields=0;
530
531
[636]532  Cell *lg = l_logo->Assoc(desc);
[124]533  if (NILP(lg))
[2]534  {
535    if (get_cflag(CFLAG_IS_WEAPON))
536    {
537      lprint(desc);
538      lbreak("object must have a logo defined if it is a weapon\n"
[124]539         "example '(logo . (""art/misc.spe"" . ""big waepon""))\n");
[2]540    }
541    logo=-1;
542  }
[124]543  else
544    logo=cache.reg_object(fn,lcdr(lg),SPEC_IMAGE,1);
[2]545    */
546}
547
548
549sequence *character_type::get_sequence(character_state s)
550{
551  if (seq[s])
552    return seq[s];
553  else return seq[stopped];
554}
555
556
557character_type::~character_type()
558{
[494]559  for (int i=0; i<ts; i++)
[124]560    if (seq[i])
[2]561      delete seq[i];
[129]562  if (ts) free(seq);
[2]563
564  if (total_fields)
565  {
[494]566    for (int i=0; i<total_fields; i++)
[2]567      delete fields[i];
[129]568    free(fields);
[2]569  }
570
571  if (ts)
[129]572    free(seq_syms);
[124]573
[2]574  if (tiv)
575  {
[129]576    free(vars);
577    free(var_index);
[2]578  }
579
580
581}
582
Note: See TracBrowser for help on using the repository browser.