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

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

lisp: fix a confusion in the `assoc' lisp implementation usage, and
make it a LList method to avoid future breakage.

File size: 14.4 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 "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"
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
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};
48
49/*                   "start_still_jump","still_jump","still_jump_fall","end_still_jump",
50
51                   "morph_pose",
52
53                   "walking",
54
55
56                   "weapon_draw",
57                   "weapon_put_away",
58                   "weapon_fire",
59                   "weapon_end_fire",
60                   "weapon_fire_up",
61                   "weapon_end_fire_up",
62
63                   "blocking",
64                   "block_recoil",
65
66                   "turn_around",
67                   "flinch_up","flinch_down","flinch_back",
68                   "flinch_air","flinch_ground","flinch_getup","woze",
69                   "stance"
70                 } ; */
71
72
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};
79
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
88int character_type::add_state(void *symbol) // returns index into seq to use
89{
90  if (item_type(symbol)!=L_SYMBOL)
91  {
92    ((LObject *)symbol)->Print();
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    {
104      ((LObject *)symbol)->Print();
105      dprintf("expecting symbol value to be a number, instead got : ");
106      ((LObject *)val)->Print();
107      lbreak("");
108      exit(0);
109    }
110    num=lnumber_value(val);
111  } else
112  {
113    num=ts;
114    if (num<MAX_STATE) num=MAX_STATE;
115    LSpace *sp = LSpace::Current;
116    LSpace::Current = &LSpace::Perm;
117    ((LSymbol *)symbol)->SetNumber(num);
118    LSpace::Current=sp;
119  }
120
121  if (num<ts && seq[num])
122  {
123    ((LObject *)symbol)->Print();
124    lbreak("symbol has been assigned value %d, but value already in use by state %s\n"
125       "use a different symbol for this state\n",
126       lstring_value(((LSymbol *)seq_syms[num])->GetName()));
127    exit(0);
128  } else if (num>=ts)
129  {
130    seq=(sequence **)realloc(seq,sizeof(sequence *)*(num+1));
131    seq_syms=(void **)realloc(seq_syms,sizeof(void *)*(num+1));
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
157  for (i=0; i<ts; i++)
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];
169  seq[which]=new_seq;
170}
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  }
180  return LNumber::Create(current_object->lvars[t->var_index[number]]);
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  }
202  dprintf("%d",current_object->lvars[t->var_index[number]]);
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 */
209  LSymbol *s=(LSymbol *)symbol;
210  if (DEFINEDP(s->m_value) && (item_type(s->m_value)!=L_OBJECT_VAR))
211  {
212    ((LObject *)symbol)->Print();
213    lbreak("symbol already has a value, cannot instantiate an object varible");
214    exit(0);
215  } else if (DEFINEDP(s->m_value))
216  {
217    int index = ((LObjectVar *)s->m_value)->m_index;
218    if (index<tiv)
219    {
220      if (vars[index])
221      {
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",
226           lstring_value(((LSymbol *)name)->GetName()),
227           lstring_value(((LSymbol *)symbol)->GetName()),
228           index,
229           lstring_value(((LSymbol *)name)->GetName()),
230           lstring_value(((LSymbol *)vars[index])->GetName()),
231           lstring_value(((LSymbol *)name)->GetName())
232           );
233    exit(0);
234      } else
235      {
236    var_index[index]=tv;
237    vars[index]=symbol;
238    tv++;
239      }
240    } else
241    {
242      int new_total=index+1;
243      vars=(void **)realloc(vars,sizeof(void *)*new_total);
244      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
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++;
252    }
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;
257    for (int i=0; i<tiv; i++)
258      if (!vars[i] && i<tiv) free_index=i;
259    if (free_index==tiv)
260    {
261      int new_total=free_index+1;
262      vars=(void **)realloc(vars,sizeof(void *)*new_total);
263      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
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 */
270    LSpace *sp = LSpace::Current;
271    LSpace::Current = &LSpace::Perm;
272
273    add_c_object(symbol,free_index);
274
275    vars[free_index]=symbol;
276    var_index[free_index]=tv;
277    tv++;
278    LSpace::Current=sp;
279  }
280}
281
282
283long character_type::isa_var_name(char *name)
284{
285  int i=0;
286  for (; i<TOTAL_OBJECT_VARS; i++)
287  {
288    if (!strcmp(object_descriptions[i].name,name))
289      return 1;
290  }
291  for (i=0; i<tiv; i++)
292    if (!strcmp(lstring_value(((LSymbol *)vars[i])->GetName()),name))
293      return 1;
294  return 0;
295}
296
297character_type::character_type(void *args, void *name)
298{
299  PtrRef r2(args);
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
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");
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
328  for (i=0; i<TOTAL_ABILITIES; i++)
329    abil[i]=get_ability_default((ability)i);
330  void *field=args;
331  PtrRef r7(field);
332  for (; field; field=CDR(field))
333  {
334    void *f=CAR(CAR(field));
335    PtrRef r1(f);
336
337    if (f==l_abil)
338    {
339      LList *l = (LList *)CDR(CAR(field));
340      PtrRef r4(l);
341      for (i=0; i<TOTAL_ABILITIES; i++)
342      {
343    Cell *ab = l->Assoc(LSymbol::FindOrCreate(ability_names[i]));
344    PtrRef r5(ab);
345    if (!NILP(ab))
346      abil[i]=lnumber_value(lcar(lcdr(ab))->Eval());
347      }
348    } else if (f==l_funs)
349    {
350      LList *l = (LList *)CDR(CAR(field));
351      PtrRef r4(l);
352      for (i=0; i<TOTAL_OFUNS; i++)
353      {
354    Cell *ab = l->Assoc(LSymbol::FindOrCreate(ofun_names[i]));
355    PtrRef r5(ab);
356    if (!NILP(ab) && lcar(lcdr(ab)))
357    fun_table[i]=lcar(lcdr(ab));
358      }
359    } else if (f==l_flags)
360    {
361      LList *l = (LList *)CDR(CAR(field));
362      PtrRef r4(l);
363      for (i=0; i<TOTAL_CFLAGS; i++)
364      {
365
366    Cell *ab = l->Assoc(LSymbol::FindOrCreate(cflag_names[i]));
367    PtrRef r5(ab);
368    if (!NILP(ab) && lcar(lcdr(ab))->Eval())
369    cflags|=(1<<i);
370      }
371
372      if (get_cflag(CFLAG_IS_WEAPON))  // if this is a weapon add to weapon array
373      {
374    total_weapons++;
375    weapon_types=(int *)realloc(weapon_types,sizeof(int)*total_weapons);
376    weapon_types[total_weapons-1]=total_objects;
377      }
378    } else if (f==l_range)
379    {
380      rangex=lnumber_value(lcar(lcdr(lcar(field)))->Eval());
381      rangey=lnumber_value(lcar(lcdr(lcdr(lcar(field))))->Eval());
382    } else if (f==l_draw_range)
383    {
384      draw_rangex=lnumber_value(lcar(lcdr(lcar(field)))->Eval());
385      draw_rangey=lnumber_value(lcar(lcdr(lcdr(lcar(field))))->Eval());
386    } else if (f==l_states)
387    {
388      void *l=CDR(CAR(field));
389      PtrRef r4(l);
390      char fn[100];
391      strcpy(fn,lstring_value(CAR(l)->Eval())); l=CDR(l);
392      while (l)
393      {
394      int index;
395      void *e;
396      sequence *mem;
397      index = add_state(CAR((CAR(l))));
398      e = CAR(CDR(CAR(l)))->Eval();
399      mem = new sequence(fn,e,NULL);
400    seq[index]=mem;
401    l=CDR(l);
402      }
403    } else if (f==l_fields)
404    {
405      void *mf=CDR(CAR(field));
406      PtrRef r4(mf);
407      while (!NILP(mf))
408      {
409    char *real=lstring_value(lcar(lcar(mf))->Eval());
410    char *fake=lstring_value(lcar(lcdr(lcar(mf)))->Eval());
411    if (!isa_var_name(real))
412    {
413      ((LObject *)field)->Print();
414      lbreak("fields : no such var name \"%s\"\n",name);
415      exit(0);
416    }
417    total_fields++;
418
419    fields=(named_field **)realloc(fields,sizeof(named_field *)*total_fields);
420    fields[total_fields-1]=new named_field(real,fake);
421    mf=lcdr(mf);
422      }
423    } else if (f==l_logo)
424    {
425      char *fn=lstring_value(CAR(CDR(CAR(field)))->Eval());
426      char *o=lstring_value(CAR(CDR(CDR(CAR(field))))->Eval());
427      logo=cache.reg(fn,o,SPEC_IMAGE,1);
428    } else if (f==l_vars)
429    {
430      void *l=CDR(CAR(field));
431      PtrRef r8(l);
432      while (l)
433      {
434    add_var(CAR(l),name);
435    l=CDR(l);
436      }
437    }
438    else
439    {
440      ((LObject *)lcar(field))->Print();
441      lbreak("Unknown field for character definition");
442      exit(0);
443    }
444  }
445
446  if (!seq[stopped])
447    lbreak("object (%s) has no stopped state, please define one!\n",
448       lstring_value(((LSymbol *)name)->GetName()));
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
459  Cell *mrph = desc->Assoc(l_morph);     // check for morph info
460  morph_power=0;
461  if (!NILP(mrph))
462  {
463    mrph=lcdr(mrph);
464    morph_mask=cache.reg_object(fn,lcar(mrph),SPEC_IMAGE,1);
465    morph_power=lnumber_value(lcar(lcdr(mrph)));
466  } else morph_mask=-1;
467
468  Cell *sa = desc->Assoc(l_state_art);
469  if (NILP(sa))
470  {
471    printf("missing state state art in def-character (%s)\n",name);
472    exit(0);
473  }
474
475  sa=lcdr(sa);   // list of state sequences
476  while (!NILP(sa))
477  {
478    int num=lnumber_value(lcar(lcar(sa)));
479    if (seq[num])
480      printf("Warning : state '%s' defined multiply for object %s\n"
481         "          using first definition\n",state_names[num],name);
482    else
483      seq[lnumber_value(lcar(lcar(sa)))]=new sequence(fn,lcar(lcdr(lcar(sa))),lcar(lcdr(lcdr(lcar(sa)))));
484    sa=lcdr(sa);
485  }
486
487  Cell *range = desc->Assoc(l_range);
488  if (!NILP(range))
489  {
490    rangex=lnumber_value(lcar(lcdr(range)));
491    rangey=lnumber_value(lcar(lcdr(lcdr(range))));
492  } else
493  {
494    rangex=100;
495    rangey=50;
496  }
497
498
499
500
501  Cell *mf = desc->Assoc(l_fields);
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;
510      for (int i=0; find<0 && i<t; i++)
511        if (!strcmp(default_simple.var_name(i),name))
512      find=i;
513      if (find<0)
514      {
515    lprint(desc->Assoc(l_fields));
516    printf("fields : no such var name \"%s\"\n",name);
517    printf("current possiblities are : \n");
518    for (int i=0; i<t; i++) printf("\"%s\" ",default_simple.var_name(i));
519    printf("\n");
520    exit(0);
521      }
522      char *new_name=lstring_value(lcar(lcdr(lcar(mf))));
523      total_fields++;
524
525      fields=(named_field **)realloc(fields,sizeof(named_field *)*total_fields);
526      fields[total_fields-1]=new named_field(find,new_name);
527      mf=lcdr(mf);
528    }
529  } else total_fields=0;
530
531
532  Cell *lg = desc->Assoc(l_logo);
533  if (NILP(lg))
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"
539         "example '(logo . (""art/misc.spe"" . ""big waepon""))\n");
540    }
541    logo=-1;
542  }
543  else
544    logo=cache.reg_object(fn,lcdr(lg),SPEC_IMAGE,1);
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{
559  for (int i=0; i<ts; i++)
560    if (seq[i])
561      delete seq[i];
562  if (ts) free(seq);
563
564  if (total_fields)
565  {
566    for (int i=0; i<total_fields; i++)
567      delete fields[i];
568    free(fields);
569  }
570
571  if (ts)
572    free(seq_syms);
573
574  if (tiv)
575  {
576    free(vars);
577    free(var_index);
578  }
579
580
581}
582
Note: See TracBrowser for help on using the repository browser.