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

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