Fix crash if Num_walls=0
[btb/d2x.git] / main / paging.c
1 /* $Id: paging.c,v 1.4 2004-08-28 23:17:45 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines for paging in/out textures.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 //#define PSX_BUILD_TOOLS
26
27 #ifdef RCS
28 static char rcsid[] = "$Id: paging.c,v 1.4 2004-08-28 23:17:45 schaffner Exp $";
29 #endif
30
31 #ifdef WINDOWS
32 #include "desw.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include <string.h>
39
40 #include "pstypes.h"
41 #include "mono.h"
42 #include "inferno.h"
43 #include "segment.h"
44 #include "textures.h"
45 #include "wall.h"
46 #include "object.h"
47 #include "gamemine.h"
48 #include "error.h"
49 #include "gameseg.h"
50 #include "game.h"
51 #include "piggy.h"
52 #include "texmerge.h"
53 #include "polyobj.h"
54 #include "vclip.h"
55 #include "effects.h"
56 #include "fireball.h"
57 #include "weapon.h"
58 #include "palette.h"
59 #include "timer.h"
60 #include "text.h"
61 #include "cntrlcen.h"
62 #include "gauges.h"
63 #include "powerup.h"
64 #include "fuelcen.h"
65 #include "mission.h"
66
67
68 #ifdef WINDOWS
69 void paging_touch_vclip_w( vclip * vc )
70 {
71         int i;
72
73         for (i=0; i<vc->num_frames; i++ )       {
74                 if ( GameBitmaps[(vc->frames[i]).index].bm_flags & BM_FLAG_PAGED_OUT)
75                         piggy_bitmap_page_in_w( vc->frames[i],1 );
76         }
77 }
78 #endif
79
80
81 void paging_touch_vclip( vclip * vc )
82 {
83         int i;
84
85         for (i=0; i<vc->num_frames; i++ )       {
86                 PIGGY_PAGE_IN( vc->frames[i] );
87         }
88 }
89
90
91 void paging_touch_wall_effects( int tmap_num )
92 {
93         int i;
94
95         for (i=0;i<Num_effects;i++)     {
96                 if ( Effects[i].changing_wall_texture == tmap_num )     {
97                         paging_touch_vclip( &Effects[i].vc );
98
99                         if (Effects[i].dest_bm_num > -1)
100                                 PIGGY_PAGE_IN( Textures[Effects[i].dest_bm_num] );      //use this bitmap when monitor destroyed
101                         if ( Effects[i].dest_vclip > -1 )
102                                 paging_touch_vclip( &Vclip[Effects[i].dest_vclip] );              //what vclip to play when exploding
103
104                         if ( Effects[i].dest_eclip > -1 )
105                                 paging_touch_vclip( &Effects[Effects[i].dest_eclip].vc ); //what eclip to play when exploding
106
107                         if ( Effects[i].crit_clip > -1 )
108                                 paging_touch_vclip( &Effects[Effects[i].crit_clip].vc ); //what eclip to play when mine critical
109                 }
110
111         }
112 }
113
114 void paging_touch_object_effects( int tmap_num )
115 {
116         int i;
117
118         for (i=0;i<Num_effects;i++)     {
119                 if ( Effects[i].changing_object_texture == tmap_num )   {
120                         paging_touch_vclip( &Effects[i].vc );
121                 }
122         }
123 }
124
125
126 void paging_touch_model( int modelnum )
127 {
128         int i;
129         polymodel *pm = &Polygon_models[modelnum];
130
131         for (i=0;i<pm->n_textures;i++)  {
132                 PIGGY_PAGE_IN( ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]] );
133                 paging_touch_object_effects( ObjBitmapPtrs[pm->first_texture+i] );
134                 #ifdef PSX_BUILD_TOOLS
135                 // cmp added
136                 paging_touch_object_effects( pm->first_texture+i );
137                 #endif
138         }
139 }
140
141 void paging_touch_weapon( int weapon_type )
142 {
143         // Page in the robot's weapons.
144         
145         if ( (weapon_type < 0) || (weapon_type > N_weapon_types) ) return;
146
147         if ( Weapon_info[weapon_type].picture.index )   {
148                 PIGGY_PAGE_IN( Weapon_info[weapon_type].picture );
149         }               
150         
151         if ( Weapon_info[weapon_type].flash_vclip > -1 )
152                 paging_touch_vclip(&Vclip[Weapon_info[weapon_type].flash_vclip]);
153         if ( Weapon_info[weapon_type].wall_hit_vclip > -1 )
154                 paging_touch_vclip(&Vclip[Weapon_info[weapon_type].wall_hit_vclip]);
155         if ( Weapon_info[weapon_type].damage_radius )   {
156                 // Robot_hit_vclips are actually badass_vclips
157                 if ( Weapon_info[weapon_type].robot_hit_vclip > -1 )
158                         paging_touch_vclip(&Vclip[Weapon_info[weapon_type].robot_hit_vclip]);
159         }
160
161         switch( Weapon_info[weapon_type].render_type )  {
162         case WEAPON_RENDER_VCLIP:
163                 if ( Weapon_info[weapon_type].weapon_vclip > -1 )
164                         paging_touch_vclip( &Vclip[Weapon_info[weapon_type].weapon_vclip] );
165                 break;
166         case WEAPON_RENDER_NONE:
167                 break;
168         case WEAPON_RENDER_POLYMODEL:
169                 paging_touch_model( Weapon_info[weapon_type].model_num );
170                 break;
171         case WEAPON_RENDER_BLOB:
172                 PIGGY_PAGE_IN( Weapon_info[weapon_type].bitmap );
173                 break;
174         }
175 }
176
177
178
179 sbyte super_boss_gate_type_list[13] = {0, 1, 8, 9, 10, 11, 12, 15, 16, 18, 19, 20, 22 };
180
181 void paging_touch_robot( int robot_index )
182 {
183         int i;
184
185         //mprintf((0, "Robot %d loading...", robot_index));
186
187         // Page in robot_index
188         paging_touch_model(Robot_info[robot_index].model_num);
189         if ( Robot_info[robot_index].exp1_vclip_num>-1 )
190                 paging_touch_vclip(&Vclip[Robot_info[robot_index].exp1_vclip_num]);
191         if ( Robot_info[robot_index].exp2_vclip_num>-1 )
192                 paging_touch_vclip(&Vclip[Robot_info[robot_index].exp2_vclip_num]);
193
194         // Page in his weapons
195         paging_touch_weapon( Robot_info[robot_index].weapon_type );
196
197         // A super-boss can gate in robots...
198         if ( Robot_info[robot_index].boss_flag==2 )     {
199                 for (i=0; i<13; i++ )
200                         paging_touch_robot(super_boss_gate_type_list[i]);
201
202                 paging_touch_vclip( &Vclip[VCLIP_MORPHING_ROBOT] );
203         }
204 }
205
206
207 void paging_touch_object( object * obj )
208 {
209         int v;
210
211         switch (obj->render_type) {
212
213                 case RT_NONE:   break;          //doesn't render, like the player
214
215                 case RT_POLYOBJ:
216                         if ( obj->rtype.pobj_info.tmap_override != -1 )
217                                 PIGGY_PAGE_IN( Textures[obj->rtype.pobj_info.tmap_override] );
218                         else
219                                 paging_touch_model(obj->rtype.pobj_info.model_num);
220                         break;
221
222                 case RT_POWERUP:
223                         if ( obj->rtype.vclip_info.vclip_num > -1 ) {
224                 //@@    #ifdef WINDOWS
225                 //@@            paging_touch_vclip_w(&Vclip[obj->rtype.vclip_info.vclip_num]);
226                 //@@    #else
227                                 paging_touch_vclip(&Vclip[obj->rtype.vclip_info.vclip_num]);
228                 //@@    #endif
229                         }
230                         break;
231
232                 case RT_MORPH:  break;
233
234                 case RT_FIREBALL: break;
235
236                 case RT_WEAPON_VCLIP: break;
237
238                 case RT_HOSTAGE:
239                         paging_touch_vclip(&Vclip[obj->rtype.vclip_info.vclip_num]);
240                         break;
241
242                 case RT_LASER: break;
243         }
244
245         switch (obj->type) {    
246         case OBJ_PLAYER:        
247                 v = get_explosion_vclip(obj, 0);
248                 if ( v > -1 )
249                         paging_touch_vclip(&Vclip[v]);
250                 break;
251         case OBJ_ROBOT:
252                 paging_touch_robot( obj->id );
253                 break;
254         case OBJ_CNTRLCEN:
255                 paging_touch_weapon( CONTROLCEN_WEAPON_NUM );
256                 if (Dead_modelnums[obj->rtype.pobj_info.model_num] != -1)       {
257                         paging_touch_model( Dead_modelnums[obj->rtype.pobj_info.model_num] );
258                 }
259                 break;
260         }
261 }
262
263         
264
265 void paging_touch_side( segment * segp, int sidenum )
266 {
267         int tmap1, tmap2;
268
269         if (!(WALL_IS_DOORWAY(segp,sidenum) & WID_RENDER_FLAG))
270                 return;
271         
272         tmap1 = segp->sides[sidenum].tmap_num;
273         paging_touch_wall_effects(tmap1);
274         tmap2 = segp->sides[sidenum].tmap_num2;
275         if (tmap2 != 0) {
276                 texmerge_get_cached_bitmap( tmap1, tmap2 );
277                 paging_touch_wall_effects( tmap2 & 0x3FFF );
278         } else  {
279                 PIGGY_PAGE_IN( Textures[tmap1] );
280         }
281
282         // PSX STUFF
283         #ifdef PSX_BUILD_TOOLS
284                 // If there is water on the level, then force the water splash into memory
285                 if(!(TmapInfo[tmap1].flags & TMI_VOLATILE) && (TmapInfo[tmap1].flags & TMI_WATER)) {
286                         bitmap_index Splash;
287                         Splash.index = 1098;
288                         PIGGY_PAGE_IN(Splash);
289                         Splash.index = 1099;
290                         PIGGY_PAGE_IN(Splash);
291                         Splash.index = 1100;
292                         PIGGY_PAGE_IN(Splash);
293                         Splash.index = 1101;
294                         PIGGY_PAGE_IN(Splash);
295                         Splash.index = 1102;
296                         PIGGY_PAGE_IN(Splash);
297                 }
298         #endif
299
300 }
301
302 void paging_touch_robot_maker( segment * segp )
303 {
304         segment2        *seg2p = &Segment2s[segp-Segments];
305
306         if ( seg2p->special == SEGMENT_IS_ROBOTMAKER )  {
307                 paging_touch_vclip(&Vclip[VCLIP_MORPHING_ROBOT]);
308                 if (RobotCenters[seg2p->matcen_num].robot_flags != 0) {
309                         int     i;
310                         uint    flags;
311                         int     robot_index;
312
313                         for (i=0;i<2;i++) {
314                                 robot_index = i*32;
315                                 flags = RobotCenters[seg2p->matcen_num].robot_flags[i];
316                                 while (flags) {
317                                         if (flags & 1)  {
318                                                 // Page in robot_index
319                                                 paging_touch_robot( robot_index );
320                                         }
321                                         flags >>= 1;
322                                         robot_index++;
323                                 }
324                         }
325                 }
326         }
327 }
328
329
330 void paging_touch_segment(segment * segp)
331 {
332         int sn;
333         int objnum;
334         segment2        *seg2p = &Segment2s[segp-Segments];
335
336         if ( seg2p->special == SEGMENT_IS_ROBOTMAKER )  
337                 paging_touch_robot_maker(segp);
338
339 //      paging_draw_orb();
340         for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++) {
341 //              paging_draw_orb();
342                 paging_touch_side( segp, sn );
343         }
344
345         for (objnum=segp->objects;objnum!=-1;objnum=Objects[objnum].next)       {
346 //              paging_draw_orb();
347                 paging_touch_object( &Objects[objnum] );
348         }
349 }
350
351
352
353 void paging_touch_walls()
354 {
355         int i,j;
356         wclip *anim;
357
358         for (i=0;i<Num_walls;i++) {
359 //              paging_draw_orb();
360                 if ( Walls[i].clip_num > -1 )   {
361                         anim = &WallAnims[Walls[i].clip_num];
362                         for (j=0; j < anim->num_frames; j++ )   {
363                                 PIGGY_PAGE_IN( Textures[anim->frames[j]] );
364                         }
365                 }
366         }
367 }
368
369 void paging_touch_all()
370 {
371         int black_screen;
372         int s;
373         
374         stop_time();
375
376         black_screen = gr_palette_faded_out;
377
378         if ( gr_palette_faded_out )     {
379                 gr_clear_canvas( BM_XRGB(0,0,0) );
380                 gr_palette_load( gr_palette );
381         }
382         
383 //@@    show_boxed_message(TXT_LOADING);
384
385         mprintf(( 0, "Loading all textures in mine..." ));
386         for (s=0; s<=Highest_segment_index; s++)        {
387                 paging_touch_segment( &Segments[s] );
388         }       
389         paging_touch_walls();
390
391         for ( s=0; s < N_powerup_types; s++ )   {
392                 if ( Powerup_info[s].vclip_num > -1 )   
393                         paging_touch_vclip(&Vclip[Powerup_info[s].vclip_num]);
394         }
395
396         for ( s=0; s<N_weapon_types; s++ )      {
397                 paging_touch_weapon(s);
398         }
399
400         for ( s=0; s < N_powerup_types; s++ )   {
401                 if ( Powerup_info[s].vclip_num > -1 )   
402                         paging_touch_vclip(&Vclip[Powerup_info[s].vclip_num]);
403         }
404
405
406         for (s=0; s<MAX_GAUGE_BMS; s++ )        {
407                 if ( Gauges[s].index )  {
408                         PIGGY_PAGE_IN( Gauges[s] );
409                 }
410         }
411         paging_touch_vclip( &Vclip[VCLIP_PLAYER_APPEARANCE] );
412         paging_touch_vclip( &Vclip[VCLIP_POWERUP_DISAPPEARANCE] );
413
414
415 #ifdef PSX_BUILD_TOOLS
416
417         //PSX STUFF
418         paging_touch_walls();
419         for(s=0; s<=Highest_object_index; s++) {
420                 paging_touch_object(&Objects[s]);
421         }
422
423
424         {
425                 char * p;
426                 extern int Current_level_num;
427                 extern ushort GameBitmapXlat[MAX_BITMAP_FILES];
428                 short Used[MAX_BITMAP_FILES];
429                 FILE * fp;
430                 char fname[128];
431                 int i;
432
433                 if (Current_level_num<0)                //secret level
434                         strcpy( fname, Secret_level_names[-Current_level_num-1] );
435                 else                                    //normal level
436                         strcpy( fname, Level_names[Current_level_num-1] );
437                 p = strchr( fname, '.' );
438                 if ( p ) *p = 0;
439                 strcat( fname, ".pag" );
440
441                 fp = fopen( fname, "wt" );
442                 for (i=0; i<MAX_BITMAP_FILES;i++ )      {
443                         Used[i] = 0;
444                 }
445                 for (i=0; i<MAX_BITMAP_FILES;i++ )      {
446                         Used[GameBitmapXlat[i]]++;
447                 }
448
449                 //cmp added so that .damage bitmaps are included for paged-in lights of the current level
450                 for (i=0; i<MAX_TEXTURES;i++) {
451                         if(Textures[i].index > 0 && Textures[i].index < MAX_BITMAP_FILES &&
452                                 Used[Textures[i].index] > 0 &&
453                                 TmapInfo[i].destroyed > 0 && TmapInfo[i].destroyed < MAX_BITMAP_FILES) {
454                                 Used[Textures[TmapInfo[i].destroyed].index] += 1;
455                                 mprintf((0, "HERE %d ", Textures[TmapInfo[i].destroyed].index));
456
457                                 PIGGY_PAGE_IN(Textures[TmapInfo[i].destroyed]);
458
459                         }
460                 }
461
462                 //      Force cockpit to be paged in.
463                 {
464                         bitmap_index bonk;
465                         bonk.index = 109;
466                         PIGGY_PAGE_IN(bonk);
467                 }
468
469                 // Force in the frames for markers
470                 {
471                         bitmap_index bonk2;
472                         bonk2.index = 2014;
473                         PIGGY_PAGE_IN(bonk2);
474                         bonk2.index = 2015;
475                         PIGGY_PAGE_IN(bonk2);
476                         bonk2.index = 2016;
477                         PIGGY_PAGE_IN(bonk2);
478                         bonk2.index = 2017;
479                         PIGGY_PAGE_IN(bonk2);
480                         bonk2.index = 2018;
481                         PIGGY_PAGE_IN(bonk2);
482                 }
483
484                 for (i=0; i<MAX_BITMAP_FILES;i++ )      {
485                         int paged_in = 1;
486                         // cmp debug
487                         //piggy_get_bitmap_name(i,fname);
488
489                         if (GameBitmaps[i].bm_flags & BM_FLAG_PAGED_OUT )
490                                 paged_in = 0;
491
492 //                      if (GameBitmapXlat[i]!=i)
493 //                              paged_in = 0;
494
495                         if ( !Used[i] )
496                                 paged_in = 0;
497                         if ( (i==47) || (i==48) )               // Mark red mplayer ship textures as paged in.
498                                 paged_in = 1;
499         
500                         if ( !paged_in )
501                                 fprintf( fp, "0,\t// Bitmap %d (%s)\n", i, "test\0"); // cmp debug fname );
502                         else
503                                 fprintf( fp, "1,\t// Bitmap %d (%s)\n", i, "test\0"); // cmp debug fname );
504                 }
505
506                 fclose(fp);
507         }
508 #endif
509
510         mprintf(( 0, "done\n" ));
511
512 //@@    clear_boxed_message();
513
514         if ( black_screen )     {
515                 gr_palette_clear();
516                 gr_clear_canvas( BM_XRGB(0,0,0) );
517         }
518         start_time();
519         reset_cockpit();                //force cockpit redraw next time
520
521 }
522