source: abuse/trunk/src/chars.cpp

Last change on this file was 643, checked in by Sam Hocevar, 9 years ago

imlib: refactor Event and EventHandler?.

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