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

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

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

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