source: abuse/branches/lol/src/chars.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

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