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