source: abuse/trunk/src/level.cpp @ 527

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

imlib: some cleaning up in trans_image before I templatise half of it.

File size: 75.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#if (defined(__MACH__) || !defined(__APPLE__))
14#include <sys/stat.h>
15#endif
16
17#include <string.h>
18#include <limits.h>
19#include <time.h>
20#include <unistd.h>
21
22#include "common.h"
23
24#include "light.h"
25#include "level.h"
26#include "game.h"
27#include "intsect.h"
28#include "lisp.h"
29#include "dprint.h"
30#include "particle.h"
31#include "objects.h"
32#include "jrand.h"
33#include "clisp.h"
34#include "status.h"
35#include "dev.h"
36#include "demo.h"
37#include "pcxread.h"
38#include "profile.h"
39#include "sbar.h"
40#include "cop.h"
41#include "nfserver.h"
42#include "lisp_gc.h"
43
44level *current_level;
45
46game_object *level::attacker(game_object *who)
47{
48  int32_t d=0x7fffffff;
49  game_object *c=NULL;
50  view *f=the_game->first_view;
51  for (; f; f=f->next)
52  {
53    if (f->focus)
54    {
55      int32_t tmp_d=abs(f->focus->x-who->x)+abs(f->focus->y-who->y);
56      if (tmp_d<d)
57      {
58    d=tmp_d;
59    c=f->focus;
60      }
61    }
62  }
63  CONDITION(c,"no attacker found");
64  return c;
65}
66
67
68
69int level::is_attacker(game_object *who)
70{
71  return who->controller()!=NULL;
72}
73
74
75game_object *level::main_character()
76{
77  return the_game->first_view->focus;
78}
79
80void level::load_fail()
81{
82  if (map_fg)    free(map_fg);   map_fg=NULL;
83  if (map_bg)    free(map_bg);   map_bg=NULL;
84  if (Name)      free(Name);     Name=NULL;
85
86  first_active=NULL;
87  view *f=player_list;
88  for (; f; f=f->next)
89    if (f->focus)
90      current_level->remove_object(f->focus);
91
92  while (first)
93  {
94    first_active=first;
95    first=first->next;
96    if (dev_cont)
97      dev_cont->notify_deleted_object(first_active);
98    delete first_active;
99  }
100
101  while (area_list)
102  {
103    area_controller *l=area_list;
104    area_list=area_list->next;
105    delete l;
106  }
107
108  last=NULL;
109  delete_panims();
110  delete_all_lights();
111
112}
113
114level::~level()
115{
116  load_fail();
117  if (attack_list) free(attack_list);
118  if (target_list) free(target_list);
119  if (block_list) free(block_list);
120  if (all_block_list) free(all_block_list);
121  if (first_name) free(first_name);
122}
123
124void level::restart()
125{
126  view *f;
127  game_object *found=NULL,*o;
128  f=the_game->first_view;
129  for (o=first; f && o; o=o->next)
130  {
131    while (f && !f->focus) f=f->next;
132    if (f)
133    {
134      if (!strcmp(object_names[o->otype],"START"))
135      {
136    if (!found) found=o;
137    f->focus->x=o->x;
138    f->focus->y=o->y;
139    f->focus->set_hp(get_ability(f->focus->otype,start_hp));
140    f->focus->set_state(stopped);
141    f=f->next;
142      }
143    }
144  }
145  while (f)
146  {
147    if (f->focus)
148    {
149      f->focus->x=found->x;
150      f->focus->y=found->y;
151      f->focus->set_hp(get_ability(f->focus->otype,start_hp));
152      f->focus->set_state(stopped);
153    }
154    f=f->next;
155  }
156}
157
158
159void level::next_focus()
160{
161/*  int i;
162  for (i=0; i<total_objs; i++)
163    if (obj[i]==the_game->first_view->focus)
164    {
165      int tries=total_objs;
166      do
167      {
168    i++;
169    if (i==total_objs)
170      i=0;
171    the_game->first_view->focus=obj[i];
172      }  while ((!the_game->first_view->focus->is_playable() ||
173         the_game->first_view->focus->hp<=0) && tries--);
174      return ;
175    }            */
176}
177
178void level::unactivate_all()
179{
180  first_active=NULL;
181  game_object *o=first;
182  attack_total=0;  // reset the attack list
183  target_total=0;
184  block_total=0;
185  all_block_total=0;
186
187  for (; o; o=o->next)
188    o->active=0;
189}
190
191
192void level::pull_actives(game_object *o, game_object *&last_active, int &t)
193{
194  int i=o->total_objects();
195  for (; i; i--)        // pull any linked object into active list
196  {
197    game_object *other=o->get_object(i-1);
198    if (!other->active)
199    {
200      other->active=1;
201      if (other->can_block())              // if object can block other player, keep a list for fast testing
202      {
203    add_block(other);
204    add_all_block(other);
205      } else if (other->hurtable())
206        add_all_block(other);
207
208      t++;
209      last_active->next_active=other;
210      last_active=other;
211      pull_actives(o,last_active,t);
212    }
213  }
214}
215
216int level::add_actives(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
217{
218  int t=0;
219  game_object *last_active=NULL;
220  if (first_active)
221    for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
222
223  game_object *o=first;
224  for (; o; o=o->next)
225  {
226    if (!o->active)
227    {
228      int32_t xr=figures[o->otype]->rangex,
229           yr=figures[o->otype]->rangey;
230
231      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
232      {
233
234    if (o->can_block())              // if object can block other player, keep a list for fast testing
235    {
236      add_block(o);
237      add_all_block(o);
238    } else if (o->hurtable())
239          add_all_block(o);
240
241
242    o->active=1;
243    t++;
244    if (!first_active)
245      first_active=o;
246    else
247          last_active->next_active=o;
248    last_active=o;
249
250    pull_actives(o,last_active,t);
251      }
252    }
253  }
254  if (last_active)
255    last_active->next_active=NULL;
256  return t;
257}
258
259
260int level::add_drawables(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
261{
262  int t=0,ft=0;
263  game_object *last_active=NULL;
264  if (first_active)
265  {
266    for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
267  } else ft=1;
268
269  game_object *o=first;
270  for (; o; o=o->next)
271  {
272    if (ft || !o->active)
273    {
274      int32_t xr=figures[o->otype]->draw_rangex,
275      yr=figures[o->otype]->draw_rangey;
276
277      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
278      {
279    t++;
280    if (!first_active)
281    first_active=o;
282    else
283    last_active->next_active=o;
284    last_active=o;
285    o->active=1;
286      } else if (ft) o->active=0;  // if this is the first pass, then mark objects not in this ranges as not active
287    }
288  }
289  if (last_active)
290    last_active->next_active=NULL;
291  return t;
292}
293
294
295view *level::make_view_list(int nplayers)
296{
297  int startable;
298  CONDITION(nplayers>0,"make_view_list with <=0 players!\n");
299  view *f=NULL;
300  int j,use_type=current_start_type;
301  figures[use_type]->cache_in();
302  game_object *o,*last_start=NULL;
303  int num=0;
304
305  for (j=0,o=first; o && j<nplayers; o=o->next)
306  {
307    if (!strcmp(object_names[o->otype],"START"))
308    {
309      f=new view(create(use_type,o->x,o->y),f,num); num++;
310      f->focus->set_controller(f);
311      add_object_after(f->focus,o);
312      j++;
313      last_start=o;
314    }
315  }
316
317  // if we couldn't find enough starts then create the rest of the players at the original start
318  startable=j;  // if we haven't created anyone yet, it's because we can't
319
320  for (; j<nplayers; j++)
321  {
322    if (startable)
323    {
324      game_object *o=create(use_type,f->focus->x,f->focus->y);
325      f=new view(o,f,num); num++;
326      f->focus->set_controller(f);
327      add_object_after(o,last_start);
328    }
329    else
330    {
331      f=new view(NULL,f,num);
332      num++;
333    }
334  }
335  return f;
336}
337
338void level::wall_push()
339{
340  int32_t sx1,sy1,sx2,sy2,xv,yv;
341  game_object *o=first_active;
342  for (; o; o=o->next_active)
343  {
344    if (o->pushable())
345    {
346      o->picture_space(sx1,sy1,sx2,sy2);
347      xv=sx1-o->x;
348      yv=0;
349      o->try_move(o->x,o->y-1,xv,yv,1);         // check for wall pushes on the left using feet
350      if (xv!=sx1-o->x)                         // is the character in the wall?
351      {
352    xv=-xv;
353    o->try_move(o->x,o->y-1,xv,yv,1);       // see how far to the right we can push the character
354    o->x+=xv;
355      } else
356      {
357    xv=sx2-o->x;
358    o->try_move(o->x,o->y-1,xv,yv,1);      // now check the right of the character for a wall
359    if (xv!=sx2-o->x)
360    {
361      xv=-xv;
362      o->try_move(o->x,o->y-1,xv,yv,1);
363      o->x+=xv;
364    }
365      }
366    }
367  }
368}
369
370
371void level::try_pushback(game_object *subject,game_object *target)
372{
373  if (subject->pushable() && target->pushable() &&
374      subject->state!=dead && target->state!=dead &&
375      subject->state!=dieing && target->state!=dieing)
376  {
377    int b1=subject->push_range(),b2=target->push_range();
378    if (abs(subject->x-target->x)<b1+b2)
379    {
380      int32_t tmove=b1+b2-abs(subject->x-target->x),xv,yv=0,xv2;
381      if (subject->x>target->x)
382        xv=tmove/2;
383      else xv=-tmove/2;
384      xv2=-xv;
385
386      subject->try_move(subject->x,subject->y,xv,yv,3);
387      subject->x+=xv;
388
389      yv=0;
390      target->try_move(target->x,target->y,xv2,yv,3);
391      target->x+=xv2;
392    }
393  }
394}
395
396/*
397void level::check_collisions()
398{
399  game_object *target,*reciever=NULL;
400  int32_t sx1,sy1,sx2,sy2,tx1,ty1,tx2,ty2,hitx,hity,
401      s_centerx,t_centerx;
402
403  for (game_object *subject=first_active; subject; subject=subject->next_active)
404  {
405    subject->picture_space(sx1,sy1,sx2,sy2);
406    s_centerx=subject->x_center();
407
408    int hit=0;
409    reciever=NULL;
410    for (target=first_active; target; target=target->next_active)
411    {
412      if (target!=subject)
413      {
414    target->picture_space(tx1,ty1,tx2,ty2);
415
416        if (!(sx2<tx1 || sx1>tx2 || sy1>ty2 || sy2<ty1))  // are they semi/overlapping?
417        {
418      try_pushback(subject,target);
419      if (subject->can_hurt(target))    // see if we can hurt him before calculating
420      {
421        t_centerx=target->x_center();
422        point_list *s_hit,*t_damage;
423
424        s_hit=subject->current_figure()->hit;
425        t_damage=target->current_figure()->damage;
426
427        unsigned char *s_dat=s_hit->data,
428        *t_dat;
429        int i,j;
430        for (i=(int)s_hit->tot-1; i>0 && !hit; i--)
431        {
432          for (t_dat=t_damage->data,j=(int)t_damage->tot-1; j>0 && !hit; j--)
433          {
434        int32_t x1,y1,x2,y2,          // define the two line segments to check
435        xp1,yp1,xp2,yp2;
436
437        xp1=target->x+target->tx(*t_dat);  t_dat++;
438        yp1=target->y+target->ty(*t_dat);  t_dat++;
439        xp2=target->x+target->tx(*t_dat);
440        yp2=target->y+target->ty(t_dat[1]);
441
442        x1=subject->x+subject->tx(s_dat[0]);
443        y1=subject->y+subject->ty(s_dat[1]);
444        x2=subject->x+subject->tx(s_dat[2]);
445        y2=subject->y+subject->ty(s_dat[3]);
446
447
448        // ok, now we know which line segemnts to check for intersection
449        // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
450        int _x2=x2,_y2=y2;
451        setback_intersect(x1, y1, x2, y2, xp1, yp1, xp2, yp2,0);
452
453
454        if (x2!=_x2 || _y2!=y2)
455        {
456          reciever=target;
457          hitx=((x1+x2)/2+(xp1+xp2)/2)/2;
458          hity=((y1+y1)/2+(yp1+yp2)/2)/2;
459        }
460          }
461          s_dat+=2;
462        }
463      }
464    }
465      }
466    }
467    if (reciever)
468    {
469      reciever->do_damage((int)subject->current_figure()->hit_damage,subject,hitx,hity,0,0);
470      subject->note_attack(reciever);
471      hit=1;
472    }
473  }
474}
475*/
476
477game_object *level::boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
478{
479  game_object *l=NULL;
480  int32_t tx1,ty1,tx2,ty2,t_centerx;
481  game_object *target=first_active;
482  game_object **blist=block_list;
483  int t=block_total;
484  for (; t; t--,blist++)
485  {
486    target=*blist;
487    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
488    {
489      target->picture_space(tx1,ty1,tx2,ty2);
490      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
491        (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
492      {
493    t_centerx=target->x_center();
494    boundary *t_damage;
495    if (target->direction>0)
496    t_damage=target->current_figure()->f_damage;
497    else
498    t_damage=target->current_figure()->b_damage;
499    unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
500    int iter=t_damage->tot-1;
501    while(iter-->0)
502    {
503      int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
504      int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
505      int32_t xp2=target->x+target->tx(*t_dat);
506      int32_t yp2=target->y+target->ty(t_dat[1]);
507
508      // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
509      if (*ins)
510      {
511        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
512        l=target;
513      }
514      else
515      {
516        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
517        l=target;
518      }
519      ins++;
520
521    }
522      }
523    }
524  }
525  return l;       // return the last person we intersected
526}
527
528
529game_object *level::all_boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
530{
531  game_object *l=NULL;
532  int32_t tx1,ty1,tx2,ty2,t_centerx;
533  game_object *target=first_active;
534  game_object **blist=all_block_list;
535  int t=all_block_total;
536  for (; t; t--,blist++)
537  {
538    target=*blist;
539    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
540    {
541      target->picture_space(tx1,ty1,tx2,ty2);
542      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
543        (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
544      {
545    t_centerx=target->x_center();
546    boundary *t_damage;
547    if (target->direction>0)
548    t_damage=target->current_figure()->f_damage;
549    else
550    t_damage=target->current_figure()->b_damage;
551    unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
552    int iter=t_damage->tot-1;
553    while(iter-->0)
554    {
555      int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
556      int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
557      int32_t xp2=target->x+target->tx(*t_dat);
558      int32_t yp2=target->y+target->ty(t_dat[1]);
559
560      // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
561      if (*ins)
562      {
563        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
564        l=target;
565      }
566      else
567      {
568        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
569        l=target;
570      }
571      ins++;
572    }
573      }
574    }
575  }
576  return l;       // return the last person we intersected
577}
578
579
580//bFILE *rcheck=NULL,*rcheck_lp=NULL;
581
582void level::interpolate_draw_objects(view *v)
583{
584  int32_t old_x,old_y;
585  current_view=v;
586
587  game_object *o=first_active;
588  for (; o; o=o->next_active)
589  {
590    old_x=o->x;
591    old_y=o->y;
592    o->x=(o->last_x+o->x)/2;
593    o->y=(o->last_y+o->y)/2;
594    o->last_x=old_x;
595    o->last_y=old_y;
596  }
597
598  for (o=first_active; o; o=o->next_active)
599    o->draw();
600
601  for (o=first_active; o; o=o->next_active)
602  {
603    o->x=o->last_x;
604    o->y=o->last_y;
605  }
606}
607
608bFILE *rcheck=NULL,*rcheck_lp=NULL;
609
610extern int sshot_fcount,screen_shot_on;
611
612int level::tick()
613{
614  game_object *o,*l=NULL,  // l is last, used for delete
615              *cur;        // cur is current object, NULL if object deletes it's self
616  int ret=1;
617
618  if (profiling())
619    profile_reset();
620
621/*  // test to see if demo is in sync
622  if (current_demo_mode()==DEMO_PLAY)
623  {
624    if (!rcheck) rcheck=open_file("rcheck","rb");
625    int32_t x=rcheck->read_uint32();
626    if (x!=rand_on)
627      dprintf("off!\n");
628  } else if (current_demo_mode()==DEMO_RECORD)
629  {
630    if (!rcheck)
631    {
632      rcheck=open_file("rcheck","wb");
633      rcheck_lp=open_file("rcheck.lp","wb");
634    }
635    rcheck->write_uint32(rand_on);
636  } else
637  {
638    if (rcheck)
639    {
640      delete rcheck;
641      rcheck=NULL;
642    }
643    if (rcheck_lp)
644    {
645      delete rcheck_lp;
646      rcheck_lp=NULL;
647    }
648  }*/
649
650  for (o=first_active; o; )
651  {
652    o->last_x=o->x;
653    o->last_y=o->y;
654    cur=o;
655    view *c=o->controller();
656    if (!(dev&SUSPEND_MODE) || c)
657    {
658      o->set_flags(o->flags()&(0xff-FLAG_JUST_HIT-FLAG_JUST_BLOCKED));
659
660      if (c)
661      {
662    area_controller *a,*smallest=NULL;
663    int32_t smallest_size=0xffffffff;
664    for (a=area_list; a; a=a->next)
665      if (o->x>=a->x && o->y>=a->y && o->x<=a->x+a->w && o->y<=a->y+a->h)
666      {
667        int32_t size=a->w*a->h;
668        if (size<smallest_size)
669        {
670          smallest=a;
671          smallest_size=size;
672        }
673      }
674
675    if (c->local_player())
676    {
677      if (!shutdown_lighting)       // should we initiate a lighting shutdown?
678      {
679        if (massive_frame_panic>30)
680        {
681          shutdown_lighting=100;
682          shutdown_lighting_value=c->ambient;
683        }
684      } else if (massive_frame_panic)  // do we need brighten towards 63?
685      {
686        if (shutdown_lighting_value<63)
687          shutdown_lighting_value++;
688      } else if (shutdown_lighting>1)        // delay for some time before turning back on
689        shutdown_lighting--;
690      else if (shutdown_lighting_value!=c->ambient) // do we need to lower light toward real ambient?
691      {
692        if (abs(shutdown_lighting_value-c->ambient)<4)
693          shutdown_lighting_value=c->ambient;
694        else
695          if (shutdown_lighting_value<c->ambient)
696              shutdown_lighting_value+=4;
697        else if (shutdown_lighting_value>c->ambient)
698          shutdown_lighting_value-=4;
699      } else shutdown_lighting=0;                    // back to normal
700    }
701
702    if (smallest)
703      c->configure_for_area(smallest);
704
705
706    o->move(c->x_suggestion,c->y_suggestion,c->b1_suggestion|(c->b2_suggestion<<1)|
707        (c->b3_suggestion<<2));
708
709    if (o->otype!=current_start_type)
710    {
711      int32_t fmp=o->fmp();
712      int reduce=figures[o->otype]->morph_power;
713      if (reduce)
714      {
715        fmp-=reduce;
716        o->add_power(fmp>>16);
717        o->set_fmp(fmp&0xffff);
718        if (o->mp()<=0)
719        o->morph_into(current_start_type,NULL,-1,9);
720      }
721    }
722
723    l=o;
724    o=o->next_active;
725      }
726      else if (!o->decide())      // if object returns 0, delete it... I don't like 0's :)
727      {
728    game_object *p=o;
729    o=o->next_active;
730    delete_object(p);
731    cur=NULL;
732      } else
733      {
734    o=o->next_active;
735    l=o;
736      }
737    } else
738    {
739      o=o->next_active;
740      l=o;
741    }
742
743    clear_tmp();
744
745    if (cur)
746    {
747      point_list *p=cur->current_figure()->hit;  // see if this character is on an attack frame
748      if (p && p->tot)
749        add_attacker(cur);               // if so add him to attack list for later collision detect
750
751      if (cur->hurtable())                    // add to target list if is hurtable
752        add_target(cur);
753
754    }
755
756  }
757  tick_panims();
758
759  check_collisions();
760//  wall_push();
761
762  set_tick_counter(tick_counter()+1);
763
764  if (sshot_fcount!=-1)
765  {
766    sshot_fcount++;
767    if ((sshot_fcount%70)==0)
768    {
769      char name[100];
770      sprintf(name,"shot%04d.pcx",screen_shot_on++);
771      write_PCX(screen,pal,name);
772    }
773  }
774
775  return ret;
776}
777
778void level::set_tick_counter(uint32_t x)
779{
780  ctick=x;
781}
782
783void level::draw_areas(view *v)
784{
785  int32_t sx1,sy1,sx2,sy2;
786  area_controller *a=area_list;
787  for (; a; a=a->next)
788  {
789    int c1,c2;
790    if (a->active)
791    {
792      c1=morph_sel_frame_color;
793      c2=wm->bright_color();
794    } else
795    {
796      c2=morph_sel_frame_color;
797      c1=wm->bright_color();
798    }
799
800    the_game->game_to_mouse(a->x,a->y,v,sx1,sy1);
801    the_game->game_to_mouse(a->x+a->w,a->y+a->h,v,sx2,sy2);
802    screen->rectangle(sx1,sy1,sx2,sy2,c1);
803    screen->bar(sx1-1,sy1-1,sx1+1,sy1+1,c2);
804    screen->bar(sx2-1,sy2-1,sx2+1,sy2+1,c2);
805  }
806}
807
808void level::draw_objects(view *v)
809{
810  current_view=v;
811  game_object *o=first_active;
812  if (dev&MAP_MODE)
813  {
814    for (; o; o=o->next_active)
815      o->map_draw();
816  } else
817  {
818    for (; o; o=o->next_active)
819      o->draw();
820  }
821
822  clear_tmp();
823}
824
825void calc_bgsize(uint16_t fgw, uint16_t  fgh, uint16_t  &bgw, uint16_t  &bgh)
826{
827  bgw=fgw/ASPECT+8;
828  bgh=fgh/ASPECT+8;
829}
830
831
832void level::set_size(int w, int h)
833{
834  if (w*h>200000)
835  {
836    the_game->show_help(symbol_str("too_big"));
837    return ;
838  }
839
840  uint16_t *new_fg,*new_bg;
841  new_fg=(uint16_t *)malloc(w*h*sizeof(int16_t));
842  memset(new_fg,0,w*h*sizeof(int16_t));
843
844  int x,y,miny=(h<fg_height)? h : fg_height,minx=(w<fg_width)? w : fg_width;
845
846  uint16_t nbw,nbh;
847  calc_bgsize(w,h,nbw,nbh);
848
849  new_bg=(uint16_t *)malloc((int)nbw*(int)nbh*sizeof(int16_t));
850  memset(new_bg,0,(int)nbw*(int)nbh*sizeof(int16_t));
851
852  for (y=0; y<miny; y++)
853    for (x=0; x<minx; x++)
854      new_fg[x+y*w]=get_fg(x,y);
855
856  miny=(nbh<bg_height) ? nbh : bg_height;
857  minx=(nbw<bg_width) ? nbw : bg_width;
858
859  for (y=0; y<miny; y++)
860    for (x=0; x<minx; x++)
861      new_bg[x+y*nbw]=get_bg(x,y);
862
863  free(map_fg);
864  free(map_bg);
865  map_fg=new_fg;
866  map_bg=new_bg;
867  fg_width=w;
868  fg_height=h;
869  bg_height=nbh;
870  bg_width=nbw;
871
872  char msg[80];
873  sprintf(msg,"Level %s size now %d %d\n",name(),foreground_width(),foreground_height());
874  the_game->show_help(msg);
875}
876
877
878int locate_var(bFILE *fp, spec_directory *sd, char *str, int size)
879{
880  spec_entry *se=sd->find(str);
881  if (se)
882  {
883    fp->seek(se->offset,0);
884    if (RC_type_size(fp->read_uint8())!=size)
885      return 0;
886    else return 1;
887  }
888  return 0;
889}
890
891
892// load objects assumes current objects have already been disposed of
893void level::old_load_objects(spec_directory *sd, bFILE *fp)
894{
895  spec_entry *se=sd->find("objects");
896  total_objs=0;
897  first=last=first_active=NULL;
898  int i,j;
899  if (se)
900  {
901    fp->seek(se->offset,0);
902    /******************************* Read debug info ******************************/
903    int16_t old_tot=fp->read_uint16();
904    uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
905    char old_name[150];
906    for (i=0; i<old_tot; i++)
907    {
908      fp->read(old_name,fp->read_uint8());    // read the name
909      for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
910      {
911    if (!strcmp(old_name,object_names[j]))
912          o_remap[i]=j;
913      }
914    }
915
916
917    /***************************** Read state names *********************************/
918    int old_stot=fp->read_uint16();
919    unsigned char *s_remap=(unsigned char *)malloc(old_stot);
920    for (i=0; i<old_stot; i++)
921    {
922      fp->read(old_name,fp->read_uint8());
923      s_remap[i]=stopped;           // non exsitant states get mapped into stopped state
924      for (j=0; j<MAX_STATE; j++)                  // see if old state exist now
925    if (!strcmp(state_names[j],old_name))
926         s_remap[i]=j;
927    }
928    total_objs=fp->read_uint32();
929
930    se=sd->find("type");
931    if (se)
932    {
933      fp->seek(se->offset,0);
934      last=NULL;
935      if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
936      {
937    for (i=0; i<total_objs; i++)
938    {
939      uint16_t t=fp->read_uint16();
940      game_object *p=new game_object(o_remap[t],1);
941      clear_tmp();
942      if (!first) first=p; else last->next=p;
943      last=p; p->next=NULL;
944    }
945
946
947    se=sd->find("state");
948    if (se)
949    {
950      fp->seek(se->offset,0);
951      if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
952      {
953        game_object *l=first;
954        for (i=0; i<total_objs; i++,l=l->next)
955        {
956          character_state s=(character_state)s_remap[fp->read_uint16()];
957          if (l->otype!=0xffff)
958          {
959        if (l->has_sequence((character_state)s))
960          l->state=s;
961        else l->state=stopped;
962        l->current_frame=0;
963          }
964        }
965      }
966    }
967
968    int frame_var=0;
969    int i=0;
970    for (; i<TOTAL_OBJECT_VARS; i++)
971      if (!strcmp(object_descriptions[i].name,"cur_frame"))
972        frame_var=i;
973
974    int j=0;
975    for (; j<default_simple.total_vars(); j++)
976    {
977      spec_entry *se=sd->find(object_descriptions[j].name);
978      if (se)
979      {
980        fp->seek(se->offset,0);
981        int t=object_descriptions[j].type;
982        if (fp->read_uint8()!=t)
983          dprintf("Warning : load level -> var '%s' size changed\n");
984        else
985        {
986          game_object *f=first;
987          for (; f; f=f->next)
988          {
989        switch (t)
990        {
991          case RC_8 : f->set_var(j,fp->read_uint8()); break;
992          case RC_16 : f->set_var(j,fp->read_uint16()); break;
993          case RC_32 : f->set_var(j,fp->read_uint32()); break;
994        }
995
996        // check to make sure the frame number is not out of bounds from the time
997        // it was last saved
998        if (j==frame_var)
999        {
1000          if (f->otype!=0xffff && f->current_frame>=
1001              figures[f->otype]->get_sequence(f->state)->length())
1002            f->current_frame=0;
1003        }
1004          }
1005        }
1006      } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1007    }
1008      }
1009    }
1010
1011    free(o_remap);
1012    free(s_remap);
1013  }
1014
1015}
1016
1017
1018// load objects assumes current objects have already been disposed of
1019void level::load_objects(spec_directory *sd, bFILE *fp)
1020{
1021  spec_entry *se=sd->find("object_descripitions");
1022  total_objs=0;
1023  first=last=first_active=NULL;
1024  int i,j;
1025  if (!se)
1026  {
1027    old_load_objects(sd,fp);
1028    return ;
1029  }
1030  else if (se)
1031  {
1032    fp->seek(se->offset,0);
1033    int16_t old_tot=fp->read_uint16();
1034    se=sd->find("describe_names");
1035    if (!se || !old_tot)
1036      return ;
1037
1038    uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
1039    uint16_t *o_backmap=(uint16_t *)malloc(total_objects * 2);
1040    memset(o_backmap,0xff,total_objects*2);
1041    char old_name[150];
1042    for (i=0; i<old_tot; i++)
1043    {
1044      fp->read(old_name,fp->read_uint8());    // read the name
1045      for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
1046      {
1047    if (!strcmp(old_name,object_names[j]))
1048    {
1049          o_remap[i]=j;
1050      o_backmap[j]=i;
1051    }
1052      }
1053    }
1054
1055    se=sd->find("describe_states");
1056    if (!se) { free(o_remap); free(o_backmap); return ; }
1057    int16_t **s_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1058    int16_t *s_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1059    fp->seek(se->offset,0);
1060    int i=0;
1061    for (; i<old_tot; i++)
1062    {
1063      int16_t t=fp->read_uint16();
1064      s_remap_totals[i]=t;
1065      if (t)
1066      {
1067        s_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1068    int j=0;
1069    for (; j<t; j++)
1070      *(s_remap[i]+j)=stopped;    // if no remap found, then go to stopped state
1071      }
1072      else s_remap[i]=0;
1073
1074      int j=0;
1075      for (; j<t; j++)
1076      {
1077    fp->read(old_name,fp->read_uint8());
1078    int new_type=o_remap[i];
1079    if (new_type<total_objects)     // make sure old object still exsist
1080    {
1081      int k=0;
1082      for (; k<figures[new_type]->ts; k++)
1083      {
1084        if (figures[new_type]->seq[k] &&
1085           !strcmp(lstring_value(((LSymbol *)figures[new_type]->seq_syms[k])->GetName()),old_name))
1086        *(s_remap[i]+j)=k;
1087      }
1088    }
1089      }
1090    }
1091
1092    int16_t **v_remap=NULL;
1093    int16_t *v_remap_totals=NULL;
1094    int load_vars=1;
1095    se=sd->find("describe_lvars");
1096    if (se)
1097    {
1098      v_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1099      v_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1100
1101      fp->seek(se->offset,0);
1102      int i=0;
1103      for (; i<old_tot; i++)
1104      {
1105    int16_t t=fp->read_uint16();
1106    v_remap_totals[i]=t;
1107    if (t)
1108    {
1109      v_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1110      memset(v_remap[i],0xff,t*sizeof(int16_t));
1111    } else { v_remap[i]=NULL; }
1112    int j=0;
1113    for (; j<t; j++)
1114    {
1115      fp->read(old_name,fp->read_uint8());
1116      int new_type=o_remap[i];
1117      if (new_type!=0xffff)        // make sure old object still exsist
1118      {
1119        int k=0;
1120        for (; k<figures[new_type]->tiv; k++)
1121        {
1122          if (figures[new_type]->vars[k])
1123          {
1124        if (!strcmp(lstring_value(((LSymbol *)figures[new_type]->vars[k])->GetName()),old_name))
1125          *(v_remap[i]+j)=figures[new_type]->var_index[k];
1126          }
1127        }
1128      }
1129    }
1130      }
1131      load_vars=1;
1132    }
1133
1134    se=sd->find("object_list");
1135    if (se)
1136    {
1137      total_objs=fp->read_uint32();
1138
1139      se=sd->find("type");
1140      if (se)
1141      {
1142    fp->seek(se->offset,0);
1143    last=NULL;
1144    if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
1145    {
1146      int i=0;
1147      for (; i<total_objs; i++)
1148      {
1149        uint16_t t=fp->read_uint16();
1150        game_object *p=new game_object(o_remap[t],1);
1151        clear_tmp();
1152        if (!first) first=p; else last->next=p;
1153        last=p; p->next=NULL;
1154      }
1155
1156      se=sd->find("state");
1157      if (se)
1158      {
1159        fp->seek(se->offset,0);
1160        if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
1161        {
1162          game_object *l=first;
1163          for (i=0; i<total_objs; i++,l=l->next)
1164          {
1165        int st=fp->read_uint16();
1166        if (l->otype==0xffff)
1167          l->state=stopped;
1168        else
1169        {
1170          character_state s=(character_state)(*(s_remap[o_backmap[l->otype]]+st));
1171          if (l->has_sequence((character_state)s))
1172                l->state=s;
1173          else l->state=stopped;
1174          l->current_frame=0;
1175        }
1176          }
1177        }
1178      }
1179
1180      se=sd->find("lvars");
1181      if (se && load_vars)
1182      {
1183        fp->seek(se->offset,0);
1184        int abort=0;
1185        game_object *o=first;
1186        for (; o && !abort; o=o->next)
1187        {
1188          int16_t ot=fp->read_uint16();
1189          int k=0;
1190          for (; k<ot; k++)
1191          {
1192        if (fp->read_uint8()!=RC_32) abort=1;
1193        else
1194        {
1195          int32_t v=fp->read_uint32();
1196          if (o->otype!=0xffff)     // non-exstant object
1197          {
1198            int remap=*(v_remap[o_backmap[o->otype]]+k);
1199            if (remap!=-1 && figures[o->otype]->tiv>=k)
1200            {
1201              o->lvars[remap]=v;
1202            }
1203          }
1204        }
1205          }
1206        }
1207      }
1208
1209      int frame_var=0;
1210      for (i=0; i<TOTAL_OBJECT_VARS; i++)
1211        if (!strcmp(object_descriptions[i].name,"cur_frame"))
1212          frame_var=i;
1213
1214
1215      int j=0;
1216      for (; j<default_simple.total_vars(); j++)
1217      {
1218        spec_entry *se=sd->find(object_descriptions[j].name);
1219        if (se)
1220        {
1221          fp->seek(se->offset,0);
1222          int t=object_descriptions[j].type;
1223          if (fp->read_uint8()!=t)
1224            dprintf("Warning : load level -> var '%s' size changed\n");
1225          else
1226          {
1227        game_object *f=first;
1228        for (; f; f=f->next)
1229        {
1230          switch (t)
1231          {
1232            case RC_8 :
1233            { f->set_var(j,fp->read_uint8()); } break;
1234            case RC_16 :
1235            { f->set_var(j,fp->read_uint16()); } break;
1236            case RC_32 :
1237            { f->set_var(j,fp->read_uint32()); } break;
1238          }
1239
1240          // check to make sure the frame number is not out of bounds from the time
1241          // it was last saved
1242          if (j==frame_var)
1243          {
1244            if (f->otype!=0xffff && f->current_frame>=
1245            figures[f->otype]->get_sequence(f->state)->length())
1246            f->current_frame=0;
1247          }
1248        }
1249          }
1250        } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1251      }
1252    }
1253      }
1254    }
1255
1256    int k=0;
1257    for (; k<old_tot; k++)
1258    {
1259      if (s_remap_totals[k])
1260        free(s_remap[k]);
1261    }
1262
1263    int l=0;
1264    for (; l<old_tot; l++)
1265    {
1266      if (v_remap_totals[l])
1267        free(v_remap[l]);
1268    }
1269    free(v_remap_totals);
1270    free(s_remap_totals);
1271    free(o_remap);
1272    free(o_backmap);
1273    free(s_remap);
1274    free(v_remap);
1275  }
1276
1277}
1278
1279level::level(spec_directory *sd, bFILE *fp, char const *lev_name)
1280{
1281  spec_entry *e;
1282  area_list=NULL;
1283
1284  attack_list=NULL;
1285  attack_list_size=attack_total=0;
1286
1287  target_list=NULL;
1288  target_list_size=target_total=0;
1289
1290  block_list=NULL;
1291  block_list_size=block_total=0;
1292
1293  all_block_list=NULL;
1294  all_block_list_size=all_block_total=0;
1295  first_name=NULL;
1296
1297  the_game->need_refresh();
1298
1299  char cmd[100];
1300  sprintf(cmd,symbol_str("loading"),lev_name);
1301  stack_stat stat(cmd);
1302  Name = strdup(lev_name);
1303
1304  e=sd->find("first name");
1305  if (e)
1306  {
1307    fp->seek(e->offset,0);
1308    int len=fp->read_uint8();   // read the length of the string
1309    first_name=(char *)malloc(len);
1310    fp->read(first_name,len);    // read the string
1311  } else
1312  {
1313    first_name = strdup(Name);
1314  }
1315
1316  e=sd->find("fgmap");
1317  int no_fg=0,no_bg=0;
1318
1319  if (e)
1320  {
1321    fp->seek(e->offset,0);
1322    fg_width=fp->read_uint32();
1323    fg_height=fp->read_uint32();
1324    map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1325    fp->read((char *)map_fg,2*fg_width*fg_height);
1326    int t=fg_width*fg_height;
1327    uint16_t *map=map_fg;
1328    while (t) { *map=lstl(*map); map++; t--; }
1329  } else
1330  {
1331    the_game->show_help("Warning foreground map missing");
1332    no_fg=1;
1333  }
1334  stat_man->update(5);
1335
1336  e=sd->find("bgmap");
1337  if (e)
1338  {
1339    fp->seek(e->offset,0);
1340    bg_width=fp->read_uint32();
1341    bg_height=fp->read_uint32();
1342    map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1343    fp->read((char *)map_bg,2*bg_width*bg_height);
1344    int t=bg_width*bg_height;
1345    uint16_t *map=map_bg;
1346    while (t) { *map=lstl(*map); map++; t--; }
1347  } else
1348  {
1349    the_game->show_help("Warning background map missing");
1350    no_bg=1;
1351  }
1352
1353  if (no_fg && !no_bg)
1354  {
1355    fg_width=bg_width;
1356    fg_height=bg_height;
1357    map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1358    memset(map_fg,0,2*fg_width*fg_height);
1359  }
1360
1361  if (no_bg)
1362  {
1363    bg_width=fg_width/8+8;
1364    bg_height=fg_height/8+8;
1365    map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1366    memset(map_bg,0,2*bg_width*bg_height);
1367  }
1368  stat_man->update(10);
1369
1370  /***************** Check map for non exsistant tiles **************************/
1371  int32_t i,w;
1372  uint16_t *m;
1373  spec_entry *load_all=sd->find("player_info");
1374  for (i=0,w=fg_width*fg_height,m=map_fg; i<w; i++,m++)
1375  {
1376    if (!load_all)
1377      (*m)=(*m)&(~0x8000);    // clear the has-seen bit on the tile
1378
1379    if (fgvalue(*m)>=nforetiles || foretiles[fgvalue(*m)]<0)
1380      *m=0;
1381  }
1382
1383  for (i=0,w=bg_width*bg_height,m=map_bg; i<w; i++,m++)
1384  {
1385    if ( (bgvalue(*m)>=nbacktiles) || backtiles[bgvalue(*m)]<0)
1386       *m=0;
1387  }
1388
1389  load_options(sd,fp);
1390  stat_man->update(15);
1391
1392//  first=first_active=last=NULL;
1393  load_objects(sd,fp);
1394  stat_man->update(25);
1395
1396  object_node *players,*objs;
1397  players=make_player_onodes();
1398  objs=make_not_list(players);
1399
1400
1401
1402  read_lights(sd,fp,lev_name);
1403  load_links(fp,sd,objs,players);
1404  int players_got_loaded=load_player_info(fp,sd,objs);
1405
1406
1407  game_object *l=first;
1408  for (; l; )
1409  {
1410    game_object *p=l;
1411    l=l->next;
1412    if (p->otype==0xffff || p->x<0 || p->y<0)
1413      delete_object(p);
1414  }
1415
1416  load_cache_info(sd,fp);
1417
1418  if (!players_got_loaded)
1419  {
1420    level *old=current_level;
1421    current_level=this;
1422
1423    object_node *list=NULL;
1424    list=make_not_list(list);     // create a list of the object list in case objects change positions
1425
1426    object_node *ln=list;
1427    for (; ln; ln=ln->next)
1428      ln->me->reload_notify();
1429    delete_object_list(list);
1430
1431    current_level=old;
1432
1433    insert_players();
1434  }
1435
1436  delete_object_list(players);
1437  delete_object_list(objs);
1438
1439}
1440
1441
1442/*
1443   [object_descriptions] 2 total_type
1444   for(1..total_types)
1445   {
1446     ["object_names"]  1,(name)
1447
1448     ["object_states"]  2(total),<2=number,1,name>
1449
1450     ["object_lvars"]   2(total),<1(type),1,name>
1451   }
1452
1453  [object_list]
1454   4 total_objects
1455   for(1..total_objects)
1456   {
1457     ["type"]
1458     ["state"]
1459     ["lvars"]
1460     ...
1461   }
1462
1463*/
1464
1465
1466void get_prof_assoc_filename(char *filename, char *prof_filename)
1467{
1468  char *s1,*s2,*dot=NULL;
1469  for (s1=filename,s2=prof_filename,dot=NULL; *s1; s1++,s2++)
1470  {
1471    *s2=*s1;
1472    if (*s1=='.') dot=s2;
1473  }
1474  if (dot) s2=dot+1;
1475
1476  *(s2++)='c';
1477  *(s2++)='p';
1478  *(s2++)='f';
1479  *s2=0;
1480}
1481
1482void level::level_loaded_notify()
1483{
1484  char *n;
1485  if (first_name)
1486    n=first_name;
1487  else
1488    n=name();
1489  if (strstr(n,"levels/level"))
1490  {
1491    char nm[100];
1492    sprintf(nm,"music/abuse%c%c.hmi",n[12],n[13]);
1493    bFILE *fp=open_file(nm,"rb");
1494    if (fp->open_failure())
1495    {
1496      delete fp;
1497    }
1498    else
1499    {
1500      if (current_song) { current_song->stop(); delete current_song; }
1501
1502      delete fp;
1503      current_song=new song(nm);
1504      current_song->play(music_volume);
1505    }
1506  }
1507
1508/*  if (DEFINEDP(symbol_function(l_level_loaded)))
1509  {
1510    int sp=current_space;
1511    current_space=PERM_SPACE;
1512
1513    void *arg_list=NULL;
1514    PtrRef r1(arg_list);
1515    push_onto_list(LString::Create(n),arg_list);
1516    ((LSymbol *)l_level_loaded)->EvalFunction(arg_list);
1517
1518    current_space=sp;
1519  } */
1520}
1521
1522
1523bFILE *level::create_dir(char *filename, int save_all,
1524             object_node *save_list, object_node *exclude_list)
1525{
1526  spec_directory sd;
1527  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"Copyright 1995 Crack dot Com, All Rights reserved",NULL,0,0));
1528  if (first_name)
1529    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"first name",NULL,strlen(first_name)+2,0));
1530
1531
1532
1533  sd.add_by_hand(new spec_entry(SPEC_GRUE_FGMAP,"fgmap",NULL,4+4+fg_width*fg_height*2,0));
1534  sd.add_by_hand(new spec_entry(SPEC_GRUE_BGMAP,"bgmap",NULL,4+4+bg_width*bg_height*2,0));
1535  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"bg_scroll_rate",NULL,1+4*4,0));
1536
1537  int ta=0;
1538  area_controller *a=area_list;
1539  for (; a; a=a->next) ta++;
1540
1541  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"area_list.v1",NULL,1+ta*(4*11)+4,0));
1542
1543  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"tick_counter",NULL,1+4,0));
1544
1545
1546
1547  // how many object types are we goint to save, use a short to specify how many
1548  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_descripitions",NULL,2,0));
1549
1550
1551  int size=0;
1552  int i=0;
1553  for (; i<total_objects; i++)       // now save the names of the objects so if ordering
1554    size+=1+strlen(object_names[i])+1;    // changes in future versions we can adjust in load
1555  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_names",NULL,size,0));
1556
1557
1558  size=0;
1559  for (i=0; i<total_objects; i++)
1560  {
1561    size+=2;  // total number of states
1562    int j=0;
1563    for (; j<figures[i]->ts; j++)
1564      if (figures[i]->seq[j])
1565        size+=1+strlen(lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName()))+1;
1566  }
1567  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_states",NULL,size,0));
1568
1569
1570
1571  size=0;
1572  for (i=0; i<total_objects; i++)
1573  {
1574    size+=2;  // total number of variables
1575    int j=0;
1576    for (; j<figures[i]->tiv; j++)
1577      if (figures[i]->vars[j])
1578        size+=1+strlen(lstring_value(((LSymbol *)figures[i]->vars[j])->GetName()))+1;
1579  }
1580  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_lvars",NULL,size,0));
1581
1582
1583
1584  // how many objects are we goint to save, use a int32_t to specify how many
1585  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_list",NULL,4,0));
1586
1587  int32_t t=0;
1588  object_node *o=save_list;
1589  for (; o; o=o->next)
1590    t++;
1591
1592  // type and state aren't normal records because they will be remapped on loading
1593  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"type",NULL,1+2*t,0));
1594  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"state",NULL,1+2*t,0));
1595
1596
1597  // now save all the lvars for each object
1598  for (size=0,o=save_list; o; o=o->next)
1599    size+=figures[o->me->otype]->tv*5+2;
1600  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"lvars",NULL,size,0));
1601
1602
1603  for (i=0; i<TOTAL_OBJECT_VARS; i++)
1604    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,object_descriptions[i].name,NULL,1+
1605              RC_type_size(object_descriptions[i].type)*t,0));
1606
1607  add_light_spec(&sd,Name);
1608
1609
1610  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_links",NULL,1+4+total_object_links(save_list)*8,0));
1611  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"light_links",NULL,1+4+total_light_links(save_list)*8,0));
1612
1613  if (save_all)
1614  {
1615    t=0;
1616    view *v=player_list;
1617    for (; v; v=v->next) t++;
1618    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_info",NULL,t*4+4,0));
1619
1620    int tv=total_view_vars();
1621    int i=0;
1622    for (; i<tv; i++)
1623      sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,get_view_var_name(i),NULL,1+4*t,0));
1624    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"random_start",NULL,5,0));
1625
1626    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"weapon_array",NULL,1+4+total_weapons*4*t,0));
1627
1628    int name_len=0;
1629    for (v=player_list; v; v=v->next)
1630      name_len+=strlen(v->name)+2;
1631    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_names",NULL,name_len,0));
1632
1633    sd.add_by_hand(new spec_entry(SPEC_IMAGE,"thumb nail",NULL,4+160*(100+wm->font()->height()*2),0));
1634  }
1635
1636  sd.calc_offsets();
1637
1638  return sd.write(filename);
1639}
1640
1641void scale_put(image *im, image *screen, int x, int y, short new_width, short new_height);
1642
1643void level::write_thumb_nail(bFILE *fp, image *im)
1644{
1645  image *i = new image(vec2i(160, 100 + wm->font()->height() * 2));
1646  i->clear();
1647  scale_put(im,i,0,0,160,100);
1648  if (first_name)
1649    wm->font()->put_string(i,80-strlen(first_name)*wm->font()->width()/2,100,first_name);
1650
1651  time_t t;
1652  t=time(NULL);
1653  char buf[80];
1654
1655  strftime(buf,80,"%T %A %B %d",localtime(&t));
1656  wm->font()->put_string(i,80-strlen(buf)*wm->font()->width()/2,100+wm->font()->height(),buf);
1657
1658  fp->write_uint16(i->Size().x);
1659  fp->write_uint16(i->Size().y);
1660
1661  i->Lock();
1662  for(int y = 0; y < i->Size().y; y++)
1663    fp->write(i->scan_line(y),i->Size().x);
1664  i->Unlock();
1665
1666  delete i;
1667}
1668
1669void level::write_player_info(bFILE *fp, object_node *save_list)
1670{
1671  int32_t t=0;
1672  view *v=player_list;
1673  for (; v; v=v->next) t++;
1674  fp->write_uint32(t);
1675
1676  for (v=player_list; v; v=v->next)
1677    fp->write_uint32(object_to_number_in_list(v->focus,save_list));
1678
1679  int tv=total_view_vars();
1680  int i=0;
1681  for (; i<tv; i++)
1682  {
1683    fp->write_uint8(RC_32);
1684    for (v=player_list; v; v=v->next)
1685      fp->write_uint32(v->get_view_var_value(i));
1686  }
1687
1688  fp->write_uint8(RC_32);
1689  fp->write_uint32(rand_on);
1690
1691  fp->write_uint8(RC_32);
1692  fp->write_uint32(total_weapons);
1693  for (v=player_list; v; v=v->next)
1694    for (i=0; i<total_weapons; i++)
1695      fp->write_uint32(v->weapons[i]);
1696
1697  for (v=player_list; v; v=v->next)
1698  {
1699    int len=strlen(v->name)+1;
1700    fp->write_uint8(len);
1701    fp->write(v->name,len);
1702  }
1703}
1704
1705
1706int level::load_player_info(bFILE *fp, spec_directory *sd, object_node *save_list)
1707{
1708  int ret;
1709  spec_entry *se=sd->find("player_info");
1710  if (se)
1711  {
1712    fp->seek(se->offset,0);
1713
1714    int set_first_view=0;
1715    if (the_game->first_view==player_list) set_first_view=1;
1716    int my_player_number=-1;
1717
1718    view *v=player_list;
1719    for (; v; v=v->next)
1720    { v->suggest.send_view=0;
1721      v->suggest.send_weapon_change=0;
1722    }
1723
1724    for (v=player_list; v; v=v->next)
1725      if (v->local_player())
1726         my_player_number=v->player_number;
1727
1728    while (player_list)    // delete all of the views (they will get recreated)
1729    {
1730      v=player_list;
1731      if (v->focus)
1732      {
1733        if (v->focus->controller())
1734         v->focus->set_controller(NULL);
1735    delete v->focus;
1736      }
1737
1738      player_list=player_list->next;
1739      delete v;
1740    }
1741
1742    int32_t total_players=fp->read_uint32();
1743    view *last=NULL;
1744    int i=0;
1745    for (; i<total_players; i++)
1746    {
1747      game_object *o=number_to_object_in_list(fp->read_uint32(),save_list);
1748      v=new view(o,NULL,0);
1749      if (o) o->set_controller(v);
1750      if (player_list)
1751        last->next=v;
1752      else player_list=v;
1753      last=v;
1754    }
1755    if (set_first_view)
1756      the_game->first_view=player_list;
1757
1758    for (i=0; i<total_view_vars(); i++)
1759    {
1760      char const *find_name = get_view_var_name(i);
1761      se=sd->find(find_name);
1762
1763      if (se)
1764      {
1765    fp->seek(se->offset,0);
1766    if (fp->read_uint8()==RC_32)
1767    {
1768      for (v=player_list; v; v=v->next)
1769            v->set_view_var_value(i,fp->read_uint32());
1770    }
1771      } else
1772      {
1773    for (v=player_list; v; v=v->next)
1774        v->set_view_var_value(i,0);
1775      }
1776    }
1777
1778    se=sd->find("random_start");      // start of index into random table
1779    if (se)
1780    {
1781      fp->seek(se->offset,0);
1782      if (fp->read_uint8()==RC_32)
1783        rand_on=fp->read_uint32();
1784    } else rand_on=0;
1785
1786    se=sd->find("weapon_array");
1787    if (se)
1788    {
1789      fp->seek(se->offset,0);
1790      if (fp->read_uint8()==RC_32)
1791      {
1792    int32_t m=fp->read_uint32();  // read how many weapons exsisted when last saved
1793    int i;
1794    for (v=player_list; v; v=v->next)
1795    {
1796      for (i=0; i<m; i++)
1797      {
1798        int32_t x=fp->read_uint32();
1799        if (i<total_weapons)
1800        {
1801          v->weapons[i]=x;
1802          v->last_weapons[i]=x;
1803        }
1804      }
1805    }
1806      }
1807    }  else
1808    {
1809      for (v=player_list; v; v=v->next)
1810      {
1811    memset(v->last_weapons,0xff,total_weapons*sizeof(int32_t));
1812    memset(v->weapons,0xff,total_weapons*sizeof(int32_t));
1813      }
1814    }
1815
1816    se=sd->find("player_names");
1817    if (se)
1818    {
1819      fp->seek(se->offset,0);
1820      for (v=player_list; v; v=v->next)
1821      {
1822    uint8_t len=fp->read_uint8();
1823    fp->read(v->name,len);
1824      }
1825    }
1826
1827    ret=1;
1828    recalc_local_view_space();
1829
1830  } else
1831  {
1832    LSymbol *fun = LSymbol::FindOrCreate("set_player_defaults");
1833    if (DEFINEDP(fun->GetFunction()))
1834    {
1835      view *f;
1836      game_object *o=current_object;
1837      for (f=player_list; f; f=f->next)
1838      {
1839    if (f->focus)
1840    {
1841      current_object=f->focus;
1842      void *m=mark_heap(TMP_SPACE);
1843      fun->EvalFunction(NULL);
1844      restore_heap(m,TMP_SPACE);
1845    }
1846      }
1847      current_object=o;
1848    }
1849    ret=0;
1850  }
1851
1852  view *vw;
1853  for (vw=player_list; vw; vw=vw->next)
1854  {
1855    if (total_weapons && !vw->has_weapon(vw->current_weapon))
1856    {
1857      vw->suggest.send_weapon_change=1;
1858      vw->suggest.new_weapon=0;
1859    }
1860  }
1861
1862  return ret;
1863}
1864
1865
1866void level::write_objects(bFILE *fp, object_node *save_list)
1867{
1868  // record information in the file about what the data structures look like
1869  // right now, so if they change later, they don't get get screwed up
1870  fp->write_uint16(total_objects);   // mark how many objects we know about right now
1871
1872  int i=0;
1873  for (; i<total_objects; i++)   // loop through all the object types we know of
1874  {
1875    fp->write_uint8(strlen(object_names[i])+1);                    // sizeof name
1876    fp->write(object_names[i],strlen(object_names[i])+1);      // write object name
1877  }
1878
1879
1880  // write state numbers and names for each object
1881  for (i=0; i<total_objects; i++)
1882  {
1883    int total=0;
1884    int j=0;
1885    for (; j<figures[i]->ts; j++)
1886      if (figures[i]->seq[j]) total++;
1887    fp->write_uint16(total);
1888
1889    for (j=0; j<figures[i]->ts; j++)
1890      if (figures[i]->seq[j])
1891      {
1892    char *state_name=lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName());
1893    fp->write_uint8(strlen(state_name)+1);
1894    fp->write(state_name,strlen(state_name)+1);
1895      }
1896  }
1897
1898
1899  // write object lvar names
1900  for (i=0; i<total_objects; i++)
1901  {
1902    fp->write_uint16(figures[i]->tv);
1903    int j,x;
1904
1905    for (x=0; x<figures[i]->tv; x++)
1906    {
1907      for (j=0; j<figures[i]->tiv; j++)
1908      {
1909        if (figures[i]->vars[j] && figures[i]->var_index[j]==x)
1910    {
1911      char *var_name=lstring_value(((LSymbol *)figures[i]->vars[j])->GetName());
1912      fp->write_uint8(strlen(var_name)+1);
1913      fp->write(var_name,strlen(var_name)+1);
1914    }
1915      }
1916    }
1917  }
1918
1919  int32_t t=0;
1920  object_node *o=save_list;
1921  for (; o; o=o->next) t++;
1922  fp->write_uint32(t);
1923
1924
1925  fp->write_uint8(RC_16);                                    // save type info for each record
1926  for (o=save_list; o; o=o->next) fp->write_uint16(o->me->type());
1927
1928  fp->write_uint8(RC_16);                                    // save state info for each record
1929  for (o=save_list; o; o=o->next) fp->write_uint16(o->me->reduced_state());
1930
1931  for (o=save_list; o; o=o->next)                            // save lvars
1932  {
1933    fp->write_uint16(figures[o->me->otype]->tv);
1934    for (i=0; i<figures[o->me->otype]->tv; i++)
1935    {
1936      fp->write_uint8(RC_32);                           // for now the only type allowed is int32_t
1937      fp->write_uint32(o->me->lvars[i]);
1938    }
1939  }
1940
1941  for (i=0; i<default_simple.total_vars(); i++)
1942  {
1943    int t=object_descriptions[i].type;
1944    fp->write_uint8(t);
1945    for (o=save_list; o; o=o->next)
1946    {
1947      switch (t)
1948      {
1949    case RC_8 :
1950    { fp->write_uint8(o->me->get_var(i)); } break;
1951    case RC_16 :
1952    { fp->write_uint16(o->me->get_var(i)); } break;
1953    case RC_32 :
1954    { fp->write_uint32(o->me->get_var(i)); } break;
1955      }
1956    }
1957  }
1958}
1959
1960
1961int32_t level::total_object_links(object_node *list)
1962{
1963  int32_t tl=0;
1964  for (object_node *o=list; o; o=o->next)
1965    tl+=o->me->total_objects();
1966  return tl;
1967}
1968
1969int32_t level::total_light_links(object_node *list)
1970{
1971  int32_t tl=0;
1972  for (object_node *o=list; o; o=o->next)
1973    tl+=o->me->total_lights();
1974  return tl;
1975}
1976
1977void level::write_links(bFILE *fp, object_node *save_list, object_node *exclude_list)
1978{
1979  fp->write_uint8(RC_32);
1980  fp->write_uint32(total_object_links(save_list));
1981
1982  int x=1;
1983  object_node *o=save_list;
1984
1985  for (; o; o=o->next,x++)
1986  {
1987    int i=0;
1988    for (; i<o->me->total_objects(); i++)
1989    {
1990      fp->write_uint32(x);
1991      int32_t x=object_to_number_in_list(o->me->get_object(i),save_list);
1992      if (x)
1993        fp->write_uint32(x);
1994      else                            // save links to excluded items as negative
1995        fp->write_uint32((int32_t)(-(object_to_number_in_list(o->me,exclude_list))));
1996    }
1997  }
1998
1999  fp->write_uint8(RC_32);
2000  fp->write_uint32(total_light_links(save_list));
2001
2002  x=1;
2003  for (o=save_list; o; o=o->next,x++)
2004  {
2005    int i=0;
2006    for (; i<o->me->total_lights(); i++)
2007    {
2008      fp->write_uint32(x);
2009      fp->write_uint32(light_to_number(o->me->get_light(i)));
2010    }
2011  }
2012
2013}
2014
2015
2016void level::load_links(bFILE *fp, spec_directory *sd,
2017               object_node *save_list, object_node *exclude_list)
2018{
2019  spec_entry *se=sd->find("object_links");
2020  if (se)
2021  {
2022    fp->seek(se->offset,0);
2023    if (fp->read_uint8()==RC_32)
2024    {
2025      int32_t t=fp->read_uint32();
2026      while (t)
2027      {
2028    int32_t x1=fp->read_uint32();
2029    CONDITION(x1>=0,"expected x1 for object link to be > 0\n");
2030    int32_t x2=fp->read_uint32();
2031    game_object *p,*q=number_to_object_in_list(x1,save_list);
2032    if (x2>0)
2033      p=number_to_object_in_list(x2,save_list);
2034    else p=number_to_object_in_list(-x2,exclude_list);
2035    if (q)
2036      q->add_object(p);
2037    else dprintf("bad object link\n");
2038
2039    t--;
2040      }
2041    }
2042  }
2043
2044  se=sd->find("light_links");
2045  if (se)
2046  {
2047    fp->seek(se->offset,0);
2048    if (fp->read_uint8()==RC_32)
2049    {
2050      int32_t t=fp->read_uint32();
2051      while (t)
2052      {
2053    int32_t x1=fp->read_uint32();
2054    int32_t x2=fp->read_uint32();
2055    game_object *p=number_to_object_in_list(x1,save_list);
2056    if (p)
2057      p->add_light(number_to_light(x2));
2058    else dprintf("bad object/light link\n");
2059    t--;
2060      }
2061    }
2062  }
2063
2064}
2065
2066
2067void level::write_options(bFILE *fp)
2068{
2069  // save background scroll rate
2070  fp->write_uint8(RC_32);
2071  fp->write_uint32(bg_xmul);
2072  fp->write_uint32(bg_xdiv);
2073  fp->write_uint32(bg_ymul);
2074  fp->write_uint32(bg_ydiv);
2075
2076  fp->write_uint8(RC_32);
2077  int ta=0;
2078  area_controller *a=area_list;
2079  for (; a; a=a->next) ta++;
2080  fp->write_uint32(ta);
2081  for (a=area_list; a; a=a->next)
2082  {
2083    fp->write_uint32(a->x);
2084    fp->write_uint32(a->y);
2085    fp->write_uint32(a->w);
2086    fp->write_uint32(a->h);
2087    fp->write_uint32(a->active);
2088
2089    fp->write_uint32(a->ambient);
2090    fp->write_uint32(a->view_xoff);
2091    fp->write_uint32(a->view_yoff);
2092    fp->write_uint32(a->ambient_speed);
2093    fp->write_uint32(a->view_xoff_speed);
2094    fp->write_uint32(a->view_yoff_speed);
2095  }
2096  fp->write_uint8(RC_32);
2097  fp->write_uint32(tick_counter());
2098}
2099
2100void level::load_options(spec_directory *sd, bFILE *fp)
2101{
2102  spec_entry *se=sd->find("bg_scroll_rate");
2103  if (se)
2104  {
2105    fp->seek(se->offset,0);
2106    if (fp->read_uint8()!=RC_32)
2107    { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2108    else
2109    {
2110      bg_xmul=fp->read_uint32();
2111      bg_xdiv=fp->read_uint32();
2112      bg_ymul=fp->read_uint32();
2113      bg_ydiv=fp->read_uint32();
2114    }
2115  } else { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2116
2117  se=sd->find("area_list.v1");
2118  if (se)
2119  {
2120    fp->seek(se->offset,0);
2121    if (fp->read_uint8()==RC_32)
2122    {
2123      area_controller *l=NULL,*p;
2124      int32_t ta=fp->read_uint32();
2125      int i=0;
2126      for (; i<ta; i++)
2127      {
2128    int32_t x,y,w,h;
2129    x=fp->read_uint32();
2130    y=fp->read_uint32();
2131    w=fp->read_uint32();
2132    h=fp->read_uint32();
2133    p=new area_controller(x,y,w,h,NULL);
2134    if (l) l->next=p;
2135    else area_list=p;
2136    l=p;
2137    p->active=fp->read_uint32();
2138    p->ambient=fp->read_uint32();
2139    p->view_xoff=fp->read_uint32();
2140    p->view_yoff=fp->read_uint32();
2141    p->ambient_speed=fp->read_uint32();
2142    p->view_xoff_speed=fp->read_uint32();
2143    p->view_yoff_speed=fp->read_uint32();
2144      }
2145    }
2146  }
2147
2148  se=sd->find("tick_counter");
2149  if (se)
2150  {
2151    fp->seek(se->offset,0);
2152    if (fp->read_uint8()==RC_32)
2153      set_tick_counter(fp->read_uint32());
2154    else set_tick_counter(0);
2155  } else set_tick_counter(0);
2156}
2157
2158
2159void level::write_cache_prof_info()
2160{
2161  if (cache.prof_is_on())
2162  {
2163    char pf_name[100];
2164    if (first_name)
2165      get_prof_assoc_filename(first_name,pf_name);
2166    else
2167      get_prof_assoc_filename(Name,pf_name);
2168
2169
2170    spec_directory sd;
2171    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"cache profile info",NULL,cache.prof_size(),0));
2172    sd.calc_offsets();
2173    jFILE *fp2=sd.write(pf_name);
2174    if (!fp2)
2175      the_game->show_help("Unable to open cache profile output file");
2176    else
2177    {
2178      cache.prof_write(fp2);
2179      delete fp2;
2180    }
2181    sd.delete_entries();
2182  }
2183
2184}
2185
2186void level::load_cache_info(spec_directory *sd, bFILE *fp)
2187{
2188  if (!DEFINEDP(symbol_value(l_empty_cache)) || !symbol_value(l_empty_cache))
2189  {
2190    char pf_name[100];
2191    if (first_name)
2192      get_prof_assoc_filename(first_name,pf_name);  // get cache info from orignal filename if this is a savegame
2193    else
2194      get_prof_assoc_filename(Name,pf_name);
2195
2196
2197    cache.load_cache_prof_info(pf_name,this);
2198  }
2199}
2200
2201
2202int level::save(char const *filename, int save_all)
2203{
2204    char name[255], bkname[255];
2205
2206    sprintf( name, "%s%s", get_save_filename_prefix(), filename );
2207    sprintf( bkname, "%slevsave.bak", get_save_filename_prefix() );
2208    if( !save_all && DEFINEDP( symbol_value( l_keep_backup ) ) &&
2209        symbol_value( l_keep_backup ) )   // make a backup
2210    {
2211        bFILE *fp = open_file( name, "rb" );    // does file already exist?
2212        if( !fp->open_failure() )
2213        {
2214            unlink( bkname );
2215            bFILE *bk = open_file( bkname, "wb" );
2216            if( bk->open_failure() )
2217                dprintf("unable to open backup file %s\n", bkname );
2218            else
2219            {
2220                uint8_t buf[0x1000];
2221                int32_t size = fp->file_size();
2222                int tr = 1;
2223                while( size && tr )
2224                {
2225                    int tr = fp->read(buf,0x1000);
2226                    if( tr )
2227                    tr = bk->write(buf,tr);
2228                    size -= tr;
2229                }
2230            }
2231            delete bk;
2232#if (defined(__MACH__) || !defined(__APPLE__))
2233            chmod( bkname, S_IRWXU | S_IRWXG | S_IRWXO );
2234#endif
2235        }
2236        delete fp;
2237    }
2238
2239    // if we are not doing a savegame then change the first_name to this name
2240    if( !save_all )
2241    {
2242        if( first_name )
2243            free(first_name);
2244        first_name = strdup(name);
2245    }
2246
2247    object_node *players, *objs;
2248    if( save_all )
2249        players = NULL;
2250    else
2251        players = make_player_onodes();
2252
2253    objs = make_not_list(players);     // negate the above list
2254
2255    bFILE *fp = create_dir( name, save_all, objs, players);
2256    if( fp != NULL )
2257    {
2258        if( !fp->open_failure() )
2259        {
2260            if( first_name )
2261            {
2262                fp->write_uint8( strlen( first_name ) + 1 );
2263                fp->write( first_name, strlen( first_name ) + 1 );
2264            }
2265            else
2266            {
2267                fp->write_uint8( 1 );
2268                fp->write_uint8( 0 );
2269            }
2270
2271            fp->write_uint32( fg_width );
2272            fp->write_uint32( fg_height );
2273
2274            int t  = fg_width * fg_height;
2275            uint16_t *rm = map_fg;
2276            for (; t; t--,rm++)
2277            {
2278                uint16_t x = *rm;
2279                x = lstl(x);            // convert to intel endianess
2280                *rm = x;
2281            }
2282
2283            fp->write( (char *)map_fg, 2 * fg_width * fg_height );
2284            t = fg_width * fg_height;
2285            rm = map_fg;
2286            for (; t; t--,rm++)
2287            {
2288                uint16_t x = *rm;
2289                x = lstl( x );            // convert to intel endianess
2290                *rm = x;
2291            }
2292
2293            fp->write_uint32( bg_width );
2294            fp->write_uint32( bg_height );
2295            t = bg_width * bg_height;
2296            rm = map_bg;
2297
2298            for (; t; t--,rm++)
2299            {
2300                uint16_t x=*rm;
2301                x = lstl( x );        // convert to intel endianess
2302                *rm = x;
2303            }
2304
2305            fp->write( (char *)map_bg, 2 * bg_width * bg_height );
2306            rm = map_bg;
2307            t = bg_width*bg_height;
2308
2309            for (; t; t--,rm++)
2310            {
2311                uint16_t x = *rm;
2312                x = lstl( x );        // convert to intel endianess
2313                *rm = x;
2314            }
2315
2316            write_options( fp );
2317            write_objects( fp, objs );
2318            write_lights( fp );
2319            write_links( fp, objs, players );
2320            if( save_all )
2321            {
2322                write_player_info( fp, objs );
2323                write_thumb_nail( fp,screen );
2324            }
2325
2326            delete fp;
2327#if (defined(__MACH__) || !defined(__APPLE__))
2328            chmod( name, S_IRWXU | S_IRWXG | S_IRWXO );
2329#endif
2330            write_cache_prof_info();
2331        }
2332        else
2333        {
2334            the_game->show_help( "Unable to open file for saving\n" );
2335            delete fp;
2336            return 0;
2337        }
2338    }
2339    else
2340    {
2341        the_game->show_help( "Unable to open file for saving.\n" );
2342        printf( "\nFailed to save game.\n" );
2343        printf( "I was trying to save to: '%s'\n\tPath: '%s'\n\tFile: '%s'\n", name, get_save_filename_prefix(), filename );
2344        printf( "\nPlease send an email to:\n\ttrandor@labyrinth.net.au\nwith these details.\nThanks.\n" );
2345        return 0;
2346    }
2347
2348    delete_object_list(players);
2349    delete_object_list(objs);
2350
2351    return 1;
2352}
2353
2354level::level(int width, int height, char const *name)
2355{
2356  the_game->need_refresh();
2357  area_list=NULL;
2358  set_tick_counter(0);
2359
2360  attack_list=NULL;
2361  attack_list_size=attack_total=0;
2362
2363  target_list=NULL;
2364  target_list_size=target_total=0;
2365
2366  block_list=NULL;
2367  block_list_size=block_total=0;
2368
2369  all_block_list=NULL;
2370  all_block_list_size=all_block_total=0;
2371
2372  Name=NULL;
2373  first_name=NULL;
2374
2375  set_name(name);
2376  first=first_active=NULL;
2377
2378  fg_width=width;
2379  fg_height=height;
2380  calc_bgsize(fg_width,fg_height,bg_width,bg_height);
2381
2382  map_bg=(uint16_t *)malloc(sizeof(int16_t)*bg_width*bg_height);
2383  map_fg=(uint16_t *)malloc(sizeof(int16_t)*fg_width*fg_height);
2384
2385
2386
2387  memset(map_bg,0,sizeof(int16_t)*bg_width*bg_height);
2388  memset(map_fg,0,sizeof(int16_t)*fg_width*fg_height);
2389
2390  int i;
2391  for (i=0; i<fg_width; i++)
2392  {
2393    map_fg[i]=1;
2394    map_fg[fg_width*(fg_height-1)+i]=1;
2395  }
2396  for (i=0; i<fg_height; i++)
2397  {
2398    map_fg[fg_width*i]=1;
2399    map_fg[fg_width*i+fg_width-1]=1;
2400  }
2401
2402  total_objs=0;
2403  insert_players();
2404}
2405
2406
2407void level::add_object(game_object *new_guy)
2408{
2409  total_objs++;
2410  new_guy->next=NULL;
2411  if (figures[new_guy->otype]->get_cflag(CFLAG_ADD_FRONT))
2412  {
2413    if (!first)
2414      first=new_guy;
2415    else
2416      last->next=new_guy;
2417    last=new_guy;
2418  } else
2419  {
2420    if (!first)
2421      last=first=new_guy;
2422    else
2423    {
2424      new_guy->next=first;
2425      first=new_guy;
2426    }
2427  }
2428}
2429
2430void level::add_object_after(game_object *new_guy,game_object *who)
2431{
2432  if (!who) add_object(new_guy);
2433  else
2434  {
2435    total_objs++;
2436    if (who==last) last=new_guy;
2437    new_guy->next=who->next;
2438    who->next=new_guy;
2439  }
2440}
2441
2442void level::delete_object(game_object *who)
2443{
2444  remove_object(who);
2445  delete who;
2446}
2447
2448void level::remove_block(game_object *who)
2449{
2450  int i=0,j;
2451  game_object **o=block_list;
2452  for (; i<block_total; i++)
2453  {
2454    if (*o==who)        // is this object in the block list?
2455    {
2456      block_total--;    // squish the block list in
2457      o++;
2458      for (j=i; j<block_total; j++)
2459        block_list[j]=block_list[j+1];
2460    } else o++;
2461  }
2462}
2463
2464
2465// searches through the all_block list for who and if it finds it deletes it
2466void level::remove_all_block(game_object *who)
2467{
2468  int i=0,j;
2469  game_object **o=all_block_list;
2470  for (; i<all_block_total; i++)
2471  {
2472    if (*o==who)        // is this object in the block list?
2473    {
2474      all_block_total--;    // squish the block list in
2475      o++;
2476      for (j=i; j<all_block_total; j++)
2477        all_block_list[j]=all_block_list[j+1];
2478    } else o++;
2479  }
2480}
2481
2482void level::remove_object(game_object *who)
2483{
2484  if (dev_cont)
2485    dev_cont->notify_deleted_object(who);
2486
2487  if (who==first)
2488  {
2489    if (who==last) last=NULL;
2490    first=first->next;
2491  }
2492  else
2493  {
2494    game_object *o=first;
2495    for (; o && o->next!=who; o=o->next);
2496    if (o)
2497    {
2498      o->next=who->next;
2499      if (!o->next) last=o;
2500    }
2501    else return ;     // if object is not in level, don't try to do anything else
2502  }
2503  total_objs--;
2504
2505
2506  if (first_active==who)
2507    first_active=who->next_active;
2508  else
2509  {
2510    game_object *o=first_active;
2511    for (; o && o->next_active!=who; o=o->next_active);
2512    if (o)
2513      o->next_active=who->next_active;
2514  }
2515
2516  if (who->flags()&KNOWN_FLAG)
2517  {
2518    game_object *o=first;
2519    for (; o; o=o->next)
2520    {
2521      int t=o->total_objects();
2522      int i=0;
2523      for (; i<t; i++)
2524        if (o->get_object(i)==who)
2525    {
2526      o->remove_object(who);
2527      t=o->total_objects();
2528    }
2529    }
2530  }
2531
2532  if (who->otype<0xffff)
2533  {
2534    if (who->can_block())  // remove object from block list and all_block if nessasary
2535    {
2536      remove_block(who);
2537      remove_all_block(who);
2538    } else if (who->hurtable())
2539      remove_all_block(who);
2540  }
2541
2542
2543  int t=who->total_objects();
2544  while (t) { who->remove_object(who->get_object(0)); t--; }
2545
2546  t=who->total_lights();
2547  while (t) { who->remove_light(who->get_light(0)); t--; }
2548}
2549
2550void level::to_front(game_object *o)  // move to end of list, so we are drawn last, therefore top
2551{
2552  if (o==last) return ;
2553  first_active=NULL;     // make sure nothing goes screwy with the active list
2554
2555  if (o==first)
2556    first=first->next;
2557  else
2558  {
2559    game_object *w=first;
2560    for (; w && w->next!=o; w=w->next);
2561    if (!w) return ;
2562    w->next=o->next;
2563  }
2564
2565  last->next=o;
2566  o->next=NULL;
2567  last=o;
2568}
2569
2570void level::to_back(game_object *o)   // to make the character drawn in back, put at front of list
2571{
2572  if (o==first) return;
2573  first_active=NULL;     // make sure nothing goes screwy with the active list
2574
2575  game_object *w=first;
2576  for (; w && w->next!=o; w=w->next);
2577  if (!w) return;
2578  if (last==o)
2579    last=w;
2580  w->next=o->next;
2581  o->next=first;
2582  first=o;
2583}
2584
2585
2586game_object *level::find_self(game_object *me)
2587{
2588  return me;
2589}
2590
2591game_object *level::find_object(int32_t x, int32_t y)
2592{
2593  int32_t x1,y1,x2,y2;
2594  game_object *o=first;
2595  for (; o; o=o->next)
2596  {
2597    o->picture_space(x1,y1,x2,y2);
2598    if (x<x2 && x>=x1 && y<y2 && y>=y1)
2599      return o;
2600  }
2601  return NULL;
2602}
2603
2604int32_t last_tile_hit_x,last_tile_hit_y;
2605
2606#define remapx(x) (x==0 ? -1 : x==tl-1 ? tl+1 : x)
2607#define remapy(y) (y==0 ? -1 : y==th-1 ? th+1 : y)
2608
2609void level::foreground_intersect(int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
2610{
2611/*  if (x1==x2)
2612  { vforeground_intersect(x1,y1,y2);
2613    return ;
2614  }  */
2615
2616  int32_t tl=the_game->ftile_width(),th=the_game->ftile_height(),
2617    j,
2618    xp1,yp1,xp2,yp2,    // starting and ending points of block line segment
2619    swap;               // temp var
2620  int32_t blockx1,blocky1,blockx2,blocky2,block,bx,by;
2621  point_list *block_list;
2622  unsigned char *bdat;
2623
2624  blockx1=x1;
2625  blocky1=y1;
2626  blockx2=x2;
2627  blocky2=y2;
2628  if (blockx1>blockx2) { swap=blockx1; blockx1=blockx2; blockx2=swap; }
2629  if (blocky1>blocky2) { swap=blocky1; blocky1=blocky2; blocky2=swap; }
2630  blockx1=(blockx1-2)/tl-1;
2631  blockx2=(blockx2+tl+2)/tl+1;
2632  blocky1=(blocky1-2)/th-1;
2633  blocky2=(blocky2+th+2)/th+1;
2634
2635
2636  if (blockx2>=foreground_width()) { x2=tl*foreground_width()-1; }
2637  if (blocky2>=foreground_height()) { y2=th*foreground_height()-1; }
2638  blockx1=Max(blockx1,0);
2639  blocky1=Max(blocky1,0);
2640
2641  if ((blockx1>blockx2) || (blocky1>blocky2)) return ;
2642
2643  // now check all the map positions this line could intersect
2644  for (bx=blockx1; bx<=blockx2; bx++)
2645  {
2646    for (by=blocky1; by<=blocky2; by++)
2647    {
2648      block=the_game->get_map_fg(bx,by);
2649      if (block>BLACK)        // don't check BLACK, should be no points in it
2650      {
2651        // now check the all the line segments in the block
2652        foretile *f=the_game->get_fg(block);
2653        block_list=f->points;
2654        unsigned char total=block_list->tot;
2655        bdat=block_list->data;
2656        unsigned char *ins=f->points->inside;
2657    int32_t xo=bx*tl,yo=by*th;
2658        for (j=0; j<total-1; j++,ins++)
2659        {
2660          // find the starting and ending points for this segment
2661      xp1=xo+remapx(*bdat);
2662      bdat++;
2663
2664      yp1=yo+remapy(*bdat);
2665      bdat++;
2666
2667      xp2=xo+remapx(*bdat);
2668      yp2=yo+remapy(bdat[1]);
2669
2670
2671      int32_t ox2=x2,oy2=y2;
2672          if (*ins)
2673            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1);
2674          else
2675            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1);
2676      if (ox2!=x2 || oy2!=y2)
2677      {
2678        last_tile_hit_x=bx;
2679        last_tile_hit_y=by;
2680      }
2681
2682        }
2683      }
2684    }
2685  }
2686}
2687
2688
2689void level::vforeground_intersect(int32_t x1, int32_t y1, int32_t &y2)
2690{
2691  int32_t tl=f_wid,th=f_hi,
2692    j,
2693    xp1,yp1,xp2,yp2;    // starting and ending points of block line segment temp var
2694  int32_t blocky1,blocky2,block,bx,by,checkx;
2695  point_list *block_list;
2696  unsigned char *bdat;
2697
2698  int y_addback;
2699  if (y1>y2)
2700  {
2701    blocky1=y2/th;
2702    blocky2=y1/th;
2703    y_addback=blocky2*f_hi;
2704  } else
2705  {
2706    blocky1=y1/th;
2707    blocky2=y2/th;
2708    y_addback=blocky1*f_hi;
2709  }
2710
2711  y1-=y_addback;
2712  y2-=y_addback;
2713
2714  bx=x1/f_wid;
2715  checkx=x1-bx*f_wid;
2716
2717
2718  // now check all the map positions this line could intersect
2719
2720  for (by=blocky1; by<=blocky2; by++,y1-=f_hi,y2-=f_hi,y_addback+=f_hi)
2721  {
2722    block=the_game->get_map_fg(bx,by);
2723
2724    // now check the all the line segments in the block
2725    foretile *f=the_game->get_fg(block);
2726    block_list=f->points;
2727
2728    unsigned char total=block_list->tot;
2729    bdat=block_list->data;
2730    unsigned char *ins=f->points->inside;
2731
2732//    int32_t xo=bx*tl,yo=by*th;
2733    for (j=0; j<total-1; j++,ins++)
2734    {
2735      // find the starting and ending points for this segment
2736      xp1=remapx(*bdat);
2737      bdat++;
2738
2739      yp1=remapy(*bdat);
2740      bdat++;
2741
2742      xp2=remapx(*bdat);
2743      yp2=remapy(bdat[1]);
2744
2745
2746      int32_t oy2=y2;
2747      if (*ins)
2748        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,1);
2749      else
2750        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,-1);
2751      if (oy2!=y2)
2752      {
2753    last_tile_hit_x=bx;
2754    last_tile_hit_y=by;
2755      }
2756    }
2757  }
2758  y2+=y_addback;
2759}
2760
2761
2762
2763void level::send_signal(int32_t signal)
2764{
2765  if (signal)   // signal 0 is never sent!
2766  {
2767    game_object *o=first_active;
2768    for (; o; o=o->next_active)
2769      o->recieve_signal(signal);
2770  }
2771}
2772
2773
2774int level::crush(game_object *by_who, int xamount, int yamount)
2775{
2776  int32_t xv,yv,crushed=0;
2777  game_object *o=first_active;
2778  for (; o; o=o->next_active)
2779  {
2780    if (o->hurtable() && o!=by_who)
2781    {
2782      xv=-xamount;
2783      yv=-yamount;
2784      if (o->try_move(o->x,o->y,xv,yv,3)==by_who)
2785      {
2786    xv=xamount;
2787    yv=yamount;
2788    o->try_move(o->x,o->y,xv,yv,3);
2789    if (xv==0 && yv==0)
2790    {
2791      if (o->state!=dead && o->state!=dieing)
2792        o->do_damage(by_who->current_figure()->hit_damage,by_who,o->x,o->y,0,0);
2793
2794/*      {
2795        if (o->has_sequence(dieing))
2796          o->set_state(dieing);
2797        else o->set_state(dead);
2798          o->hp=0;
2799      }        */
2800      crushed=1;
2801    }
2802      }
2803    }
2804  }
2805
2806  return crushed;
2807}
2808
2809
2810int level::platform_push(game_object *by_who, int xamount, int yamount)
2811{
2812  int failed=0;
2813  int32_t xv,yv;
2814  game_object *o=first_active;
2815  for (; o; o=o->next_active)
2816  {
2817    if (o->is_playable() && o->state!=dieing && o->state!=dead)
2818    {
2819      // check to see if the platform is going up and will run into us.
2820      int32_t tvx,tvy;
2821      if (yamount<0)
2822      {
2823    tvx=-xamount;
2824    tvy=-yamount;
2825    if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)
2826    {
2827      o->x+=tvx;
2828      o->y+=tvy;
2829    }
2830      }
2831
2832/*      xv=xamount;
2833      yv=yamount;
2834      tvx,tvy;
2835      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2836      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2837      if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)  // we the platform hit us?
2838      {
2839    o->x+=tvx;
2840    o->y+=tvy;
2841      }*/
2842
2843      xv=0;
2844      yv=2;
2845      if (o->try_move(o->x,o->y,xv,yv,1)==by_who)  // are we standing on the platform?
2846      {
2847    by_who->x=-by_who->x;
2848    xv=xamount;
2849    yv=yamount;
2850    o->try_move(o->x,o->y,xv,yv,3);
2851    if (xv!=xamount || yv!=yamount) failed=1;
2852    o->x+=xv;
2853    o->y+=yv;
2854    by_who->x=-by_who->x;
2855      }
2856    }
2857  }
2858  return !failed;
2859}
2860
2861int level::push_characters(game_object *by_who, int xamount, int yamount)
2862{
2863  int32_t xv,yv;
2864  int failed=0;
2865  game_object *o=first_active;
2866  for (; o; o=o->next_active)
2867  {
2868    if ((o->is_playable() || o->pushable()) && o->state!=dieing && o->state!=dead)
2869    {
2870      xv=-xamount;
2871      yv=-yamount;
2872      int32_t tvx,tvy;
2873      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2874      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2875      if (o->try_move(o->x+xamount,o->y+yamount,tvx,tvy,3)==by_who)
2876      {
2877    xv=(xamount-tvx);
2878    yv=(yamount-tvy);
2879    o->try_move(o->x,o->y,xv,yv,3);
2880    o->x+=xv;
2881    o->y+=yv;
2882    if (xv!=xamount-tvx || yv!=yamount-tvy)
2883      failed=1;
2884      }
2885    }
2886  }
2887  return !failed;
2888}
2889
2890game_object *level::find_xrange(int x, int y, int type, int xd)
2891{
2892  int32_t find_ydist=100000;
2893  game_object *find=NULL;
2894  game_object *o=first_active;
2895  for (; o; o=o->next_active)
2896  {
2897    if (o->otype==type)
2898    {
2899      int x_dist=abs(x-o->x);
2900      int y_dist=abs(y-o->y);
2901
2902      if (x_dist<xd  && y_dist<find_ydist)
2903      {
2904    find_ydist=y_dist;
2905    find=o;
2906      }
2907    }
2908  }
2909  return find;
2910}
2911
2912
2913game_object *level::find_xclosest(int x, int y, int type, game_object *who)
2914{
2915  int32_t find_ydist=100000,find_xdist=0xffffff;
2916  game_object *find=NULL;
2917  game_object *o=first_active;
2918  for (; o; o=o->next_active)
2919  {
2920    if (o->otype==type && o!=who)
2921    {
2922      int x_dist=abs(x-o->x);
2923      if (x_dist<find_xdist)
2924      {
2925    find_xdist=x_dist;
2926    find_ydist=abs(y-o->y);
2927    find=o;
2928      }
2929      else if (x_dist==find_xdist)
2930      {
2931    int y_dist=abs(y-o->y);
2932    if (y_dist<find_ydist)
2933    {
2934      find_ydist=y_dist;
2935      find=o;
2936    }
2937      }
2938    }
2939  }
2940  return find;
2941}
2942
2943game_object *level::find_closest(int x, int y, int type, game_object *who)
2944{
2945  int32_t find_dist=100000;
2946  game_object *find=NULL;
2947  game_object *o=first_active;
2948  for (; o; o=o->next_active)
2949  {
2950    if (o->otype==type && o!=who)
2951    {
2952      int d=(x-o->x)*(x-o->x)+(y-o->y)*(y-o->y);
2953      if (d<find_dist)
2954      {
2955    find=o;
2956    find_dist=d;
2957      }
2958    }
2959  }
2960  return find;
2961}
2962
2963
2964
2965void level::remove_light(light_source *which)
2966{
2967  if (which->known)
2968  {
2969    game_object *o=first;
2970    for (; o; o=o->next)
2971    {
2972      int t=o->total_lights();
2973      int i=0;
2974      for (; i<t; i++)
2975        if (o->get_light(i)==which)
2976      o->remove_light(o->get_light(i));
2977    }
2978  }
2979  delete_light(which);
2980}
2981
2982
2983game_object *level::find_type(int type, int skip)
2984{
2985  game_object *l=NULL;
2986  game_object *o=first;
2987  for (; o; o=o->next)
2988  {
2989    if (o->otype==type)
2990    {
2991      if (!skip)
2992        return o;
2993      skip--;
2994      l=o;
2995    }
2996  }
2997  return l;
2998}
2999
3000void level::hurt_radius(int32_t x, int32_t y,int32_t r, int32_t m, game_object *from, game_object *exclude,
3001            int max_push)
3002{
3003  if (r<1) return ;   // avoid dev vy zero
3004  game_object *o=first_active;
3005  for (; o; o=o->next_active)
3006  {
3007    if (o!=exclude && o->hurtable())
3008    {
3009      int32_t y1=o->y,y2=o->y-o->picture()->Size().y;
3010      int32_t cx=abs(o->x-x),cy1=abs(y1-y),d1,d2,cy2=abs(y2-y);
3011      if (cx<cy1)
3012        d1=cx+cy1-(cx>>1);
3013      else d1=cx+cy1-(cy1>>1);
3014
3015      if (cx<cy2)
3016        d2=cx+cy2-(cx>>1);
3017      else d2=cx+cy2-(cy2>>1);
3018      if (d2<d1)
3019        d1=d2;
3020
3021
3022
3023      if (d1<r)
3024      {
3025
3026    int px=(r-cx)*max_push/r,py=(r-cy1)*max_push/r;
3027    if (o->x<x)
3028          px=-px;
3029    if (o->y<y)
3030          py=-py;
3031    o->do_damage((r-d1)*m/r,from,x,y1,px,py);
3032      }
3033
3034
3035    }
3036  }
3037
3038}
3039
3040
3041
3042game_object *level::get_random_start(int min_player_dist, view *exclude)
3043{
3044  int t=0;
3045  game_object *o=first;
3046  for (; o; o=o->next)
3047    if (o->otype==start_position_type) t++;    // count how many starts there are in the level
3048
3049  if (t==0) return NULL;                       // there aren't any starts in level!
3050
3051  int retries=t;
3052  do
3053  {
3054    int ctry=jrandom(t)+1;
3055    game_object *n=first;
3056    for (n=first; ctry && n; n=n->next)
3057    {
3058      if (n->otype==start_position_type)
3059      {
3060    o=n;
3061        ctry--;
3062      }
3063    }
3064
3065    int too_close=0;
3066    view *v=player_list;
3067    for (; v; v=v->next)
3068    {
3069      if (v!=exclude)
3070      {
3071    int32_t cx=abs(v->x_center()-o->x),cy=abs(v->y_center()-o->y),d;
3072    if (cx<cy)
3073          d=cx+cy-(cx>>1);
3074    else d=cx+cy-(cy>>1);
3075    if (d<min_player_dist) too_close=1;
3076      }
3077    }
3078    if (too_close) retries--;
3079    else retries=0;
3080  } while (retries);
3081
3082  return o;
3083}
3084
3085
3086
3087
3088
3089void level::insert_players()
3090{
3091
3092  int start=0;
3093  int i=0;
3094  for (; i<total_objects; i++)
3095    if (!strcmp(object_names[i],"START"))
3096      start=i;
3097
3098  view *f=player_list;
3099  for (; f; f=f->next)
3100  {
3101    game_object *st=find_type(start,f->player_number);
3102    if (st)
3103    {
3104      f->focus->x=st->x;
3105      f->focus->y=st->y;
3106    }
3107    add_object_after(f->focus,st);
3108  }
3109
3110}
3111
3112
3113void level::add_attacker(game_object *who)
3114{
3115  if (attack_total>=attack_list_size)  // see if we need to grow the list size..
3116  {
3117    attack_list_size++;
3118    attack_list=(game_object **)realloc(attack_list,sizeof(game_object *)*attack_list_size);
3119  }
3120  attack_list[attack_total]=who;
3121  attack_total++;
3122}
3123
3124
3125
3126void level::add_target(game_object *who)
3127{
3128  if (target_total>=target_list_size)  // see if we need to grow the list size..
3129  {
3130    target_list_size++;
3131    target_list=(game_object **)realloc(target_list,sizeof(game_object *)*target_list_size);
3132  }
3133  target_list[target_total]=who;
3134  target_total++;
3135}
3136
3137
3138
3139void level::add_block(game_object *who)
3140{
3141  if (block_total>=block_list_size)  // see if we need to grow the list size..
3142  {
3143    block_list_size++;
3144    block_list=(game_object **)realloc(block_list,sizeof(game_object *)*block_list_size);
3145  }
3146  block_list[block_total]=who;
3147  block_total++;
3148}
3149
3150
3151void level::add_all_block(game_object *who)
3152{
3153  if (all_block_total>=all_block_list_size)  // see if we need to grow the list size..
3154  {
3155    all_block_list_size++;
3156    all_block_list=(game_object **)realloc(all_block_list,sizeof(game_object *)*all_block_list_size);
3157  }
3158  all_block_list[all_block_total]=who;
3159  all_block_total++;
3160}
3161
3162
3163game_object *level::find_object_in_area(int32_t x, int32_t y, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
3164                     Cell *list, game_object *exclude)
3165{
3166  game_object *closest=NULL;
3167  int32_t closest_distance=0xfffffff,distance,xo,yo;
3168  game_object *o=first_active;
3169  for (; o; o=o->next_active)
3170  {
3171    int32_t xp1,yp1,xp2,yp2;
3172    o->picture_space(xp1,yp1,xp2,yp2);
3173
3174
3175    if (!(xp1>x2 || xp2<x1 || yp1>y2 || yp2<y1) && o!=exclude)
3176    {
3177      // check to see if the type is in the list
3178      Cell *v=list;
3179      for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3180      if (!NILP(v))
3181      {
3182    xo=abs(o->x-x);
3183    yo=abs(o->y-y);
3184    distance=xo*xo+yo*yo;
3185    if (distance<closest_distance)
3186    {
3187      closest_distance=distance;
3188      closest=o;
3189    }
3190      }
3191    }
3192  }
3193  return closest;
3194}
3195
3196
3197
3198
3199game_object *level::find_object_in_angle(int32_t x, int32_t y, int32_t start_angle, int32_t end_angle,
3200                    void *list, game_object *exclude)
3201{
3202  game_object *closest=NULL;
3203  int32_t closest_distance=0xfffffff,distance,xo,yo;
3204  game_object *o=first_active;
3205  for (; o; o=o->next_active)
3206  {
3207    int32_t angle=lisp_atan2(o->y-y,o->x-x);
3208    if (((start_angle<=end_angle && (angle>=start_angle && angle<=end_angle))
3209    || (start_angle>end_angle && (angle>=start_angle || angle<=end_angle)))
3210    && o!=exclude)
3211    {
3212      // check to see if the type is in the list
3213      Cell *v=(Cell *)list;
3214      for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3215      if (!NILP(v))
3216      {
3217    xo=abs(o->x-x);
3218    yo=abs(o->y-y);
3219    distance=xo*xo+yo*yo;
3220    if (distance<closest_distance)
3221    {
3222      closest_distance=distance;
3223      closest=o;
3224    }
3225      }
3226    }
3227  }
3228  return closest;
3229}
3230
3231
3232object_node *level::make_not_list(object_node *list)
3233{
3234  object_node *f=NULL,*l=NULL;
3235  game_object *o=first;
3236  for (; o; o=o->next)
3237  {
3238    if (!object_to_number_in_list(o,list))
3239    {
3240      object_node *q=new object_node(o,NULL);
3241      if (f)
3242        l->next=q;
3243      else f=q;
3244      l=q;
3245    }
3246  }
3247  return f;
3248}
3249
3250void level::write_object_info(char *filename)
3251{
3252  FILE *fp=open_FILE(filename,"wb");
3253  if (fp)
3254  {
3255    int i=0;
3256    game_object *o=first;
3257    for (; o; o=o->next)
3258    {
3259      fprintf(fp,"%3d %s %4ld %4ld %4ld %4ld %04d\n",i++,object_names[o->otype],(long)o->x,(long)o->y,
3260          (long)o->xvel(),(long)o->yvel(),o->current_frame);
3261    }
3262    fclose(fp);
3263  }
3264}
3265
3266
3267area_controller::area_controller(int32_t X, int32_t Y, int32_t W, int32_t H, area_controller *Next)
3268{
3269  x=X; y=Y; w=W; h=H;
3270  next=Next; active=0;
3271
3272  ambient=-1;
3273  view_xoff=-1;
3274  view_yoff=-1;
3275  ambient_speed=2;
3276  view_xoff_speed=4;
3277  view_yoff_speed=4;
3278}
Note: See TracBrowser for help on using the repository browser.