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

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

imlib: refactor Event and EventHandler?.

File size: 15.3 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
[642]31CharacterType **figures;
[2]32
[642]33int total_weapons = 0;
34int *weapon_types = NULL; // maps 0..total_weapons into 'real' weapon type
[2]35
[39]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"
[642]45#if 0
46    "start_still_jump", "still_jump", "still_jump_fall", "end_still_jump",
[2]47
[642]48    "morph_pose",
[2]49
[642]50    "walking",
[494]51
[642]52    "weapon_draw",
53    "weapon_put_away",
54    "weapon_fire",
55    "weapon_end_fire",
56    "weapon_fire_up",
57    "weapon_end_fire_up",
[2]58
[642]59    "blocking",
60    "block_recoil",
[494]61
[642]62    "turn_around",
63    "flinch_up", "flinch_down", "flinch_back",
64    "flinch_air", "flinch_ground", "flinch_getup", "woze",
65    "stance"
66#endif
67};
[2]68
[39]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};
[2]75
[39]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
[642]84int CharacterType::add_state(LObject *symbol) // returns index into seq to use
[2]85{
[642]86    if (item_type(symbol) != L_SYMBOL)
87    {
88        symbol->Print();
89        lbreak("is not a symbol (in def_char)");
90        exit(0);
91    }
[2]92
[642]93    LObject *val = symbol_value((LSymbol *)symbol);
[2]94
[642]95    int num;
96    if (DEFINEDP(val))
[2]97    {
[642]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);
[2]107    }
[642]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    }
[2]116
[642]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));
[2]130
[642]131        memset(&seq[ts], 0, sizeof(sequence *) * ((num + 1) - ts));
132        memset(&seq_syms[ts], 0, sizeof(LSymbol *) * ((num + 1) - ts));
[2]133
[642]134        ts = num + 1;
135    }
[2]136
[642]137    seq_syms[num] = (LSymbol *)symbol;
138    return num;
[2]139}
140
141int flinch_state(character_state state)
142{
[642]143    if (state == flinch_up || state == flinch_down)
144        return 1;
145    return 0;
[2]146}
147
[642]148int CharacterType::cache_in()    // returns false if out of cache memory
[2]149{
[642]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
[2]158    return 1;
159}
160
[642]161void CharacterType::add_sequence(character_state which, sequence *new_seq)
[2]162{
163    delete seq[which];
[642]164    seq[which] = new_seq;
[124]165}
[2]166
167void *l_obj_get(long number) // exten lisp function switches on number
168{
[642]169    CharacterType *t = figures[current_object->otype];
170    if (t->tiv <= number || !t->vars[number])
171    {
[643]172        lbreak("access : variable does not exists for this class\n");
[642]173        return 0;
174    }
175    return LNumber::Create(current_object->lvars[t->var_index[number]]);
[2]176}
177
178void l_obj_set(long number, void *arg)  // exten lisp function switches on number
179{
[642]180  CharacterType *t=figures[current_object->otype];
[2]181  if (t->tiv<=number || !t->vars[number])
182  {
[643]183    lbreak("set : variable does not exists for this class\n");
[2]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{
[642]191  CharacterType *t=figures[current_object->otype];
[2]192  if (t->tiv<=number || !t->vars[number])
193  {
[643]194    lbreak("access : variable does not exists for this class\n");
[2]195    return;
196  }
[124]197  dprintf("%d",current_object->lvars[t->var_index[number]]);
[2]198}
199
[642]200void CharacterType::add_var(void *symbol, void *name)
[2]201{
202  /* First see if the variable has been defined for another object
203     if so report a conflict if any occur */
[492]204  LSymbol *s=(LSymbol *)symbol;
[636]205  if (DEFINEDP(s->m_value) && (item_type(s->m_value)!=L_OBJECT_VAR))
[2]206  {
[493]207    ((LObject *)symbol)->Print();
[2]208    lbreak("symbol already has a value, cannot instantiate an object varible");
209    exit(0);
[636]210  } else if (DEFINEDP(s->m_value))
[2]211  {
[636]212    int index = ((LObjectVar *)s->m_value)->m_index;
[2]213    if (index<tiv)
214    {
215      if (vars[index])
216      {
[124]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",
[492]221           lstring_value(((LSymbol *)name)->GetName()),
222           lstring_value(((LSymbol *)symbol)->GetName()),
[124]223           index,
[492]224           lstring_value(((LSymbol *)name)->GetName()),
225           lstring_value(((LSymbol *)vars[index])->GetName()),
226           lstring_value(((LSymbol *)name)->GetName())
[124]227           );
228    exit(0);
229      } else
230      {
231    var_index[index]=tv;
[642]232    vars[index]=(LSymbol *)symbol;
[124]233    tv++;
[2]234      }
235    } else
236    {
237      int new_total=index+1;
[642]238      vars=(LSymbol **)realloc(vars,sizeof(LSymbol *)*new_total);
[129]239      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
[642]240      memset(&vars[tiv],0,(new_total-tiv)*sizeof(LSymbol *));
[2]241      memset(&var_index[tiv],0,(new_total-tiv)*sizeof(short));
242      tiv=new_total;
243
244      var_index[index]=tv;
[642]245      vars[index]=(LSymbol *)symbol;
[2]246      tv++;
[124]247    }
[2]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;
[494]252    for (int i=0; i<tiv; i++)
[2]253      if (!vars[i] && i<tiv) free_index=i;
254    if (free_index==tiv)
255    {
256      int new_total=free_index+1;
[642]257      vars=(LSymbol **)realloc(vars,sizeof(LSymbol *)*new_total);
[129]258      var_index=(short *)realloc(var_index,sizeof(short)*new_total);
[642]259      memset(&vars[tiv],0,(new_total-tiv)*sizeof(LSymbol *));
[2]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 */
[635]265    LSpace *sp = LSpace::Current;
266    LSpace::Current = &LSpace::Perm;
[2]267
268    add_c_object(symbol,free_index);
[124]269
[642]270    vars[free_index]=(LSymbol *)symbol;
[2]271    var_index[free_index]=tv;
272    tv++;
[635]273    LSpace::Current=sp;
[2]274  }
275}
276
277
[642]278long CharacterType::isa_var_name(char *name)
[2]279{
[642]280  for (int i=0; i<TOTAL_OBJECT_VARS; i++)
[2]281    if (!strcmp(object_descriptions[i].name,name))
282      return 1;
[642]283  for (int i=0; i<tiv; i++)
[492]284    if (!strcmp(lstring_value(((LSymbol *)vars[i])->GetName()),name))
[2]285      return 1;
286  return 0;
287}
288
[642]289CharacterType::CharacterType(LList *args, LSymbol *name)
[2]290{
[642]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;
[2]298
[642]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");
[2]308
[642]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;
[2]318
[642]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))
[2]324    {
[642]325        LObject *f=CAR(CAR(field));
326        PtrRef r1(f);
[636]327
[642]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            {
[124]356
[642]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            }
[2]362
[642]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        }
[2]435    }
436
[642]437    if (!seq[stopped])
438        lbreak("object (%s) has no stopped state, please define one!\n",
439             lstring_value(name->GetName()));
[2]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
[638]450  Cell *mrph = desc->Assoc(l_morph);     // check for morph info
[2]451  morph_power=0;
452  if (!NILP(mrph))
453  {
454    mrph=lcdr(mrph);
[123]455    morph_mask=cache.reg_object(fn,lcar(mrph),SPEC_IMAGE,1);
[2]456    morph_power=lnumber_value(lcar(lcdr(mrph)));
457  } else morph_mask=-1;
458
[638]459  Cell *sa = desc->Assoc(l_state_art);
[2]460  if (NILP(sa))
461  {
462    printf("missing state state art in def-character (%s)\n",name);
463    exit(0);
[124]464  }
465
[2]466  sa=lcdr(sa);   // list of state sequences
467  while (!NILP(sa))
468  {
469    int num=lnumber_value(lcar(lcar(sa)));
[124]470    if (seq[num])
[2]471      printf("Warning : state '%s' defined multiply for object %s\n"
[124]472         "          using first definition\n",state_names[num],name);
473    else
[2]474      seq[lnumber_value(lcar(lcar(sa)))]=new sequence(fn,lcar(lcdr(lcar(sa))),lcar(lcdr(lcdr(lcar(sa)))));
[124]475    sa=lcdr(sa);
[2]476  }
477
[638]478  Cell *range = desc->Assoc(l_range);
[2]479  if (!NILP(range))
480  {
481    rangex=lnumber_value(lcar(lcdr(range)));
[124]482    rangey=lnumber_value(lcar(lcdr(lcdr(range))));
483  } else
[2]484  {
485    rangex=100;
486    rangey=50;
487  }
488
489
490
491
[638]492  Cell *mf = desc->Assoc(l_fields);
[2]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;
[494]501      for (int i=0; find<0 && i<t; i++)
[2]502        if (!strcmp(default_simple.var_name(i),name))
[124]503      find=i;
[2]504      if (find<0)
505      {
[638]506    lprint(desc->Assoc(l_fields));
[124]507    printf("fields : no such var name \"%s\"\n",name);
508    printf("current possiblities are : \n");
[494]509    for (int i=0; i<t; i++) printf("\"%s\" ",default_simple.var_name(i));
[124]510    printf("\n");
511    exit(0);
512      }
[2]513      char *new_name=lstring_value(lcar(lcdr(lcar(mf))));
514      total_fields++;
515
[129]516      fields=(named_field **)realloc(fields,sizeof(named_field *)*total_fields);
[2]517      fields[total_fields-1]=new named_field(find,new_name);
518      mf=lcdr(mf);
519    }
520  } else total_fields=0;
521
522
[638]523  Cell *lg = desc->Assoc(l_logo);
[124]524  if (NILP(lg))
[2]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"
[124]530         "example '(logo . (""art/misc.spe"" . ""big waepon""))\n");
[2]531    }
532    logo=-1;
533  }
[124]534  else
535    logo=cache.reg_object(fn,lcdr(lg),SPEC_IMAGE,1);
[2]536    */
537}
538
539
[642]540sequence *CharacterType::get_sequence(character_state s)
[2]541{
[642]542    if (!seq[s])
543        return seq[stopped];
544
[2]545    return seq[s];
546}
547
[642]548CharacterType::~CharacterType()
[2]549{
[642]550    for (int i = 0; i < ts; i++)
551        delete seq[i];
[2]552
[642]553    if (ts)
554        free(seq);
[2]555
[642]556    if (total_fields)
557    {
558        for (int i = 0; i < total_fields; i++)
559            delete fields[i];
560        free(fields);
561    }
[124]562
[642]563    if (ts)
564        free(seq_syms);
[2]565
[642]566    if (tiv)
567    {
568        free(vars);
569        free(var_index);
570    }
[2]571}
572
Note: See TracBrowser for help on using the repository browser.