]> icculus.org git repositories - taylor/freespace2.git/blob - src/ship/shield.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / ship / shield.cpp
1 /*
2  * $Logfile: /Freespace2/code/Ship/Shield.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  *      Stuff pertaining to shield graphical effects, etc.
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:52  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:10  root
14  * Initial import.
15  *
16  * 
17  * 11    8/03/99 1:46p Dave
18  * Make opacity higher.
19  * 
20  * 10    8/03/99 11:28a Dave
21  * Fixed shield problem.
22  * 
23  * 9     8/02/99 10:42p Dave
24  * Make shields less opaque in the nebula.
25  * 
26  * 8     8/02/99 10:39p Dave
27  * Added colored shields. OoOoOoooOoo
28  * 
29  * 7     7/15/99 9:20a Andsager
30  * FS2_DEMO initial checkin
31  * 
32  * 6     3/10/99 6:50p Dave
33  * Changed the way we buffer packets for all clients. Optimized turret
34  * fired packets. Did some weapon firing optimizations.
35  * 
36  * 5     1/12/99 5:45p Dave
37  * Moved weapon pipeline in multiplayer to almost exclusively client side.
38  * Very good results. Bandwidth goes down, playability goes up for crappy
39  * connections. Fixed object update problem for ship subsystems.
40  * 
41  * 4     12/01/98 8:06a Dave
42  * Temporary checkin to fix some texture transparency problems in d3d.
43  * 
44  * 3     11/05/98 5:55p Dave
45  * Big pass at reducing #includes
46  * 
47  * 2     10/07/98 10:53a Dave
48  * Initial checkin.
49  * 
50  * 1     10/07/98 10:51a Dave
51  * 
52  * 65    5/25/98 12:12a Mike
53  * Make shield effect less CPU-intensive in software.  Always use lower
54  * detail versions.
55  * 
56  * 64    4/22/98 8:37p Mike
57  * Recover gracefully from exhausted MAX_GLOBAL_TRIS asserts.
58  * 
59  * 63    4/09/98 7:58p John
60  * Cleaned up tmapper code a bit.   Put NDEBUG around some ndebug stuff.
61  * Took out XPARENT flag settings in all the alpha-blended texture stuff.
62  * 
63  * 62    4/02/98 6:28p Lawrance
64  * remove shield code from demo build
65  * 
66  * 61    4/02/98 11:40a Lawrance
67  * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
68  * 
69  * 60    3/31/98 5:32p Mike
70  * Reduce size of some buffers.
71  * 
72  * 59    3/31/98 5:19p John
73  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
74  * bunch of debug stuff out of player file.  Made model code be able to
75  * unload models and malloc out only however many models are needed.
76  *  
77  * 
78  * 58    3/30/98 4:02p John
79  * Made machines with < 32 MB of RAM use every other frame of certain
80  * bitmaps.   Put in code to keep track of how much RAM we've malloc'd.
81  * 
82  * 57    3/30/98 12:18a Lawrance
83  * change some DEMO_RELEASE code to not compile code rather than return
84  * early
85  * 
86  * 56    3/29/98 11:33p Mike
87  * Speedup sheidl hit effect at detail levels 1, 3 (in 0..4).
88  * 
89  * 55    3/29/98 5:02p Adam
90  * changed ANIs referenced for shieldhit effect to all be
91  * shieldhit01a.ani.  There won't be different ones for different species
92  * like I once thought.
93  * 
94  * 54    3/29/98 4:05p John
95  * New paging code that loads everything necessary at level startup.
96  * 
97  * 53    3/27/98 9:06p Mike
98  * Make shield effect larger in lower detail levels (to match size in
99  * higher detail level) and handle changing detail level whiel shield
100  * effect playing.
101  * 
102  * 52    3/27/98 8:35p Mike
103  * Detail level support in shield effect system.
104  * 
105  * 51    3/16/98 4:07p Sandeep
106  * 
107  * 50    3/12/98 1:24p Mike
108  * When weapons linked, increase firing delay.
109  * Free up weapon slots for AI ships, if necessary.
110  * Backside render shield effect.
111  * Remove shield hit triangle if offscreen.
112  * 
113  * 49    3/02/98 5:42p John
114  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
115  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
116  * model_caching be on by default.  Made each cached model have it's own
117  * bitmap id.  Made asteroids not rotate when model_caching is on.  
118  * 
119  * 48    2/22/98 4:17p John
120  * More string externalization classification... 190 left to go!
121  * 
122  * 47    2/14/98 11:13p Mike
123  * Optimize a bit by making old ones go away if Poly_count high.
124  * 
125  * 46    2/06/98 9:10a Allender
126  * removed an Assert for multiplayer clients
127  * 
128  * 45    2/05/98 9:21p John
129  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
130  * game.
131  * 
132  * 44    1/28/98 11:15p Allender
133  * work on getting shield effect to show correctly in client side
134  * multiplayer
135  * 
136  * 43    12/30/97 4:26p Lawrance
137  * Remove .ani from shield animations, avoids bmpman warning
138  * 
139  * $NoKeywords: $
140  */
141
142 //      Detail level effects (Detail.shield_effects)
143 //              0               Nothing rendered
144 //              1               An animating bitmap rendered per hit, not shrink-wrapped.  Lasts half time.  One per ship.
145 //              2               Animating bitmap per hit, not shrink-wrapped.  Lasts full time.  Unlimited.
146 //              3               Shrink-wrapped texture.  Lasts half-time.
147 //              4               Shrink-wrapped texture.  Lasts full-time.
148
149 #include <math.h>
150
151 #include "2d.h"
152 #include "3d.h"
153 #include "model.h"
154 #include "tmapper.h"
155 #include "floating.h"
156 #include "fvi.h"
157 #include "lighting.h"
158 #include "fireballs.h"
159 #include "fix.h"
160 #include "bmpman.h"
161 #include        "object.h"
162 #include "player.h"             //      #include of "player.h" is only for debugging!
163 #include "timer.h"
164 #include "freespace.h"
165 #include "packunpack.h"
166 #include "animplay.h"
167 #include "shiphit.h"
168 #include "missionparse.h"
169 #include "multimsgs.h"
170 #include "multi.h"
171
172 int     New_shield_system = 1;
173 int     Show_shield_mesh = 0;
174
175 #ifndef DEMO // not for FS2_DEMO
176
177 //      One unit in 3d means this in the shield hit texture map.
178 //#define       SHIELD_HIT_SCALE        0.075f                  //      Scale decreased by MK on 12/18/97, made about 1/4x as large. Note, larger constant means smaller effect
179 #define SHIELD_HIT_SCALE        0.15f                   //      Doubled on 12/23/97 by MK.  Was overflowing.  See todo item #924.
180 //#define       MAX_SHIELD_HITS 20
181 #define MAX_TRIS_PER_HIT        40                                      //      Number of triangles per shield hit, maximum.
182 #define MAX_SHIELD_HITS 20                                      //      Maximum number of active shield hits.
183 #define MAX_SHIELD_TRI_BUFFER   (MAX_SHIELD_HITS*20) // Persistent buffer of triangle comprising all active shield hits.
184 #define SHIELD_HIT_DURATION     (3*F1_0/4)      //      Duration, in milliseconds, of shield hit effect
185
186 #define SH_UNUSED                       -1                                      //      Indicates an unused record in Shield_hits
187 #define SH_TYPE_1                       1                                       //      Indicates Shield_hits record is of type 1.
188
189 #define UV_MAX                          (63.95f/64.0f)  //      max allowed value until tmapper bugs fixed, 1/24/97
190
191 float   Shield_scale = SHIELD_HIT_SCALE;
192
193 //      Structure which mimics the shield_tri structure in model.h.  Since the global shield triangle
194 // array needs the vertex information, we will acutally store the information in this
195 // structure instead of the indices into the vertex list
196 typedef struct gshield_tri {
197         int                             used;                                                   //      Set if this triangle is currently in use.
198         int                             trinum;                                         //      a debug parameter
199         fix                             creation_time;                          //      time at which created.
200         shield_vertex   verts[4];                                       //      Triangles, but at lower detail level, a square.
201 } gshield_tri;
202
203 typedef struct shield_hit {
204         int     start_time;                                                             //      start time of this object
205         int     type;                                                                           //      type, probably the weapon type, to indicate the bitmap to use
206         int     objnum;                                                                 //      Object index, needed to get current orientation, position.
207         int     num_tris;                                                               //      Number of Shield_tris comprising this shield.
208         int     tri_list[MAX_TRIS_PER_HIT];             //      Indices into Shield_tris, triangles for this shield hit.
209         ubyte rgb[3];                                                                   // rgb colors
210 } shield_hit;
211
212 //      Stores point at which shield was hit.
213 //      Gets processed in frame interval.
214 typedef struct shield_point {
215         int             objnum;                                                         //      Object that was hit.
216         int             shield_tri;                                                     //      Triangle in shield mesh that took hit.
217         vector  hit_point;                                                      //      Point in global 3-space of hit.
218 } shield_point;
219
220 #define MAX_SHIELD_POINTS       100
221 shield_point    Shield_points[MAX_SHIELD_POINTS];
222 int             Num_shield_points;
223 int             Num_multi_shield_points;                                        // used by multiplayer clients
224
225 gshield_tri     Global_tris[MAX_SHIELD_TRI_BUFFER];     //      The persistent triangles, part of shield hits.
226 int     Num_tris;                                                               //      Number of triangles in current shield.  Would be a local, but needed in numerous routines.
227
228 shield_hit      Shield_hits[MAX_SHIELD_HITS];
229
230 typedef struct shield_ani {
231         char            *filename;
232         int             first_frame;
233         int             nframes;
234 } shield_ani;
235
236 //XSTR:OFF
237 #define MAX_SHIELD_ANIMS MAX_SPECIES_NAMES
238 shield_ani Sheild_ani[MAX_SHIELD_ANIMS] = {
239         { "shieldhit01a", -1, -1 },
240         { "shieldhit01a", -1, -1 },
241         { "shieldhit01a", -1, -1 },
242 };
243 //XSTR:ON
244
245 int Shield_bitmaps_loaded = 0;
246
247 //      This is a recursive function, so prototype it.
248 extern void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec);
249
250 void load_shield_hit_bitmap()
251 {
252         #ifndef DEMO // not for FS2_DEMO
253
254         int i;
255         // Check if we've already allocated the shield effect bitmaps
256         if ( Shield_bitmaps_loaded )
257                 return;
258
259         Shield_bitmaps_loaded = 1;
260
261         for (i=0; i<MAX_SHIELD_ANIMS; i++ )     {
262                 Sheild_ani[i].first_frame = bm_load_animation(Sheild_ani[i].filename, &Sheild_ani[i].nframes,NULL, 1);
263                 if ( Sheild_ani[i].first_frame < 0 )
264                         Int3();
265         }
266
267         #endif
268 }
269
270 void shield_hit_page_in()
271 {
272         int i;
273
274         if ( !Shield_bitmaps_loaded )   {
275                 load_shield_hit_bitmap();
276         }
277
278         for (i=0; i<MAX_SHIELD_ANIMS; i++ )     {
279                 bm_page_in_xparent_texture( Sheild_ani[i].first_frame, Sheild_ani[i].nframes );
280         }
281 }
282
283
284 //      Initialize shield hit system.  Called from game_level_init()
285 void shield_hit_init()
286 {
287         int     i;
288
289         for (i=0; i<MAX_SHIELD_HITS; i++)
290                 Shield_hits[i].type = SH_UNUSED;
291
292         for (i=0; i<MAX_SHIELD_TRI_BUFFER; i++) {
293                 Global_tris[i].used = 0;
294                 Global_tris[i].creation_time = Missiontime;
295         }
296
297         Num_multi_shield_points = 0;
298
299         load_shield_hit_bitmap();
300 }
301
302 // ---------------------------------------------------------------------
303 // release_shield_hit_bitmap()
304 //
305 // Release the storage allocated to store the shield effect.
306 //
307 void release_shield_hit_bitmap()
308 {
309         if ( !Shield_bitmaps_loaded )
310                 return;
311
312         // This doesn't need to do anything; the bitmap manager will
313         // release everything.
314 }
315
316 int     Poly_count = 0;
317
318 // ---------------------------------------------------------------------
319 // shield_hit_close()
320 //
321 // De-initalize the shield hit system.  Called from game_level_close().
322 //
323 // TODO: We should probably not bother releasing the shield hit bitmaps every level.
324 //
325 void shield_hit_close()
326 {
327         release_shield_hit_bitmap();
328 }
329
330 void shield_frame_init()
331 {
332         //nprintf(("AI", "Frame %i: Number of shield hits: %i, polycount = %i\n", Framecount, Num_shield_points, Poly_count));
333
334         Poly_count = 0;
335
336         Num_shield_points = 0;
337 }
338
339 void create_low_detail_poly(int global_index, vector *tcp, vector *rightv, vector *upv)
340 {
341         float           scale;
342         gshield_tri     *trip;
343
344         trip = &Global_tris[global_index];
345
346         scale = vm_vec_mag(tcp) * 2.0f;
347
348         vm_vec_scale_add(&trip->verts[0].pos, tcp, rightv, -scale/2.0f);
349         vm_vec_scale_add2(&trip->verts[0].pos, upv, scale/2.0f);
350
351         vm_vec_scale_add(&trip->verts[1].pos, &trip->verts[0].pos, rightv, scale);
352
353         vm_vec_scale_add(&trip->verts[2].pos, &trip->verts[1].pos, upv, -scale);
354
355         vm_vec_scale_add(&trip->verts[3].pos, &trip->verts[2].pos, rightv, -scale);
356
357         //      Set u, v coordinates.
358         //      Note, this need only be done once, as it's common for all explosions.
359         trip->verts[0].u = 0.0f;
360         trip->verts[0].v = 0.0f;
361
362         trip->verts[1].u = 1.0f;
363         trip->verts[1].v = 0.0f;
364
365         trip->verts[2].u = 1.0f;
366         trip->verts[2].v = 1.0f;
367
368         trip->verts[3].u = 0.0f;
369         trip->verts[3].v = 1.0f;
370
371 }
372
373 //      ----------------------------------------------------------------------------------------------------
374 //      Given a shield triangle, compute the uv coordinates at its vertices given
375 //      the center point of the explosion texture, distance to center of shield and
376 //      right and up vectors.
377 //      For small distances (relative to radius), coordinates can be computed using
378 //      distance.  For larger values, should comptue angle.
379 void rs_compute_uvs(shield_tri *stp, shield_vertex *verts, vector *tcp, float radius, vector *rightv, vector *upv)
380 {
381         int     i;
382         shield_vertex *sv;
383
384         for (i=0; i<3; i++) {
385                 vector  v2cp;
386
387                 sv = &verts[stp->verts[i]];
388
389                 vm_vec_sub(&v2cp, &sv->pos, tcp);
390                 sv->u = vm_vec_dot(&v2cp, rightv) * Shield_scale + 0.5f;
391                 sv->v = - vm_vec_dot(&v2cp, upv) * Shield_scale + 0.5f;
392
393                 if (sv->u > UV_MAX){
394                         sv->u = UV_MAX;
395                 }
396
397                 if (sv->u < 0.0f){
398                         sv->u = 0.0f;
399                 }
400
401                 if (sv->v > UV_MAX){
402                         sv->v = UV_MAX;
403                 }
404
405                 if (sv->v < 0.0f){
406                         sv->v = 0.0f;
407                 }
408
409                 // mprintf(("u, v = %7.3f %7.3f\n", stp->verts[i].u, stp->verts[i].v));
410         }
411
412         // mprintf(("\n"));
413 }
414
415 //      ----------------------------------------------------------------------------------------------------
416 //      Free records in Global_tris previously used by Shield_hits[shnum].tri_list
417 void free_global_tri_records(int shnum)
418 {
419         int     i;
420
421         Assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
422
423         //mprintf(("Freeing up %i global records.\n", Shield_hits[shnum].num_tris));
424
425         for (i=0; i<Shield_hits[shnum].num_tris; i++){
426                 Global_tris[Shield_hits[shnum].tri_list[i]].used = 0;
427         }
428 }
429
430 void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vector *pos, ubyte r, ubyte g, ubyte b)
431 {
432         matrix  m;
433         int             j;
434         vector  pnt;
435         vertex  verts[4];
436
437         vm_copy_transpose_matrix(&m,orient);
438
439         for (j=0; j<4; j++ )    {
440                 // Rotate point into world coordinates
441                 vm_vec_rotate(&pnt, &trip->verts[j].pos, &m);
442                 vm_vec_add2(&pnt, pos);
443
444                 // Pnt is now the x,y,z world coordinates of this vert.
445                 g3_rotate_vertex(&verts[j], &pnt);
446                 verts[j].u = trip->verts[j].u;
447                 verts[j].v = trip->verts[j].v;
448         }       
449
450         verts[0].r = r;
451         verts[0].g = g;
452         verts[0].b = b;
453         verts[1].r = r;
454         verts[1].g = g;
455         verts[1].b = b;
456         verts[2].r = r;
457         verts[2].g = g;
458         verts[2].b = b;
459         verts[3].r = r;
460         verts[3].g = g;
461         verts[3].b = b;
462
463         vector  norm;
464         vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos);
465         vertex  *vertlist[4];
466         if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 )    {
467                 vertlist[0] = &verts[3]; 
468                 vertlist[1] = &verts[2];
469                 vertlist[2] = &verts[1]; 
470                 vertlist[3] = &verts[0]; 
471                 g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
472         } else {
473                 vertlist[0] = &verts[0]; 
474                 vertlist[1] = &verts[1];
475                 vertlist[2] = &verts[2]; 
476                 vertlist[3] = &verts[3]; 
477                 g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
478         }
479 }
480
481 //      Render one triangle of a shield hit effect on one ship.
482 //      Each frame, the triangle needs to be rotated into global coords.
483 //      trip            pointer to triangle in global array
484 //      orient  orientation of object shield is associated with
485 //      pos             center point of object
486 void render_shield_triangle(gshield_tri *trip, matrix *orient, vector *pos, ubyte r, ubyte g, ubyte b)
487 {
488         matrix  m;
489         int             j;
490         vector  pnt;
491         vertex  *verts[3];
492         vertex  points[3];
493
494         if (trip->trinum == -1)
495                 return; //      Means this is a quad, must have switched detail_level.
496
497         vm_copy_transpose_matrix(&m,orient);
498
499         for (j=0; j<3; j++ )    {
500                 // Rotate point into world coordinates
501                 vm_vec_rotate(&pnt, &trip->verts[j].pos, &m);
502                 vm_vec_add2(&pnt, pos);
503
504                 // Pnt is now the x,y,z world coordinates of this vert.
505                 // For this example, I am just drawing a sphere at that point.
506                 g3_rotate_vertex(&points[j], &pnt);
507                 points[j].u = trip->verts[j].u;
508                 points[j].v = trip->verts[j].v;
509                 Assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX));
510                 Assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX));
511                 verts[j] = &points[j];
512         }
513
514         verts[0]->r = r;
515         verts[0]->g = g;
516         verts[0]->b = b;
517         verts[1]->r = r;
518         verts[1]->g = g;
519         verts[1]->b = b;
520         verts[2]->r = r;
521         verts[2]->g = g;
522         verts[2]->b = b;
523
524         vector  norm;
525         Poly_count++;
526         vm_vec_perp(&norm,(vector *)&verts[0]->x,(vector *)&verts[1]->x,(vector*)&verts[2]->x);
527         if ( vm_vec_dot(&norm,(vector *)&verts[1]->x ) >= 0.0 ) {
528                 vertex  *vertlist[3];
529                 vertlist[0] = verts[2]; 
530                 vertlist[1] = verts[1]; 
531                 vertlist[2] = verts[0]; 
532                 g3_draw_poly( 3, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
533         } else {
534                 g3_draw_poly( 3, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
535         }
536 }
537
538 MONITOR(NumShieldRend);
539
540 //      Render a shield mesh in the global array Shield_hits[]
541 void render_shield(int shield_num) //, matrix *orient, vector *centerp)
542 {
543         int             i;
544         vector  *centerp;
545         matrix  *orient;
546         object  *objp;
547         ship            *shipp;
548         ship_info       *si;
549
550         if (Shield_hits[shield_num].type == SH_UNUSED)  {
551                 return;
552         }
553
554         Assert(Shield_hits[shield_num].objnum >= 0);
555
556         objp = &Objects[Shield_hits[shield_num].objnum];
557
558         if (objp->flags & OF_NO_SHIELDS)        {
559                 return;
560         }
561
562         //      If this object didn't get rendered, don't render its shields.  In fact, make the shield hit go away.
563         if (!(objp->flags & OF_WAS_RENDERED)) {
564                 Shield_hits[shield_num].type = SH_UNUSED;
565                 return;
566         }
567
568         //      At detail levels 1, 3, animations play at double speed to reduce load.
569         if (!D3D_enabled || (Detail.shield_effects == 1) || (Detail.shield_effects == 3)) {
570                 Shield_hits[shield_num].start_time -= Frametime;
571         }
572
573         MONITOR_INC(NumShieldRend,1);
574
575         shipp = &Ships[objp->instance];
576         si = &Ship_info[shipp->ship_info_index];
577
578         // objp, shipp, and si are now setup correctly
579
580         //      If this ship is in its deathroll, make the shield hit effects go away faster.
581         if (shipp->flags & SF_DYING)    {
582                 Shield_hits[shield_num].start_time -= fl2f(2*flFrametime);
583         }
584
585         //      Detail level stuff.  When lots of shield hits, maybe make them go away faster.
586         if (Poly_count > 50) {
587                 if (Shield_hits[shield_num].start_time + (SHIELD_HIT_DURATION*50)/Poly_count < Missiontime) {
588                         Shield_hits[shield_num].type = SH_UNUSED;
589                         free_global_tri_records(shield_num);
590                         // nprintf(("AI", "* "));
591                         return;
592                 }
593         } else if ((Shield_hits[shield_num].start_time + SHIELD_HIT_DURATION) < Missiontime) {
594                 Shield_hits[shield_num].type = SH_UNUSED;
595                 free_global_tri_records(shield_num);
596                 return;
597         }
598
599         orient = &objp->orient;
600         centerp = &objp->pos;
601
602         int bitmap_id, frame_num, n;
603
604         // mprintf(("Percent = %7.3f\n", f2fl(Missiontime - Shield_hits[shield_num].start_time)));
605
606         n = si->species;                
607         // Do some sanity checking
608         Assert( (n >=0) && (n<MAX_SPECIES_NAMES));
609         Assert( (n >=0) && (n<MAX_SHIELD_ANIMS));
610
611         frame_num = fl2i( f2fl(Missiontime - Shield_hits[shield_num].start_time) * Sheild_ani[n].nframes);
612         if ( frame_num >= Sheild_ani[n].nframes )       {
613                 frame_num = Sheild_ani[n].nframes - 1;
614         } else if ( frame_num < 0 )     {
615                 mprintf(( "HEY! Missiontime went backwards! (Shield.cpp)\n" ));
616                 frame_num = 0;
617         }
618         bitmap_id = Sheild_ani[n].first_frame + frame_num;
619
620         float alpha = 0.9999f;
621         if(The_mission.flags & MISSION_FLAG_FULLNEB){
622                 alpha *= 0.85f;
623         }
624         gr_set_bitmap(bitmap_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha );
625
626         if (!D3D_enabled || (Detail.shield_effects == 1) || (Detail.shield_effects == 2)) {
627                 if ( bitmap_id != - 1 ) {
628                         render_low_detail_shield_bitmap(&Global_tris[Shield_hits[shield_num].tri_list[0]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
629                 }
630         } else {
631
632                 // AL 06/01/97 don't use Assert() until issue with Missiontime being reset to 0 are worked out
633                 if ( bitmap_id != - 1 ) {
634                         for (i=0; i<Shield_hits[shield_num].num_tris; i++) {
635                                 //if (Missiontime == Shield_hits[shield_num].start_time)
636                                 //      nprintf(("AI", "Frame %i: Render triangle %i.\n", Framecount, Global_tris[Shield_hits[shield_num].tri_list[i]].trinum));
637                                 render_shield_triangle(&Global_tris[Shield_hits[shield_num].tri_list[i]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
638                         }
639                 }
640         }
641 }
642
643 //      Render all the shield hits  in the global array Shield_hits[]
644 //      This is a temporary function.  Shield hit rendering will at least have to
645 // occur with the ship, perhaps even internal to the ship.
646 void render_shields()
647 {
648         int     i;
649
650         if (Detail.shield_effects == 0){
651                 return; //      No shield effect rendered at lowest detail level.
652         }
653
654         if (!New_shield_system){
655                 return;
656         }
657
658         for (i=0; i<MAX_SHIELD_HITS; i++){
659                 if (Shield_hits[i].type != SH_UNUSED){
660                         render_shield(i);
661                 }
662         }
663 }
664
665
666 // -----------------------------------------------------------------------------------------------------
667 void create_tris_containing(vector *vp, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
668 {
669         int     i, j;
670         shield_vertex *verts;
671
672         verts = shieldp->verts;
673
674         for (i=0; i<Num_tris; i++) {
675                 if ( !shieldp->tris[i].used ) {
676                         for (j=0; j<3; j++) {
677                                 vector v;
678
679                                 v = verts[shieldp->tris[i].verts[j]].pos;
680                                 if ((vp->x == v.x) && (vp->y == v.y) && (vp->z == v.z))
681                                         create_shield_from_triangle(i, orient, shieldp, tcp, centerp, radius, rvec, uvec);
682                         }
683                 }
684         }
685 }
686
687 void visit_children(int trinum, int vertex_index, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
688 {
689         shield_vertex *sv;
690
691         sv = &(shieldp->verts[shieldp->tris[trinum].verts[vertex_index]]);
692
693         if ( (sv->u > 0.0f) && (sv->u < UV_MAX) && (sv->v > 0.0f) && (sv->v < UV_MAX))
694                         create_tris_containing(&sv->pos, orient, shieldp, tcp, centerp, radius, rvec, uvec);
695 }
696
697 int     Gi_max = 0;
698
699 int get_free_global_shield_index()
700 {
701         int     gi = 0;
702
703         while ((gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
704                 gi++;
705         }
706
707         //      If couldn't find one, choose a random one.
708         if (gi == MAX_SHIELD_TRI_BUFFER)
709                 gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
710
711         return gi;
712 }
713
714 int get_global_shield_tri()
715 {
716         int     shnum;
717
718         //      Find unused shield hit buffer
719         for (shnum=0; shnum<MAX_SHIELD_HITS; shnum++)
720                 if (Shield_hits[shnum].type == SH_UNUSED)
721                         break;
722
723         if (shnum == MAX_SHIELD_HITS) {
724                 //nprintf(("AI", "Warning: Shield_hit buffer full!  Stealing an old one!\n"));
725                 shnum = myrand() % MAX_SHIELD_HITS;
726         }
727
728         Assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
729
730         return shnum;
731 }
732
733 void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
734 {
735         //nprintf(("AI", "[%3i] ", trinum));
736
737         rs_compute_uvs( &shieldp->tris[trinum], shieldp->verts, tcp, radius, rvec, uvec);
738
739         //Assert(trinum < MAX_SHIELD_HITS);
740         shieldp->tris[trinum].used = 1;
741
742 //mprintf(("%i ", trinum));
743         visit_children(trinum, 0, orient, shieldp, tcp, centerp, radius, rvec, uvec);
744         visit_children(trinum, 1, orient, shieldp, tcp, centerp, radius, rvec, uvec);
745         visit_children(trinum, 2, orient, shieldp, tcp, centerp, radius, rvec, uvec);
746 }
747
748 //      Copy information from Current_tris to Global_tris, stuffing information
749 //      in a slot in Shield_hits.  The Global_tris array is not a shield_tri structure.
750 // We need to store vertex information in the global array since the vertex list
751 // will not be available to us when we actually use the array.
752 void copy_shield_to_globals( int objnum, shield_info *shieldp )
753 {
754         int     i, j;
755         int     gi = 0;
756         int     count = 0;                      //      Number of triangles in this shield hit.
757         int     shnum;                          //      shield hit number, index in Shield_hits.
758
759         shnum = get_global_shield_tri();
760         
761         Shield_hits[shnum].type = SH_TYPE_1;
762         // mprintf(("Creating hit #%i at time = %7.3f\n", shnum, f2fl(Missiontime)));
763
764         for (i = 0; i < shieldp->ntris; i++ ) {
765                 if ( shieldp->tris[i].used ) {
766                         while ( (gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
767                                 gi++;
768                         }
769                         
770                         //      If couldn't find one, choose a random one.
771                         if (gi == MAX_SHIELD_TRI_BUFFER)
772                                 gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
773
774                         Global_tris[gi].used = shieldp->tris[i].used;
775                         Global_tris[gi].trinum = i;
776                         Global_tris[gi].creation_time = Missiontime;
777
778                         // copy the pos/u/v elements of the shield_vertex structure into the shield vertex structure for this global triangle.
779                         for (j = 0; j < 3; j++)
780                                 Global_tris[gi].verts[j] = shieldp->verts[shieldp->tris[i].verts[j]];
781                         Shield_hits[shnum].tri_list[count++] = gi;
782
783                         if (count >= MAX_TRIS_PER_HIT) {
784                                 mprintf(("Warning: Too many triangles in shield hit.\n"));
785                                 break;
786                         }
787                 }
788         }
789
790         Shield_hits[shnum].num_tris = count;
791         Shield_hits[shnum].start_time = Missiontime;
792         Shield_hits[shnum].objnum = objnum;
793
794         Shield_hits[shnum].rgb[0] = 255;
795         Shield_hits[shnum].rgb[1] = 255;
796         Shield_hits[shnum].rgb[2] = 255;
797         if((objnum >= 0) && (objnum < MAX_OBJECTS) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) && (Objects[objnum].instance < MAX_SHIPS) && (Ships[Objects[objnum].instance].ship_info_index >= 0) && (Ships[Objects[objnum].instance].ship_info_index < Num_ship_types)){
798                 ship_info *sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
799                 
800                 Shield_hits[shnum].rgb[0] = sip->shield_color[0];
801                 Shield_hits[shnum].rgb[1] = sip->shield_color[1];
802                 Shield_hits[shnum].rgb[2] = sip->shield_color[2];
803         }
804 }
805
806 //      ***** This is the version that works on a quadrant basis.
807 //      Return absolute amount of damage not applied.
808 float apply_damage_to_shield(object *objp, int shield_quadrant, float damage)
809 {
810         ai_info *aip;
811
812         // multiplayer clients bail here if nodamage
813         // if(MULTIPLAYER_CLIENT && (Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
814         if(MULTIPLAYER_CLIENT){
815                 return damage;
816         }
817
818         if ( (shield_quadrant < 0)  || (shield_quadrant > 3) ) return damage;   
819         
820         Assert(objp->type == OBJ_SHIP);
821         aip = &Ai_info[Ships[objp->instance].ai_index];
822         aip->last_hit_quadrant = shield_quadrant;
823
824         objp->shields[shield_quadrant] -= damage;
825
826         if (objp->shields[shield_quadrant] < 0.0f) {
827                 float   remaining_damage;
828
829                 remaining_damage = -objp->shields[shield_quadrant];
830                 objp->shields[shield_quadrant] = 0.0f;
831                 //nprintf(("AI", "Applied %7.3f damage to quadrant #%i, %7.3f passes through\n", damage - remaining_damage, quadrant_num, remaining_damage));
832                 return remaining_damage;
833         } else {
834                 //nprintf(("AI", "Applied %7.3f damage to quadrant #%i\n", damage, quadrant_num));
835                 return 0.0f;
836         }
837                 
838 }
839
840 //      At lower detail levels, shield hit effects are a single texture, applied to one enlarged triangle.
841 void create_shield_low_detail(int objnum, int model_num, matrix *orient, vector *centerp, vector *tcp, int tr0, shield_info *shieldp)
842 {
843         matrix  tom;
844         int             gi;
845         int             shnum;
846
847         shnum = get_global_shield_tri();
848         Shield_hits[shnum].type = SH_TYPE_1;
849
850         gi = get_free_global_shield_index();
851
852         Global_tris[gi].used = 1;
853         Global_tris[gi].trinum = -1;            //      This tells triangle renderer to not render in case detail_level was switched.
854         Global_tris[gi].creation_time = Missiontime;
855
856         Shield_hits[shnum].tri_list[0] = gi;
857         Shield_hits[shnum].num_tris = 1;
858         Shield_hits[shnum].start_time = Missiontime;
859         Shield_hits[shnum].objnum = objnum;
860
861         Shield_hits[shnum].rgb[0] = 255;
862         Shield_hits[shnum].rgb[1] = 255;
863         Shield_hits[shnum].rgb[2] = 255;
864         if((objnum >= 0) && (objnum < MAX_OBJECTS) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) && (Objects[objnum].instance < MAX_SHIPS) && (Ships[Objects[objnum].instance].ship_info_index >= 0) && (Ships[Objects[objnum].instance].ship_info_index < Num_ship_types)){
865                 ship_info *sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
866                 
867                 Shield_hits[shnum].rgb[0] = sip->shield_color[0];
868                 Shield_hits[shnum].rgb[1] = sip->shield_color[1];
869                 Shield_hits[shnum].rgb[2] = sip->shield_color[2];
870         }
871
872         vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
873         //rs_compute_uvs( &shieldp->tris[tr0], shieldp->verts, tcp, Objects[objnum].radius, &tom.rvec, &tom.uvec);
874
875         create_low_detail_poly(gi, tcp, &tom.rvec, &tom.uvec);
876
877 }
878
879 // Algorithm for shrink-wrapping a texture across a triangular mesh.
880 // 
881 // - Given a point of intersection, tcp (local to objnum)
882 // - Vector to center of shield from tcp is v2c.
883 // - Using v2c, compute right and down vectors.  These are the vectors of
884 //   increasing u and v, respectively.
885 // - Triangle of intersection of tcp is tr0.
886 // - For 3 points in tr0, compute u,v coordinates using up and down vectors
887 //   from center point, tcp.  Need to know size of explosion texture.  N units
888 //   along right vector corresponds to O units in explosion texture space.
889 // - For each edge, if either endpoint was outside texture bounds, recursively
890 //   apply previous and current step.
891 // 
892 // Output of above is a list of triangles with u,v coordinates.  These u,v
893 // coordinates will have to be clipped against the explosion texture bounds.
894
895 void create_shield_explosion(int objnum, int model_num, matrix *orient, vector *centerp, vector *tcp, int tr0)
896 {
897 //      vector  v2c;            //      Vector to center from point tcp
898         matrix  tom;            //      Texture Orientation Matrix
899 //      float           radius; // Radius of shield, computed as distance from tcp to objp->pos.
900         shield_info     *shieldp;
901         polymodel       *pm;
902         int             i;
903
904         if (!New_shield_system)
905                 return;
906
907         if (Objects[objnum].flags & OF_NO_SHIELDS)
908                 return;
909
910         pm = model_get(model_num);
911         Num_tris = pm->shield.ntris;
912         //Assert(Num_tris < MAX_SHIELD_HITS);
913         shieldp = &pm->shield;
914
915         if (Num_tris == 0)
916                 return;
917
918         //nprintf(("AI", "Frame %i: Creating explosion on %i.\n", Framecount, objnum));
919
920         if (!D3D_enabled || (Detail.shield_effects == 1) || (Detail.shield_effects == 2)) {
921                 create_shield_low_detail(objnum, model_num, orient, centerp, tcp, tr0, shieldp);
922                 return;
923         }
924
925         for (i=0; i<Num_tris; i++)
926                 shieldp->tris[i].used = 0;
927
928         //      Compute orientation matrix from normal of surface hit.
929         //      Note, this will cause the shape of the bitmap to change abruptly
930         //      as the impact point moves to another triangle.  To prevent this,
931         //      you could average the normals at the vertices, then interpolate the
932         //      normals from the vertices to get a smoothly changing normal across the face.
933         //      I had tried using the vector from the impact point to the center, which
934         //      changes smoothly, but this looked surprisingly bad.
935         vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
936         //vm_vec_sub(&v2c, tcp, &Objects[objnum].pos);
937
938         //      Create the shield from the current triangle, as well as its neighbors.
939         create_shield_from_triangle(tr0, orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.rvec, &tom.uvec);
940         //nprintf(("AI", "\n"));
941         for (i=0; i<3; i++)
942                 create_shield_from_triangle(shieldp->tris[tr0].neighbors[i], orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.rvec, &tom.uvec);
943         
944         copy_shield_to_globals(objnum, shieldp);
945         // render_shield(orient, centerp);
946 }
947
948 MONITOR(NumShieldHits);
949
950 //      Add data for a shield hit.
951 void add_shield_point(int objnum, int tri_num, vector *hit_pos)
952 {
953         //Assert(Num_shield_points < MAX_SHIELD_POINTS);
954         if (Num_shield_points >= MAX_SHIELD_POINTS)
955                 return;
956
957         MONITOR_INC(NumShieldHits,1);
958
959         Shield_points[Num_shield_points].objnum = objnum;
960         Shield_points[Num_shield_points].shield_tri = tri_num;
961         Shield_points[Num_shield_points].hit_point = *hit_pos;
962
963         Num_shield_points++;
964
965         // in multiplayer -- send the shield hit data to the clients
966         // if ( MULTIPLAYER_MASTER && !(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
967                 // send_shield_explosion_packet( objnum, tri_num, *hit_pos );
968         // }
969
970         Ships[Objects[objnum].instance].shield_hits++;
971 }
972
973 // ugh!  I wrote a special routine to store shield points for clients in multiplayer
974 // games.  Problem is initilization and flow control of normal gameplay make this problem
975 // more than trivial to solve.  Turns out that I think I can just keep track of the
976 // shield_points for multiplayer in a separate count -- then assign the multi count to
977 // the normal count at the correct time.
978 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos)
979 {
980         //Assert(Num_multi_shield_points < MAX_SHIELD_POINTS);
981
982         if (Num_multi_shield_points >= MAX_SHIELD_POINTS)
983                 return;
984
985         Shield_points[Num_shield_points].objnum = objnum;
986         Shield_points[Num_shield_points].shield_tri = tri_num;
987         Shield_points[Num_shield_points].hit_point = *hit_pos;
988
989         Num_multi_shield_points++;
990 }
991
992 // sets up the shield point hit information for multiplayer clients
993 void shield_point_multi_setup()
994 {
995         int i;
996
997         Assert( MULTIPLAYER_CLIENT );
998
999         if ( Num_multi_shield_points == 0 )
1000                 return;
1001
1002         Num_shield_points = Num_multi_shield_points;
1003         for (i = 0; i < Num_shield_points; i++ ){
1004                 Ships[Objects[Shield_points[i].objnum].instance].shield_hits++;
1005         }
1006
1007         Num_multi_shield_points = 0;
1008 }
1009
1010
1011 //      Create all the shield explosions that occurred on object *objp this frame.
1012 void create_shield_explosion_all(object *objp)
1013 {
1014         int     i;
1015         int     num;
1016         int     count;
1017         int     objnum;
1018         ship    *shipp;
1019
1020         if (Detail.shield_effects == 0){
1021                 return; 
1022         }
1023
1024         num = objp->instance;
1025         shipp = &Ships[num];
1026
1027         count = shipp->shield_hits;
1028         objnum = objp-Objects;
1029
1030         for (i=0; i<Num_shield_points; i++) {
1031                 if (Shield_points[i].objnum == objnum) {
1032                         create_shield_explosion(objnum, shipp->modelnum, &objp->orient, &objp->pos, &Shield_points[i].hit_point, Shield_points[i].shield_tri);
1033                         count--;
1034                         if (count <= 0){
1035                                 break;
1036                         }
1037                 }
1038         }
1039
1040         //mprintf(("Creating %i explosions took %7.3f seconds\n", shipp->shield_hits, (float) (timer_get_milliseconds() - start_time)/1000.0f));
1041
1042         // some some reason, clients seem to have a bogus count valud on occation.  I"ll chalk it up
1043         // to missed packets :-)  MWA 2/6/98
1044         if ( !MULTIPLAYER_CLIENT ){
1045                 Assert(count == 0);     //      Couldn't find all the alleged shield hits.  Bogus!
1046         }
1047 }
1048
1049 int     Break_value = -1;
1050
1051 //      This is a debug function.
1052 //      Draw the whole shield as a wireframe mesh, not looking at the current
1053 //      integrity.
1054 #ifndef NDEBUG
1055 void ship_draw_shield( object *objp)
1056 {
1057         int             model_num;
1058         matrix  m;
1059         int             i;
1060         vector  pnt;
1061         polymodel * pm; 
1062
1063         if (!New_shield_system)
1064                 return;
1065
1066         if (objp->flags & OF_NO_SHIELDS)
1067                 return;
1068
1069         Assert(objp->instance >= 0);
1070
1071         model_num = Ships[objp->instance].modelnum;
1072
1073         if ( Fred_running ) return;
1074
1075         pm = model_get(model_num);
1076
1077         if (pm->shield.ntris<1) return;
1078
1079         vm_copy_transpose_matrix(&m, &objp->orient);
1080
1081         //      Scan all the triangles in the mesh.
1082         for (i=0; i<pm->shield.ntris; i++ )     {
1083                 int             j;
1084                 vector  gnorm, v2f, tri_point;
1085                 vertex prev_pnt, pnt0;
1086                 shield_tri *tri;
1087
1088                 tri = &pm->shield.tris[i];
1089
1090                 if (i == Break_value)
1091                         Int3();
1092
1093                 //      Hack! Only works for object in identity orientation.
1094                 //      Need to rotate eye position into object's reference frame.
1095                 //      Only draw facing triangles.
1096                 vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix);
1097                 vm_vec_add2(&tri_point, &objp->pos);
1098
1099                 vm_vec_sub(&v2f, &tri_point, &Eye_position);
1100                 vm_vec_rotate(&gnorm, &tri->norm, &m);
1101
1102                 if (vm_vec_dot(&gnorm, &v2f) < 0.0f) {
1103                         int     intensity;
1104
1105                         intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255);
1106
1107                         if (intensity < 0)
1108                                 intensity = 0;
1109                         else if (intensity > 255)
1110                                 intensity = 255;
1111                         
1112                         gr_set_color(0, 0, intensity);
1113
1114                         //      Process the vertices.
1115                         //      Note this rotates each vertex each time it's needed, very dumb.
1116                         for (j=0; j<3; j++ )    {
1117                                 vertex tmp;
1118
1119                                 // Rotate point into world coordinates
1120                                 vm_vec_rotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &m);
1121                                 //vm_vec_rotate(&pnt,&pm->shield[i].pnt[j],&m);
1122                                 vm_vec_add2(&pnt, &objp->pos);
1123
1124                                 // Pnt is now the x,y,z world coordinates of this vert.
1125                                 // For this example, I am just drawing a sphere at that
1126                                 // point.
1127                                 g3_rotate_vertex(&tmp, &pnt);
1128
1129                                 if (j)
1130                                         g3_draw_line(&prev_pnt, &tmp);
1131                                 else
1132                                         pnt0 = tmp;
1133                                 prev_pnt = tmp;
1134                         }
1135
1136                         g3_draw_line(&pnt0, &prev_pnt);
1137                 }
1138         }
1139 }
1140 #endif
1141
1142 // Returns true if the shield presents any opposition to something 
1143 // trying to force through it.
1144 // If quadrant is -1, looks at entire shield, otherwise
1145 // just one quadrant
1146 int ship_is_shield_up( object *obj, int quadrant )
1147 {
1148         if ( (quadrant>=0) && (quadrant<=3))    {
1149                 // Just check one quadrant
1150                 if (obj->shields[quadrant] > max(2.0f, 0.1f * Ship_info[Ships[obj->instance].ship_info_index].shields/4.0f))    {
1151                         return 1;
1152                 }
1153         } else {
1154                 // Check all quadrants
1155                 float strength = get_shield_strength(obj);
1156
1157                 if ( strength > max(2.0f*4.0f, 0.1f * Ship_info[Ships[obj->instance].ship_info_index].shields ))        {
1158                         return 1;
1159                 }
1160         }
1161         return 0;       // no shield strength
1162 }
1163
1164
1165 /*
1166 //-- CODE TO "BOUNCE" AN ARRAY FROM A GIVEN POINT.
1167 //-- LIKE A MATTRESS.
1168 #define BOUNCE_SIZE ???
1169
1170 byte Bouncer1[BOUNCE_SIZE];
1171 byte Bouncer2[BOUNCE_SIZE];
1172
1173 byte * Bouncer = Bouncer1;
1174 byte * OldBouncer = Bouncer2;
1175
1176 // To wiggle, add value to Bouncer[] 
1177
1178 void bounce_it()
1179 {
1180         int i, tmp;
1181
1182
1183         for (i=0; i<BOUNCE_SIZE; i++ )  {
1184                 int t = 0;
1185
1186                 t += OldBouncer[ LEFT ];
1187                 t += OldBouncer[ RIGHT ];
1188                 t += OldBouncer[ UP ];
1189                 t += OldBouncer[ DOWN ];
1190
1191                 t = (t/2) - Bouncer[i];
1192                 tmp = t - t/16;         // 8
1193                 
1194                 if ( tmp < -127 ) tmp = -127;
1195                 if ( tmp > 127 ) tmp = 127;
1196                 Bouncer[i] = tmp;
1197         }
1198
1199         if ( Bouncer == Bouncer1 )      {
1200                 OldBouncer = Bouncer1;
1201                 Bouncer = Bouncer2;
1202         } else {
1203                 OldBouncer = Bouncer2;
1204                 Bouncer = Bouncer1;
1205         }
1206 }
1207 */
1208
1209 #else 
1210
1211 // stub out shield functions for the demo
1212 void shield_hit_init() {}
1213 void create_shield_explosion_all(object *objp) {}
1214 void shield_frame_init() {}
1215 void add_shield_point(int objnum, int tri_num, vector *hit_pos) {}
1216 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos) {}
1217 void shield_point_multi_setup() {}
1218 void shield_hit_close() {}
1219 void ship_draw_shield( object *objp) {}
1220 void shield_hit_page_in() {}
1221 void render_shields() {}
1222 float apply_damage_to_shield(object *objp, int shield_quadrant, float damage) {return damage;} 
1223 int ship_is_shield_up( object *obj, int quadrant ) {return 0;}
1224
1225 #endif // DEMO
1226
1227
1228 //      return quadrant containing hit_pnt.
1229 //      \  1  /.
1230 //      3 \ / 0
1231 //        / \.
1232 //      /  2  \.
1233 //      Note: This is in the object's local reference frame.  Do _not_ pass a vector in the world frame.
1234 int get_quadrant(vector *hit_pnt)
1235 {
1236         int     result = 0;
1237
1238         if (hit_pnt->x < hit_pnt->z)
1239                 result |= 1;
1240
1241         if (hit_pnt->x < -hit_pnt->z)
1242                 result |= 2;
1243
1244         return result;
1245 }
1246