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