added -udp documentation from d1x
[btb/d2x.git] / main / fuelcen.c
1 /* $Id: fuelcen.c,v 1.9 2004-05-15 17:16:34 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Functions for refueling centers.
18  *
19  * Old Log:
20  * Revision 1.2  1995/10/31  10:23:40  allender
21  * shareware stuff
22  *
23  * Revision 1.1  1995/05/16  15:24:50  allender
24  * Initial revision
25  *
26  * Revision 2.3  1995/03/21  14:38:40  john
27  * Ifdef'd out the NETWORK code.
28  *
29  * Revision 2.2  1995/03/06  15:23:09  john
30  * New screen techniques.
31  *
32  * Revision 2.1  1995/02/27  13:13:26  john
33  * Removed floating point.
34  *
35  * Revision 2.0  1995/02/27  11:27:20  john
36  * New version 2.0, which has no anonymous unions, builds with
37  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
38  *
39  * Revision 1.159  1995/02/22  13:48:10  allender
40  * remove anonymous unions in object structure
41  *
42  * Revision 1.158  1995/02/08  11:37:48  mike
43  * Check for failures in call to obj_create.
44  *
45  * Revision 1.157  1995/02/07  20:39:39  mike
46  * fix toasters in multiplayer
47  *
48  *
49  * Revision 1.156  1995/02/02  18:40:10  john
50  * Fixed bug with full screen cockpit flashing non-white.
51  *
52  * Revision 1.155  1995/01/28  15:27:22  yuan
53  * Make sure fuelcen nums are valid.
54  *
55  * Revision 1.154  1995/01/03  14:26:23  rob
56  * Better ifdef for robot centers.
57  *
58  * Revision 1.153  1995/01/03  11:27:49  rob
59  * Added include of fuelcen.c
60  *
61  * Revision 1.152  1995/01/03  09:47:22  john
62  * Some ifdef SHAREWARE lines.
63  *
64  * Revision 1.151  1995/01/02  21:02:07  rob
65  * added matcen support for coop/multirobot.
66  *
67  * Revision 1.150  1994/12/15  18:31:22  mike
68  * fix confusing precedence problems.
69  *
70  * Revision 1.149  1994/12/15  13:04:22  mike
71  * Replace Players[Player_num].time_total references with GameTime.
72  *
73  * Revision 1.148  1994/12/15  03:05:18  matt
74  * Added error checking for NULL return from object_create_explosion()
75  *
76  * Revision 1.147  1994/12/13  19:49:12  rob
77  * Made the fuelcen noise quieter.
78  *
79  * Revision 1.146  1994/12/13  12:03:18  john
80  * Made the warning sirens not start until after "desccruction
81  * secquence activated voice".
82  *
83  * Revision 1.145  1994/12/12  17:18:30  mike
84  * make warning siren louder.
85  *
86  * Revision 1.144  1994/12/11  23:18:04  john
87  * Added -nomusic.
88  * Added RealFrameTime.
89  * Put in a pause when sound initialization error.
90  * Made controlcen countdown and framerate use RealFrameTime.
91  *
92  * Revision 1.143  1994/12/11  14:10:16  mike
93  * louder sounds.
94  *
95  * Revision 1.142  1994/12/06  11:33:19  yuan
96  * Fixed bug with fueling when above 100.
97  *
98  * Revision 1.141  1994/12/05  23:37:14  matt
99  * Took out calls to warning() function
100  *
101  * Revision 1.140  1994/12/05  23:19:18  yuan
102  * Fixed fuel center refuelers..
103  *
104  * Revision 1.139  1994/12/03  12:48:12  mike
105  * diminish rocking due to control center destruction.
106  *
107  * Revision 1.138  1994/12/02  23:30:32  mike
108  * fix bumpiness after toasting control center.
109  *
110  * Revision 1.137  1994/12/02  22:48:14  mike
111  * rock the ship after toasting the control center!
112  *
113  * Revision 1.136  1994/12/02  17:12:11  rob
114  * Fixed countdown sounds.
115  *
116  * Revision 1.135  1994/11/29  20:59:43  rob
117  * Don't run out of fuel in net games (don't want to sync it between machines)
118  *
119  * Revision 1.134  1994/11/29  19:10:57  john
120  * Took out debugging mprintf.
121  *
122  * Revision 1.133  1994/11/29  13:19:40  john
123  * Made voice for "destruction actived in t-"
124  * be at 12.75 secs.
125  *
126  * Revision 1.132  1994/11/29  12:19:46  john
127  * MAde the "Mine desctruction will commence"
128  * voice play at 12.5 secs.
129  *
130  * Revision 1.131  1994/11/29  12:12:54  adam
131  * *** empty log message ***
132  *
133  * Revision 1.130  1994/11/28  21:04:26  rob
134  * Added code to cast noise when player refuels.
135  *
136  * Revision 1.129  1994/11/27  23:15:04  matt
137  * Made changes for new mprintf calling convention
138  *
139  * Revision 1.128  1994/11/21  16:27:51  mike
140  * debug code for morphing.
141  *
142  * Revision 1.127  1994/11/21  12:33:50  matt
143  * For control center explosions, use small fireball, not pseudo-random vclip
144  *
145  * Revision 1.126  1994/11/20  22:12:15  mike
146  * Fix bug in initializing materialization centers.
147  *
148  * Revision 1.125  1994/11/19  15:18:22  mike
149  * rip out unused code and data.
150  *
151  * Revision 1.124  1994/11/08  12:18:59  mike
152  * Initialize Fuelcen_seconds_left.
153  *
154  * Revision 1.123  1994/10/30  14:12:33  mike
155  * rip out repair center stuff
156  *
157  * Revision 1.122  1994/10/28  14:42:45  john
158  * Added sound volumes to all sound calls.
159  *
160  * Revision 1.121  1994/10/16  12:44:02  mike
161  * Make time to exit mine after control center destruction diff level dependent.
162  *
163  * Revision 1.120  1994/10/09  22:03:26  mike
164  * Adapt to new create_n_segment_path parameters.
165  *
166  * Revision 1.119  1994/10/06  14:52:42  mike
167  * Remove last of ability to damage fuel centers.
168  *
169  * Revision 1.118  1994/10/06  14:08:45  matt
170  * Made morph flash effect get orientation from segment
171  *
172  * Revision 1.117  1994/10/05  16:09:03  mike
173  * Put debugging code into matcen/fuelcen synchronization problem.
174  *
175  * Revision 1.116  1994/10/04  15:32:41  john
176  * Took out the old PLAY_SOUND??? code and replaced it
177  * with direct calls into digi_link_??? so that all sounds
178  * can be made 3d.
179  *
180  * Revision 1.115  1994/10/03  23:37:57  mike
181  * Clean up this mess of confusion to the point where maybe matcens actually work.
182  *
183  * Revision 1.114  1994/10/03  13:34:40  matt
184  * Added new (and hopefully better) game sequencing functions
185  *
186  * Revision 1.113  1994/09/30  14:41:57  matt
187  * Fixed bug as per Mike's instructions
188  *
189  * Revision 1.112  1994/09/30  00:37:33  mike
190  * Balance materialization centers.
191  *
192  * Revision 1.111  1994/09/28  23:12:52  matt
193  * Macroized palette flash system
194  *
195  * Revision 1.110  1994/09/27  15:42:31  mike
196  * Add names of Specials.
197  *
198  * Revision 1.109  1994/09/27  00:02:23  mike
199  * Yet more materialization center stuff.
200  *
201  * Revision 1.108  1994/09/26  11:26:23  mike
202  * Balance materialization centers.
203  *
204  * Revision 1.107  1994/09/25  23:40:47  matt
205  * Changed the object load & save code to read/write the structure fields one
206  * at a time (rather than the whole structure at once).  This mean that the
207  * object structure can be changed without breaking the load/save functions.
208  * As a result of this change, the local_object data can be and has been
209  * incorporated into the object array.  Also, timeleft is now a property
210  * of all objects, and the object structure has been otherwise cleaned up.
211  *
212  * Revision 1.106  1994/09/25  15:55:58  mike
213  * Balance materialization centers, make them emit light, make them re-triggerable after awhile.
214  *
215  * Revision 1.105  1994/09/24  17:42:33  mike
216  * Making materialization centers be activated by triggers and balancing them.
217  *
218  * Revision 1.104  1994/09/24  14:16:06  mike
219  * Support new network constants.
220  *
221  * Revision 1.103  1994/09/20  19:14:40  john
222  * Massaged the sound system; used a better formula for determining
223  * which l/r balance, also, put in Mike's stuff that searches for a connection
224  * between the 2 sounds' segments, stopping for closed doors, etc.
225  *
226  * Revision 1.102  1994/09/17  01:40:51  matt
227  * Added status bar/sizable window mode, and in the process revamped the
228  * whole cockpit mode system.
229  *
230  * Revision 1.101  1994/08/31  20:57:25  matt
231  * Cleaned up endlevel/death code
232  *
233  * Revision 1.100  1994/08/30  17:54:20  mike
234  * Slow down rate of creation of objects by materialization centers.
235  *
236  * Revision 1.99  1994/08/29  11:47:01  john
237  * Added warning if no control centers in mine.
238  *
239  */
240
241 #ifdef HAVE_CONFIG_H
242 #include <conf.h>
243 #endif
244
245 #ifdef RCS
246 static char rcsid[] = "$Id: fuelcen.c,v 1.9 2004-05-15 17:16:34 schaffner Exp $";
247 #endif
248
249 #include <stdio.h>
250 #include <stdlib.h>
251 #include <math.h>
252 #include <string.h>
253
254 #include "fuelcen.h"
255 #include "gameseg.h"
256 #include "game.h"               // For FrameTime
257 #include "error.h"
258 #include "mono.h"
259 #include "gauges.h"
260 #include "vclip.h"
261 #include "fireball.h"
262 #include "robot.h"
263 #include "powerup.h"
264
265 #include "wall.h"
266 #include "sounds.h"
267 #include "morph.h"
268 #include "3d.h"
269 #include "bm.h"
270 #include "polyobj.h"
271 #include "ai.h"
272 #include "gamemine.h"
273 #include "gamesave.h"
274 #include "player.h"
275 #include "collide.h"
276 #include "laser.h"
277 #ifdef NETWORK
278 #include "network.h"
279 #include "multi.h"
280 #endif
281 #include "multibot.h"
282 #include "escort.h"
283
284 // The max number of fuel stations per mine.
285
286 fix Fuelcen_refill_speed = i2f(1);
287 fix Fuelcen_give_amount = i2f(25);
288 fix Fuelcen_max_amount = i2f(100);
289
290 // Every time a robot is created in the morphing code, it decreases capacity of the morpher
291 // by this amount... when capacity gets to 0, no more morphers...
292 fix EnergyToCreateOneRobot = i2f(1);
293
294 #define MATCEN_HP_DEFAULT                       F1_0*500; // Hitpoints
295 #define MATCEN_INTERVAL_DEFAULT F1_0*5; //  5 seconds
296
297 matcen_info RobotCenters[MAX_ROBOT_CENTERS];
298 int Num_robot_centers;
299
300 FuelCenter Station[MAX_NUM_FUELCENS];
301 int Num_fuelcenters = 0;
302
303 segment * PlayerSegment= NULL;
304
305 #ifdef EDITOR
306 char    Special_names[MAX_CENTER_TYPES][11] = {
307         "NOTHING   ",
308         "FUELCEN   ",
309         "REPAIRCEN ",
310         "CONTROLCEN",
311         "ROBOTMAKER",
312         "GOAL_RED",
313         "GOAL_BLUE",
314 };
315 #endif
316
317 //------------------------------------------------------------
318 // Resets all fuel center info
319 void fuelcen_reset()
320 {
321         int i;
322
323         Num_fuelcenters = 0;
324         //mprintf( (0, "All fuel centers reset.\n"));
325
326         for(i=0; i<MAX_SEGMENTS; i++ )
327                 Segment2s[i].special = SEGMENT_IS_NOTHING;
328
329         Num_robot_centers = 0;
330
331 }
332
333 #ifndef NDEBUG          //this is sometimes called by people from the debugger
334 void reset_all_robot_centers()
335 {
336         int i;
337
338         // Remove all materialization centers
339         for (i=0; i<Num_segments; i++)
340                 if (Segment2s[i].special == SEGMENT_IS_ROBOTMAKER) {
341                         Segment2s[i].special = SEGMENT_IS_NOTHING;
342                         Segment2s[i].matcen_num = -1;
343                 }
344 }
345 #endif
346
347 //------------------------------------------------------------
348 // Turns a segment into a fully charged up fuel center...
349 void fuelcen_create( segment *segp)
350 {
351         segment2        *seg2p = &Segment2s[segp-Segments];
352
353         int     station_type;
354
355         station_type = seg2p->special;
356
357         switch( station_type )  {
358         case SEGMENT_IS_NOTHING:
359         case SEGMENT_IS_GOAL_BLUE:
360         case SEGMENT_IS_GOAL_RED:
361                 return;
362         case SEGMENT_IS_FUELCEN:
363         case SEGMENT_IS_REPAIRCEN:
364         case SEGMENT_IS_CONTROLCEN:
365         case SEGMENT_IS_ROBOTMAKER:
366                 break;
367         default:
368                 Error( "Invalid station type %d in fuelcen.c\n", station_type );
369         }
370
371         Assert( (seg2p != NULL) );
372         if ( seg2p == NULL ) return;
373
374         Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
375         Assert( Num_fuelcenters > -1 );
376
377         seg2p->value = Num_fuelcenters;
378         Station[Num_fuelcenters].Type = station_type;
379         Station[Num_fuelcenters].MaxCapacity = Fuelcen_max_amount;
380         Station[Num_fuelcenters].Capacity = Station[Num_fuelcenters].MaxCapacity;
381         Station[Num_fuelcenters].segnum = seg2p-Segment2s;
382         Station[Num_fuelcenters].Timer = -1;
383         Station[Num_fuelcenters].Flag = 0;
384 //      Station[Num_fuelcenters].NextRobotType = -1;
385 //      Station[Num_fuelcenters].last_created_obj=NULL;
386 //      Station[Num_fuelcenters].last_created_sig = -1;
387         compute_segment_center(&Station[Num_fuelcenters].Center, segp);
388
389 //      if (station_type == SEGMENT_IS_ROBOTMAKER)
390 //              Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
391
392         //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
393         Num_fuelcenters++;
394 }
395
396 //------------------------------------------------------------
397 // Adds a matcen that already is a special type into the Station array.
398 // This function is separate from other fuelcens because we don't want values reset.
399 void matcen_create( segment *segp)
400 {
401         segment2        *seg2p = &Segment2s[segp-Segments];
402
403         int     station_type = seg2p->special;
404
405         Assert( (seg2p != NULL) );
406         Assert(station_type == SEGMENT_IS_ROBOTMAKER);
407         if ( seg2p == NULL ) return;
408
409         Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
410         Assert( Num_fuelcenters > -1 );
411
412         seg2p->value = Num_fuelcenters;
413         Station[Num_fuelcenters].Type = station_type;
414         Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
415         Station[Num_fuelcenters].MaxCapacity = Station[Num_fuelcenters].Capacity;
416
417         Station[Num_fuelcenters].segnum = seg2p-Segment2s;
418         Station[Num_fuelcenters].Timer = -1;
419         Station[Num_fuelcenters].Flag = 0;
420 //      Station[Num_fuelcenters].NextRobotType = -1;
421 //      Station[Num_fuelcenters].last_created_obj=NULL;
422 //      Station[Num_fuelcenters].last_created_sig = -1;
423         compute_segment_center(&Station[Num_fuelcenters].Center, &Segments[seg2p-Segment2s] );
424
425         seg2p->matcen_num = Num_robot_centers;
426         Num_robot_centers++;
427
428         RobotCenters[seg2p->matcen_num].hit_points = MATCEN_HP_DEFAULT;
429         RobotCenters[seg2p->matcen_num].interval = MATCEN_INTERVAL_DEFAULT;
430         RobotCenters[seg2p->matcen_num].segnum = seg2p-Segment2s;
431         RobotCenters[seg2p->matcen_num].fuelcen_num = Num_fuelcenters;
432
433         //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
434         Num_fuelcenters++;
435 }
436
437 //------------------------------------------------------------
438 // Adds a segment that already is a special type into the Station array.
439 void fuelcen_activate( segment * segp, int station_type )
440 {
441         segment2        *seg2p = &Segment2s[segp-Segments];
442
443         seg2p->special = station_type;
444
445         if (seg2p->special == SEGMENT_IS_ROBOTMAKER)
446                 matcen_create( segp);
447         else
448                 fuelcen_create( segp);
449         
450 }
451
452 //      The lower this number is, the more quickly the center can be re-triggered.
453 //      If it's too low, it can mean all the robots won't be put out, but for about 5
454 //      robots, that's not real likely.
455 #define MATCEN_LIFE (i2f(30-2*Difficulty_level))
456
457 //------------------------------------------------------------
458 //      Trigger (enable) the materialization center in segment segnum
459 void trigger_matcen(int segnum)
460 {
461         // -- segment           *segp = &Segments[segnum];
462         segment2                *seg2p = &Segment2s[segnum];
463         vms_vector      pos, delta;
464         FuelCenter      *robotcen;
465         int                     objnum;
466
467         mprintf((0, "Trigger matcen, segment %i\n", segnum));
468
469         Assert(seg2p->special == SEGMENT_IS_ROBOTMAKER);
470         Assert(seg2p->matcen_num < Num_fuelcenters);
471         Assert((seg2p->matcen_num >= 0) && (seg2p->matcen_num <= Highest_segment_index));
472
473         robotcen = &Station[RobotCenters[seg2p->matcen_num].fuelcen_num];
474
475         if (robotcen->Enabled == 1)
476                 return;
477
478         if (!robotcen->Lives)
479                 return;
480
481         //      MK: 11/18/95, At insane, matcens work forever!
482         if (Difficulty_level+1 < NDL)
483                 robotcen->Lives--;
484
485         robotcen->Timer = F1_0*1000;    //      Make sure the first robot gets emitted right away.
486         robotcen->Enabled = 1;                  //      Say this center is enabled, it can create robots.
487         robotcen->Capacity = i2f(Difficulty_level + 3);
488         robotcen->Disable_time = MATCEN_LIFE;
489
490         //      Create a bright object in the segment.
491         pos = robotcen->Center;
492         vm_vec_sub(&delta, &Vertices[Segments[segnum].verts[0]], &robotcen->Center);
493         vm_vec_scale_add2(&pos, &delta, F1_0/2);
494         objnum = obj_create( OBJ_LIGHT, 0, segnum, &pos, NULL, 0, CT_LIGHT, MT_NONE, RT_NONE );
495         if (objnum != -1) {
496                 Objects[objnum].lifeleft = MATCEN_LIFE;
497                 Objects[objnum].ctype.light_info.intensity = i2f(8);    //      Light cast by a fuelcen.
498         } else {
499                 mprintf((1, "Can't create invisible flare for matcen.\n"));
500                 Int3();
501         }
502 //      mprintf((0, "Created invisibile flare, object=%i, segment=%i, pos=%7.3f %7.3f%7.3f\n", objnum, segnum, f2fl(pos.x), f2fl(pos.y), f2fl(pos.z)));
503 }
504
505 #ifdef EDITOR
506 //------------------------------------------------------------
507 // Takes away a segment's fuel center properties.
508 //      Deletes the segment point entry in the FuelCenter list.
509 void fuelcen_delete( segment * segp )
510 {
511         segment2        *seg2p = &Segment2s[segp-Segments];
512         int i, j;
513
514 Restart: ;
515
516         seg2p->special = 0;
517
518         for (i=0; i<Num_fuelcenters; i++ )      {
519                 if ( Station[i].segnum == segp-Segments )       {
520
521                         // If Robot maker is deleted, fix Segments and RobotCenters.
522                         if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
523                                 Num_robot_centers--;
524                                 Assert(Num_robot_centers >= 0);
525
526                                 for (j=seg2p->matcen_num; j<Num_robot_centers; j++)
527                                         RobotCenters[j] = RobotCenters[j+1];
528
529                                 for (j=0; j<Num_fuelcenters; j++) {
530                                         if ( Station[j].Type == SEGMENT_IS_ROBOTMAKER )
531                                                 if ( Segment2s[Station[j].segnum].matcen_num > seg2p->matcen_num )
532                                                         Segment2s[Station[j].segnum].matcen_num--;
533                                 }
534                         }
535
536                         //fix RobotCenters so they point to correct fuelcenter
537                         for (j=0; j<Num_robot_centers; j++ )
538                                 if (RobotCenters[j].fuelcen_num > i)            //this robotcenter's fuelcen is changing
539                                         RobotCenters[j].fuelcen_num--;
540
541                         Num_fuelcenters--;
542                         Assert(Num_fuelcenters >= 0);
543                         for (j=i; j<Num_fuelcenters; j++ )      {
544                                 Station[j] = Station[j+1];
545                                 Segment2s[Station[j].segnum].value = j;
546                         }
547                         goto Restart;
548                 }
549         }
550
551 }
552 #endif
553
554 #define ROBOT_GEN_TIME (i2f(5))
555
556 object * create_morph_robot( segment *segp, vms_vector *object_pos, int object_id)
557 {
558         short           objnum;
559         object  *obj;
560         int             default_behavior;
561
562         Players[Player_num].num_robots_level++;
563         Players[Player_num].num_robots_total++;
564
565         objnum = obj_create(OBJ_ROBOT, object_id, segp-Segments, object_pos,
566                                 &vmd_identity_matrix, Polygon_models[Robot_info[object_id].model_num].rad,
567                                 CT_AI, MT_PHYSICS, RT_POLYOBJ);
568
569         if ( objnum < 0 ) {
570                 mprintf((1, "Can't create morph robot.  Aborting morph.\n"));
571                 Int3();
572                 return NULL;
573         }
574
575         obj = &Objects[objnum];
576
577         //Set polygon-object-specific data
578
579         obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
580         obj->rtype.pobj_info.subobj_flags = 0;
581
582         //set Physics info
583
584         obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
585         obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
586
587         obj->mtype.phys_info.flags |= (PF_LEVELLING);
588
589         obj->shields = Robot_info[obj->id].strength;
590         
591         default_behavior = Robot_info[obj->id].behavior;
592
593         init_ai_object(obj-Objects, default_behavior, -1 );             //      Note, -1 = segment this robot goes to to hide, should probably be something useful
594
595         create_n_segment_path(obj, 6, -1);              //      Create a 6 segment path from creation point.
596
597         Ai_local_info[objnum].mode = ai_behavior_to_mode(default_behavior);
598
599         return obj;
600 }
601
602 int Num_extry_robots = 15;
603
604 #ifndef NDEBUG
605 int     FrameCount_last_msg = 0;
606 #endif
607
608 //      ----------------------------------------------------------------------------------------------------------
609 void robotmaker_proc( FuelCenter * robotcen )
610 {
611         fix             dist_to_player;
612         vms_vector      cur_object_loc; //, direction;
613         int             matcen_num, segnum, objnum;
614         object  *obj;
615         fix             top_time;
616         vms_vector      direction;
617
618         if (robotcen->Enabled == 0)
619                 return;
620
621         if (robotcen->Disable_time > 0) {
622                 robotcen->Disable_time -= FrameTime;
623                 if (robotcen->Disable_time <= 0) {
624                         mprintf((0, "Robot center #%i gets disabled due to time running out.\n", robotcen-Station));
625                         robotcen->Enabled = 0;
626                 }
627         }
628
629         // mprintf((0, "Capacity of robot maker #%i is %i\n", robotcen - Station, robotcen->Capacity));
630
631         //      No robot making in multiplayer mode.
632 #ifdef NETWORK
633 #ifndef SHAREWARE
634         if ((Game_mode & GM_MULTI) && (!(Game_mode & GM_MULTI_ROBOTS) || !network_i_am_master()))
635                 return;
636 #else
637         if (Game_mode & GM_MULTI)
638                 return;
639 #endif
640 #endif
641
642         // Wait until transmorgafier has capacity to make a robot...
643         if ( robotcen->Capacity <= 0 ) {
644                 return;
645         }
646
647         matcen_num = Segment2s[robotcen->segnum].matcen_num;
648         //mprintf((0, "Robotmaker #%i flags = %8x\n", matcen_num, RobotCenters[matcen_num].robot_flags));
649
650         if ( matcen_num == -1 ) {
651                 mprintf((0, "Non-functional robotcen at %d\n", robotcen->segnum));
652                 return;
653         }
654
655         if (RobotCenters[matcen_num].robot_flags[0]==0 && RobotCenters[matcen_num].robot_flags[1]==0) {
656                 //mprintf((0, "robot_flags = 0 at robot maker #%i\n", RobotCenters[matcen_num].robot_flags));
657                 return;
658         }
659
660         // Wait until we have a free slot for this puppy...
661    //     <<<<<<<<<<<<<<<< Num robots in mine >>>>>>>>>>>>>>>>>>>>>>>>>>    <<<<<<<<<<<< Max robots in mine >>>>>>>>>>>>>>>
662         if ( (Players[Player_num].num_robots_level - Players[Player_num].num_kills_level) >= (Gamesave_num_org_robots + Num_extry_robots ) ) {
663                 #ifndef NDEBUG
664                 if (FrameCount > FrameCount_last_msg + 20) {
665                         mprintf((0, "Cannot morph until you kill one!\n"));
666                         FrameCount_last_msg = FrameCount;
667                 }
668                 #endif
669                 return;
670         }
671
672         robotcen->Timer += FrameTime;
673
674         switch( robotcen->Flag )        {
675         case 0:         // Wait until next robot can generate
676                 if (Game_mode & GM_MULTI)
677                 {
678                         top_time = ROBOT_GEN_TIME;      
679                 }
680                 else
681                 {
682                         dist_to_player = vm_vec_dist_quick( &ConsoleObject->pos, &robotcen->Center );
683                         top_time = dist_to_player/64 + d_rand() * 2 + F1_0*2;
684                         if ( top_time > ROBOT_GEN_TIME )
685                                 top_time = ROBOT_GEN_TIME + d_rand();
686                         if ( top_time < F1_0*2 )
687                                 top_time = F1_0*3/2 + d_rand()*2;
688                 }
689
690                 // mprintf( (0, "Time between morphs %d seconds, dist_to_player = %7.3f\n", f2i(top_time), f2fl(dist_to_player) ));
691
692                 if (robotcen->Timer > top_time )        {
693                         int     count=0;
694                         int     i, my_station_num = robotcen-Station;
695                         object *obj;
696
697                         //      Make sure this robotmaker hasn't put out its max without having any of them killed.
698                         for (i=0; i<=Highest_object_index; i++)
699                                 if (Objects[i].type == OBJ_ROBOT)
700                                         if ((Objects[i].matcen_creator^0x80) == my_station_num)
701                                                 count++;
702                         if (count > Difficulty_level + 3) {
703                                 mprintf((0, "Cannot morph: center %i has already put out %i robots.\n", my_station_num, count));
704                                 robotcen->Timer /= 2;
705                                 return;
706                         }
707
708                         //      Whack on any robot or player in the matcen segment.
709                         count=0;
710                         segnum = robotcen->segnum;
711                         for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next)    {
712                                 count++;
713                                 if ( count > MAX_OBJECTS )      {
714                                         mprintf((0, "Object list in segment %d is circular.", segnum ));
715                                         Int3();
716                                         return;
717                                 }
718                                 if (Objects[objnum].type==OBJ_ROBOT) {
719                                         collide_robot_and_materialization_center(&Objects[objnum]);
720                                         robotcen->Timer = top_time/2;
721                                         return;
722                                 } else if (Objects[objnum].type==OBJ_PLAYER ) {
723                                         collide_player_and_materialization_center(&Objects[objnum]);
724                                         robotcen->Timer = top_time/2;
725                                         return;
726                                 }
727                         }
728
729                         compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
730                         // HACK!!! The 10 under here should be something equal to the 1/2 the size of the segment.
731                         obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT );
732
733                         if (obj)
734                                 extract_orient_from_segment(&obj->orient,&Segments[robotcen->segnum]);
735
736                         if ( Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1 )               {
737                                 digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 );
738                         }
739                         robotcen->Flag  = 1;
740                         robotcen->Timer = 0;
741
742                 }
743                 break;
744         case 1:                 // Wait until 1/2 second after VCLIP started.
745                 if (robotcen->Timer > (Vclip[VCLIP_MORPHING_ROBOT].play_time/2) )       {
746
747                         robotcen->Capacity -= EnergyToCreateOneRobot;
748                         robotcen->Flag = 0;
749
750                         robotcen->Timer = 0;
751                         compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
752
753                         // If this is the first materialization, set to valid robot.
754                         if (RobotCenters[matcen_num].robot_flags[0] != 0 || RobotCenters[matcen_num].robot_flags[1] != 0) {
755                                 int     type;
756                                 uint    flags;
757                                 sbyte   legal_types[64];   // 64 bits, the width of robot_flags[].
758                                 int     num_types, robot_index, i;
759
760                                 num_types = 0;
761                                 for (i=0;i<2;i++) {
762                                         robot_index = i*32;
763                                         flags = RobotCenters[matcen_num].robot_flags[i];
764                                         while (flags) {
765                                                 if (flags & 1)
766                                                         legal_types[num_types++] = robot_index;
767                                                 flags >>= 1;
768                                                 robot_index++;
769                                         }
770                                 }
771
772                                 //mprintf((0, "Flags = %08x, %2i legal types to morph: \n", RobotCenters[matcen_num].robot_flags, num_types));
773                                 //for (i=0; i<num_types; i++)
774                                 //      mprintf((0, "%2i ", legal_types[i]));
775                                 //mprintf((0, "\n"));
776
777                                 if (num_types == 1)
778                                         type = legal_types[0];
779                                 else
780                                         type = legal_types[(d_rand() * num_types) / 32768];
781
782                                 mprintf((0, "Morph: (type = %i) (seg = %i) (capacity = %08x)\n", type, robotcen->segnum, robotcen->Capacity));
783                                 obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type );
784                                 if (obj != NULL) {
785 #ifndef SHAREWARE
786 #ifdef NETWORK
787                                         if (Game_mode & GM_MULTI)
788                                                 multi_send_create_robot(robotcen-Station, obj-Objects, type);
789 #endif
790 #endif
791                                         obj->matcen_creator = (robotcen-Station) | 0x80;
792
793                                         // Make object faces player...
794                                         vm_vec_sub( &direction, &ConsoleObject->pos,&obj->pos );
795                                         vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL);
796         
797                                         morph_start( obj );
798                                         //robotcen->last_created_obj = obj;
799                                         //robotcen->last_created_sig = robotcen->last_created_obj->signature;
800                                 } else
801                                         mprintf((0, "Warning: create_morph_robot returned NULL (no objects left?)\n"));
802
803                         }
804  
805                 }
806                 break;
807         default:
808                 robotcen->Flag = 0;
809                 robotcen->Timer = 0;
810         }
811 }
812
813
814 //-------------------------------------------------------------
815 // Called once per frame, replenishes fuel supply.
816 void fuelcen_update_all()
817 {
818         int i;
819         fix AmountToreplenish;
820         
821         AmountToreplenish = fixmul(FrameTime,Fuelcen_refill_speed);
822
823         for (i=0; i<Num_fuelcenters; i++ )      {
824                 if ( Station[i].Type == SEGMENT_IS_ROBOTMAKER ) {
825                         if (! (Game_suspended & SUSP_ROBOTS))
826                                 robotmaker_proc( &Station[i] );
827                 } else if ( Station[i].Type == SEGMENT_IS_CONTROLCEN )  {
828                         //controlcen_proc( &Station[i] );
829         
830                 } else if ( (Station[i].MaxCapacity > 0) && (PlayerSegment!=&Segments[Station[i].segnum]) )     {
831                         if ( Station[i].Capacity < Station[i].MaxCapacity )     {
832                                 Station[i].Capacity += AmountToreplenish;
833                                 //mprintf( (0, "Fuel center %d replenished to %d.\n", i, f2i(Station[i].Capacity) ));
834                                 if ( Station[i].Capacity >= Station[i].MaxCapacity )            {
835                                         Station[i].Capacity = Station[i].MaxCapacity;
836                                         //gauge_message( "Fuel center is fully recharged!    " );
837                                 }
838                         }
839                 }
840         }
841 }
842
843 //--unused-- //-------------------------------------------------------------
844 //--unused-- // replenishes all fuel supplies.
845 //--unused-- void fuelcen_replenish_all()
846 //--unused-- {
847 //--unused--    int i;
848 //--unused--
849 //--unused--    for (i=0; i<Num_fuelcenters; i++ )      {
850 //--unused--            Station[i].Capacity = Station[i].MaxCapacity;
851 //--unused--    }
852 //--unused--    //mprintf( (0, "All fuel centers are replenished\n" ));
853 //--unused--
854 //--unused-- }
855
856 #define FUELCEN_SOUND_DELAY (f1_0/4)            //play every half second
857
858 //-------------------------------------------------------------
859 fix fuelcen_give_fuel(segment *segp, fix MaxAmountCanTake )
860 {
861         segment2        *seg2p = &Segment2s[segp-Segments];
862
863         static fix last_play_time=0;
864
865         Assert( segp != NULL );
866
867         PlayerSegment = segp;
868
869         if ( (segp) && (seg2p->special==SEGMENT_IS_FUELCEN) )   {
870                 fix amount;
871
872                 detect_escort_goal_accomplished(-4);    //      UGLY! Hack! -4 means went through fuelcen.
873
874 //              if (Station[segp->value].MaxCapacity<=0)        {
875 //                      HUD_init_message( "Fuelcenter %d is destroyed.", segp->value );
876 //                      return 0;
877 //              }
878
879 //              if (Station[segp->value].Capacity<=0)   {
880 //                      HUD_init_message( "Fuelcenter %d is empty.", segp->value );
881 //                      return 0;
882 //              }
883
884                 if (MaxAmountCanTake <= 0 )     {
885 //                      //gauge_message( "Fueled up!");
886                         return 0;
887                 }
888
889                 amount = fixmul(FrameTime,Fuelcen_give_amount);
890
891                 if (amount > MaxAmountCanTake )
892                         amount = MaxAmountCanTake;
893
894 //              if (!(Game_mode & GM_MULTI))
895 //                      if ( Station[segp->value].Capacity < amount  )  {
896 //                              amount = Station[segp->value].Capacity;
897 //                              Station[segp->value].Capacity = 0;
898 //                      } else {
899 //                              Station[segp->value].Capacity -= amount;
900 //                      }
901
902                 if (last_play_time > GameTime)
903                         last_play_time = 0;
904
905                 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
906
907                         digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
908 #ifdef NETWORK
909                         if (Game_mode & GM_MULTI)
910                                 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
911 #endif
912
913                         last_play_time = GameTime;
914                 }
915
916
917                 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
918                 return amount;
919
920         } else {
921                 return 0;
922         }
923 }
924
925 //-------------------------------------------------------------
926 // DM/050904
927 // Repair centers
928 // use same values as fuel centers
929 fix repaircen_give_shields(segment *segp, fix MaxAmountCanTake )
930 {
931         segment2        *seg2p = &Segment2s[segp-Segments];
932         static fix last_play_time=0;
933
934         Assert( segp != NULL );
935         PlayerSegment = segp;
936         if ( (segp) && (seg2p->special==SEGMENT_IS_REPAIRCEN) ) {
937                 fix amount;
938 //             detect_escort_goal_accomplished(-4);    //      UGLY! Hack! -4 means went through fuelcen.
939 //             if (Station[segp->value].MaxCapacity<=0)        {
940 //                     HUD_init_message( "Repaircenter %d is destroyed.", segp->value );
941 //                     return 0;
942 //             }
943 //             if (Station[segp->value].Capacity<=0)   {
944 //                     HUD_init_message( "Repaircenter %d is empty.", segp->value );
945 //                     return 0;
946 //             }
947                 if (MaxAmountCanTake <= 0 ) {
948                         //gauge_message( "Shields restored!");
949                         return 0;
950                 }
951                 amount = fixmul(FrameTime,Fuelcen_give_amount);
952                 if (amount > MaxAmountCanTake )
953                         amount = MaxAmountCanTake;
954 //        if (!(Game_mode & GM_MULTI))
955 //                     if ( Station[segp->value].Capacity < amount  )  {
956 //                             amount = Station[segp->value].Capacity;
957 //                             Station[segp->value].Capacity = 0;
958 //                     } else {
959 //                             Station[segp->value].Capacity -= amount;
960 //                     }
961                 if (last_play_time > GameTime)
962                         last_play_time = 0;
963                 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
964                         digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
965 #ifdef NETWORK
966                         if (Game_mode & GM_MULTI)
967                                 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
968 #endif
969                         last_play_time = GameTime;
970                 }
971 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
972                 return amount;
973         } else {
974                 return 0;
975         }
976 }
977
978 //--unused-- //-----------------------------------------------------------
979 //--unused-- // Damages a fuel center
980 //--unused-- void fuelcen_damage(segment *segp, fix damage )
981 //--unused-- {
982 //--unused--    //int i;
983 //--unused--    // int  station_num = segp->value;
984 //--unused--
985 //--unused--    Assert( segp != NULL );
986 //--unused--    if ( segp == NULL ) return;
987 //--unused--
988 //--unused--    mprintf((0, "Obsolete function fuelcen_damage() called with seg=%i, damage=%7.3f\n", segp-Segments, f2fl(damage)));
989 //--unused--    switch( segp->special ) {
990 //--unused--    case SEGMENT_IS_NOTHING:
991 //--unused--            return;
992 //--unused--    case SEGMENT_IS_ROBOTMAKER:
993 //--unused-- //--               // Robotmaker hit by laser
994 //--unused-- //--               if (Station[station_num].MaxCapacity<=0 )       {
995 //--unused-- //--                       // Shooting a already destroyed materializer
996 //--unused-- //--               } else {
997 //--unused-- //--                       Station[station_num].MaxCapacity -= damage;
998 //--unused-- //--                       if (Station[station_num].Capacity > Station[station_num].MaxCapacity )  {
999 //--unused-- //--                               Station[station_num].Capacity = Station[station_num].MaxCapacity;
1000 //--unused-- //--                       }
1001 //--unused-- //--                       if (Station[station_num].MaxCapacity <= 0 )     {
1002 //--unused-- //--                               Station[station_num].MaxCapacity = 0;
1003 //--unused-- //--                               // Robotmaker dead
1004 //--unused-- //--                               for (i=0; i<6; i++ )
1005 //--unused-- //--                                       segp->sides[i].tmap_num2 = 0;
1006 //--unused-- //--                       }
1007 //--unused-- //--               }
1008 //--unused-- //--               //mprintf( (0, "Materializatormografier has %x capacity left\n", Station[station_num].MaxCapacity ));
1009 //--unused--            break;
1010 //--unused--    case SEGMENT_IS_FUELCEN:        
1011 //--unused-- //--               digi_play_sample( SOUND_REFUEL_STATION_HIT );
1012 //--unused-- //--               if (Station[station_num].MaxCapacity>0 )        {
1013 //--unused-- //--                       Station[station_num].MaxCapacity -= damage;
1014 //--unused-- //--                       if (Station[station_num].Capacity > Station[station_num].MaxCapacity )  {
1015 //--unused-- //--                               Station[station_num].Capacity = Station[station_num].MaxCapacity;
1016 //--unused-- //--                       }
1017 //--unused-- //--                       if (Station[station_num].MaxCapacity <= 0 )     {
1018 //--unused-- //--                               Station[station_num].MaxCapacity = 0;
1019 //--unused-- //--                               digi_play_sample( SOUND_REFUEL_STATION_DESTROYED );
1020 //--unused-- //--                       }
1021 //--unused-- //--               } else {
1022 //--unused-- //--                       Station[station_num].MaxCapacity = 0;
1023 //--unused-- //--               }
1024 //--unused-- //--               HUD_init_message( "Fuelcenter %d damaged", station_num );
1025 //--unused--            break;
1026 //--unused--    case SEGMENT_IS_REPAIRCEN:
1027 //--unused--            break;
1028 //--unused--    case SEGMENT_IS_CONTROLCEN:
1029 //--unused--            break;
1030 //--unused--    default:
1031 //--unused--            Error( "Invalid type in fuelcen.c" );
1032 //--unused--    }
1033 //--unused-- }
1034
1035 //--unused-- // ----------------------------------------------------------------------------------------------------------
1036 //--unused-- fixang my_delta_ang(fixang a,fixang b)
1037 //--unused-- {
1038 //--unused--    fixang delta0,delta1;
1039 //--unused--
1040 //--unused--    return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1;
1041 //--unused--
1042 //--unused-- }
1043
1044 //--unused-- // ----------------------------------------------------------------------------------------------------------
1045 //--unused-- //return though which side of seg0 is seg1
1046 //--unused-- int john_find_connect_side(int seg0,int seg1)
1047 //--unused-- {
1048 //--unused--    segment *Seg=&Segments[seg0];
1049 //--unused--    int i;
1050 //--unused--
1051 //--unused--    for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i;
1052 //--unused--
1053 //--unused--    return -1;
1054 //--unused-- }
1055
1056 //      ----------------------------------------------------------------------------------------------------------
1057 //--unused-- vms_angvec start_angles, delta_angles, goal_angles;
1058 //--unused-- vms_vector start_pos, delta_pos, goal_pos;
1059 //--unused-- int FuelStationSeg;
1060 //--unused-- fix current_time,delta_time;
1061 //--unused-- int next_side, side_index;
1062 //--unused-- int * sidelist;
1063
1064 //--repair-- int Repairing;
1065 //--repair-- vms_vector repair_save_uvec;               //the player's upvec when enter repaircen
1066 //--repair-- object *RepairObj=NULL;            //which object getting repaired
1067 //--repair-- int disable_repair_center=0;
1068 //--repair-- fix repair_rate;
1069 //--repair-- #define FULL_REPAIR_RATE i2f(10)
1070
1071 //--unused-- ubyte save_control_type,save_movement_type;
1072
1073 //--unused-- int SideOrderBack[] = {WFRONT, WRIGHT, WTOP, WLEFT, WBOTTOM, WBACK};
1074 //--unused-- int SideOrderFront[] =  {WBACK, WLEFT, WTOP, WRIGHT, WBOTTOM, WFRONT};
1075 //--unused-- int SideOrderLeft[] =  { WRIGHT, WBACK, WTOP, WFRONT, WBOTTOM, WLEFT };
1076 //--unused-- int SideOrderRight[] =  { WLEFT, WFRONT, WTOP, WBACK, WBOTTOM, WRIGHT };
1077 //--unused-- int SideOrderTop[] =  { WBOTTOM, WLEFT, WBACK, WRIGHT, WFRONT, WTOP };
1078 //--unused-- int SideOrderBottom[] =  { WTOP, WLEFT, WFRONT, WRIGHT, WBACK, WBOTTOM };
1079
1080 //--unused-- int SideUpVector[] = {WBOTTOM, WFRONT, WBOTTOM, WFRONT, WBOTTOM, WBOTTOM };
1081
1082 //--repair-- // ----------------------------------------------------------------------------------------------------------
1083 //--repair-- void refuel_calc_deltas(object *obj, int next_side, int repair_seg)
1084 //--repair-- {
1085 //--repair--    vms_vector nextcenter, headfvec, *headuvec;
1086 //--repair--    vms_matrix goal_orient;
1087 //--repair--
1088 //--repair--    // Find time for this movement
1089 //--repair--    delta_time = F1_0;              // one second...
1090 //--repair--            
1091 //--repair--    // Find start and goal position
1092 //--repair--    start_pos = obj->pos;
1093 //--repair--    
1094 //--repair--    // Find delta position to get to goal position
1095 //--repair--    compute_segment_center(&goal_pos,&Segments[repair_seg]);
1096 //--repair--    vm_vec_sub( &delta_pos,&goal_pos,&start_pos);
1097 //--repair--    
1098 //--repair--    // Find start angles
1099 //--repair--    //angles_from_vector(&start_angles,&obj->orient.fvec);
1100 //--repair--    vm_extract_angles_matrix(&start_angles,&obj->orient);
1101 //--repair--    
1102 //--repair--    // Find delta angles to get to goal orientation
1103 //--repair--    med_compute_center_point_on_side(&nextcenter,&Segments[repair_seg],next_side);
1104 //--repair--    vm_vec_sub(&headfvec,&nextcenter,&goal_pos);
1105 //--repair--    //mprintf( (0, "Next_side = %d, Head fvec = %d,%d,%d\n", next_side, headfvec.x, headfvec.y, headfvec.z ));
1106 //--repair--
1107 //--repair--    if (next_side == 5)                                             //last side
1108 //--repair--            headuvec = &repair_save_uvec;
1109 //--repair--    else
1110 //--repair--            headuvec = &Segments[repair_seg].sides[SideUpVector[next_side]].normals[0];
1111 //--repair--
1112 //--repair--    vm_vector_2_matrix(&goal_orient,&headfvec,headuvec,NULL);
1113 //--repair--    vm_extract_angles_matrix(&goal_angles,&goal_orient);
1114 //--repair--    delta_angles.p = my_delta_ang(start_angles.p,goal_angles.p);
1115 //--repair--    delta_angles.b = my_delta_ang(start_angles.b,goal_angles.b);
1116 //--repair--    delta_angles.h = my_delta_ang(start_angles.h,goal_angles.h);
1117 //--repair--    current_time = 0;
1118 //--repair--    Repairing = 0;
1119 //--repair-- }
1120 //--repair--
1121 //--repair-- // ----------------------------------------------------------------------------------------------------------
1122 //--repair-- //if repairing, cut it short
1123 //--repair-- abort_repair_center()
1124 //--repair-- {
1125 //--repair--    if (!RepairObj || side_index==5)
1126 //--repair--            return;
1127 //--repair--
1128 //--repair--    current_time = 0;
1129 //--repair--    side_index = 5;
1130 //--repair--    next_side = sidelist[side_index];
1131 //--repair--    refuel_calc_deltas(RepairObj, next_side, FuelStationSeg);
1132 //--repair-- }
1133 //--repair--
1134 //--repair-- // ----------------------------------------------------------------------------------------------------------
1135 //--repair-- void repair_ship_damage()
1136 //--repair-- {
1137 //--repair--    //mprintf((0,"Repairing ship damage\n"));
1138 //--repair-- }
1139 //--repair--
1140 //--repair-- // ----------------------------------------------------------------------------------------------------------
1141 //--repair-- int refuel_do_repair_effect( object * obj, int first_time, int repair_seg )        {
1142 //--repair--
1143 //--repair--    obj->mtype.phys_info.velocity.x = 0;                            
1144 //--repair--    obj->mtype.phys_info.velocity.y = 0;                            
1145 //--repair--    obj->mtype.phys_info.velocity.z = 0;                            
1146 //--repair--
1147 //--repair--    if (first_time) {
1148 //--repair--            int entry_side;
1149 //--repair--            current_time = 0;
1150 //--repair--
1151 //--repair--            digi_play_sample( SOUND_REPAIR_STATION_PLAYER_ENTERING, F1_0 );
1152 //--repair--
1153 //--repair--            entry_side = john_find_connect_side(repair_seg,obj->segnum );
1154 //--repair--            Assert( entry_side > -1 );
1155 //--repair--
1156 //--repair--            switch( entry_side )    {
1157 //--repair--            case WBACK: sidelist = SideOrderBack; break;
1158 //--repair--            case WFRONT: sidelist = SideOrderFront; break;
1159 //--repair--            case WLEFT: sidelist = SideOrderLeft; break;
1160 //--repair--            case WRIGHT: sidelist = SideOrderRight; break;
1161 //--repair--            case WTOP: sidelist = SideOrderTop; break;
1162 //--repair--            case WBOTTOM: sidelist = SideOrderBottom; break;
1163 //--repair--            }
1164 //--repair--            side_index = 0;
1165 //--repair--            next_side = sidelist[side_index];
1166 //--repair--
1167 //--repair--            refuel_calc_deltas(obj,next_side, repair_seg);
1168 //--repair--    }
1169 //--repair--
1170 //--repair--    //update shields
1171 //--repair--    if (Players[Player_num].shields < MAX_SHIELDS) {        //if above max, don't mess with it
1172 //--repair--
1173 //--repair--            Players[Player_num].shields += fixmul(FrameTime,repair_rate);
1174 //--repair--
1175 //--repair--            if (Players[Player_num].shields > MAX_SHIELDS)
1176 //--repair--                    Players[Player_num].shields = MAX_SHIELDS;
1177 //--repair--    }
1178 //--repair--
1179 //--repair--    current_time += FrameTime;
1180 //--repair--
1181 //--repair--    if (current_time >= delta_time )        {
1182 //--repair--            vms_angvec av;
1183 //--repair--            obj->pos = goal_pos;
1184 //--repair--            av      = goal_angles;
1185 //--repair--            vm_angles_2_matrix(&obj->orient,&av);
1186 //--repair--
1187 //--repair--            if (side_index >= 5 )   
1188 //--repair--                    return 1;               // Done being repaired...
1189 //--repair--
1190 //--repair--            if (Repairing==0)               {
1191 //--repair--                    //mprintf( (0, "<MACHINE EFFECT ON SIDE %d>\n", next_side ));
1192 //--repair--                    //digi_play_sample( SOUND_REPAIR_STATION_FIXING );
1193 //--repair--                    Repairing=1;
1194 //--repair--
1195 //--repair--                    switch( next_side )     {
1196 //--repair--                    case 0: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
1197 //--repair--                    case 1: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
1198 //--repair--                    case 2: digi_play_sample( SOUND_REPAIR_STATION_FIXING_3,F1_0 ); break;
1199 //--repair--                    case 3: digi_play_sample( SOUND_REPAIR_STATION_FIXING_4,F1_0 ); break;
1200 //--repair--                    case 4: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
1201 //--repair--                    case 5: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
1202 //--repair--                    }
1203 //--repair--            
1204 //--repair--                    repair_ship_damage();
1205 //--repair--
1206 //--repair--            }
1207 //--repair--
1208 //--repair--            if (current_time >= (delta_time+(F1_0/2)) )     {
1209 //--repair--                    current_time = 0;
1210 //--repair--                    // Find next side...
1211 //--repair--                    side_index++;
1212 //--repair--                    if (side_index >= 6 ) return 1;
1213 //--repair--                    next_side = sidelist[side_index];
1214 //--repair--    
1215 //--repair--                    refuel_calc_deltas(obj, next_side, repair_seg);
1216 //--repair--            }
1217 //--repair--
1218 //--repair--    } else {
1219 //--repair--            fix factor, p,b,h;      
1220 //--repair--            vms_angvec av;
1221 //--repair--
1222 //--repair--            factor = fixdiv( current_time,delta_time );
1223 //--repair--
1224 //--repair--            // Find object's current position
1225 //--repair--            obj->pos = delta_pos;
1226 //--repair--            vm_vec_scale( &obj->pos, factor );
1227 //--repair--            vm_vec_add2( &obj->pos, &start_pos );
1228 //--repair--                    
1229 //--repair--            // Find object's current orientation
1230 //--repair--            p       = fixmul(delta_angles.p,factor);
1231 //--repair--            b       = fixmul(delta_angles.b,factor);
1232 //--repair--            h       = fixmul(delta_angles.h,factor);
1233 //--repair--            av.p = (fixang)p + start_angles.p;
1234 //--repair--            av.b = (fixang)b + start_angles.b;
1235 //--repair--            av.h = (fixang)h + start_angles.h;
1236 //--repair--            vm_angles_2_matrix(&obj->orient,&av);
1237 //--repair--
1238 //--repair--    }
1239 //--repair--
1240 //--repair--    update_object_seg(obj);         //update segment
1241 //--repair--
1242 //--repair--    return 0;
1243 //--repair-- }
1244 //--repair--
1245 //--repair-- // ----------------------------------------------------------------------------------------------------------
1246 //--repair-- //do the repair center for this frame
1247 //--repair-- void do_repair_sequence(object *obj)
1248 //--repair-- {
1249 //--repair--    Assert(obj == RepairObj);
1250 //--repair--
1251 //--repair--    if (refuel_do_repair_effect( obj, 0, FuelStationSeg )) {
1252 //--repair--            if (Players[Player_num].shields < MAX_SHIELDS)
1253 //--repair--                    Players[Player_num].shields = MAX_SHIELDS;
1254 //--repair--            obj->control_type = save_control_type;
1255 //--repair--            obj->movement_type = save_movement_type;
1256 //--repair--            disable_repair_center=1;
1257 //--repair--            RepairObj = NULL;
1258 //--repair--
1259 //--repair--
1260 //--repair--            //the two lines below will spit the player out of the rapair center,
1261 //--repair--            //but what happen is that the ship just bangs into the door
1262 //--repair--            //if (obj->movement_type == MT_PHYSICS)
1263 //--repair--            //      vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&obj->orient.fvec,i2f(200));
1264 //--repair--    }
1265 //--repair--
1266 //--repair-- }
1267 //--repair--
1268 //--repair-- // ----------------------------------------------------------------------------------------------------------
1269 //--repair-- //see if we should start the repair center
1270 //--repair-- void check_start_repair_center(object *obj)
1271 //--repair-- {
1272 //--repair--    if (RepairObj != NULL) return;          //already in repair center
1273 //--repair--
1274 //--repair--    if (Lsegments[obj->segnum].special_type & SS_REPAIR_CENTER) {
1275 //--repair--
1276 //--repair--            if (!disable_repair_center) {
1277 //--repair--                    //have just entered repair center
1278 //--repair--
1279 //--repair--                    RepairObj = obj;
1280 //--repair--                    repair_save_uvec = obj->orient.uvec;
1281 //--repair--
1282 //--repair--                    repair_rate = fixmuldiv(FULL_REPAIR_RATE,(MAX_SHIELDS - Players[Player_num].shields),MAX_SHIELDS);
1283 //--repair--
1284 //--repair--                    save_control_type = obj->control_type;
1285 //--repair--                    save_movement_type = obj->movement_type;
1286 //--repair--
1287 //--repair--                    obj->control_type = CT_REPAIRCEN;
1288 //--repair--                    obj->movement_type = MT_NONE;
1289 //--repair--
1290 //--repair--                    FuelStationSeg  = Lsegments[obj->segnum].special_segment;
1291 //--repair--                    Assert(FuelStationSeg != -1);
1292 //--repair--
1293 //--repair--                    if (refuel_do_repair_effect( obj, 1, FuelStationSeg )) {
1294 //--repair--                            Int3();         //can this happen?
1295 //--repair--                            obj->control_type = CT_FLYING;
1296 //--repair--                            obj->movement_type = MT_PHYSICS;
1297 //--repair--                    }
1298 //--repair--            }
1299 //--repair--    }
1300 //--repair--    else
1301 //--repair--            disable_repair_center=0;
1302 //--repair--
1303 //--repair-- }
1304
1305 //      --------------------------------------------------------------------------------------------
1306 void disable_matcens(void)
1307 {
1308         int     i;
1309
1310         for (i=0; i<Num_robot_centers; i++) {
1311                 Station[i].Enabled = 0;
1312                 Station[i].Disable_time = 0;
1313         }
1314 }
1315
1316 //      --------------------------------------------------------------------------------------------
1317 //      Initialize all materialization centers.
1318 //      Give them all the right number of lives.
1319 void init_all_matcens(void)
1320 {
1321         int     i;
1322
1323         for (i=0; i<Num_fuelcenters; i++)
1324                 if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
1325                         Station[i].Lives = 3;
1326                         Station[i].Enabled = 0;
1327                         Station[i].Disable_time = 0;
1328 #ifndef NDEBUG
1329 {
1330                         //      Make sure this fuelcen is pointed at by a matcen.
1331                         int     j;
1332                         for (j=0; j<Num_robot_centers; j++) {
1333                                 if (RobotCenters[j].fuelcen_num == i)
1334                                         break;
1335                         }
1336                         Assert(j != Num_robot_centers);
1337 }
1338 #endif
1339
1340                 }
1341
1342 #ifndef NDEBUG
1343         //      Make sure all matcens point at a fuelcen
1344         for (i=0; i<Num_robot_centers; i++) {
1345                 int     fuelcen_num = RobotCenters[i].fuelcen_num;
1346
1347                 Assert(fuelcen_num < Num_fuelcenters);
1348                 Assert(Station[fuelcen_num].Type == SEGMENT_IS_ROBOTMAKER);
1349         }
1350 #endif
1351
1352 }
1353
1354 #ifdef NETWORK
1355 extern void multi_send_capture_bonus (char);
1356
1357 void fuelcen_check_for_goal(segment *segp)
1358 {
1359         segment2        *seg2p = &Segment2s[segp-Segments];
1360
1361         Assert( segp != NULL );
1362         Assert (Game_mode & GM_CAPTURE);
1363
1364         if (seg2p->special==SEGMENT_IS_GOAL_BLUE )      {
1365
1366                         if ((get_team(Player_num)==TEAM_BLUE) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1367                          {
1368                                 mprintf ((0,"In goal segment BLUE\n"));
1369
1370                                 multi_send_capture_bonus (Player_num);
1371                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1372                                 maybe_drop_net_powerup (POW_FLAG_RED);
1373                          }
1374                  }
1375         if ( seg2p->special==SEGMENT_IS_GOAL_RED) {
1376
1377                         if ((get_team(Player_num)==TEAM_RED) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1378                          {              
1379                                 mprintf ((0,"In goal segment RED\n"));
1380                                 multi_send_capture_bonus (Player_num);
1381                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1382                                 maybe_drop_net_powerup (POW_FLAG_BLUE);
1383                          }
1384                  }
1385   }
1386
1387 void fuelcen_check_for_hoard_goal(segment *segp)
1388 {
1389         segment2        *seg2p = &Segment2s[segp-Segments];
1390
1391         Assert( segp != NULL );
1392         Assert (Game_mode & GM_HOARD);
1393
1394    if (Player_is_dead)
1395                 return;
1396
1397         if (seg2p->special==SEGMENT_IS_GOAL_BLUE || seg2p->special==SEGMENT_IS_GOAL_RED  )      
1398         {
1399                 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
1400                 {
1401                                 mprintf ((0,"In orb goal!\n"));
1402                                 multi_send_orb_bonus (Player_num);
1403                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1404                                 Players[Player_num].secondary_ammo[PROXIMITY_INDEX]=0;
1405       }
1406         }
1407
1408 }
1409
1410 #endif
1411
1412 #ifndef FAST_FILE_IO
1413 /*
1414  * reads an old_matcen_info structure from a CFILE
1415  */
1416 void old_matcen_info_read(old_matcen_info *mi, CFILE *fp)
1417 {
1418         mi->robot_flags = cfile_read_int(fp);
1419         mi->hit_points = cfile_read_fix(fp);
1420         mi->interval = cfile_read_fix(fp);
1421         mi->segnum = cfile_read_short(fp);
1422         mi->fuelcen_num = cfile_read_short(fp);
1423 }
1424
1425 /*
1426  * reads a matcen_info structure from a CFILE
1427  */
1428 void matcen_info_read(matcen_info *mi, CFILE *fp)
1429 {
1430         mi->robot_flags[0] = cfile_read_int(fp);
1431         mi->robot_flags[1] = cfile_read_int(fp);
1432         mi->hit_points = cfile_read_fix(fp);
1433         mi->interval = cfile_read_fix(fp);
1434         mi->segnum = cfile_read_short(fp);
1435         mi->fuelcen_num = cfile_read_short(fp);
1436 }
1437 #endif