]> icculus.org git repositories - btb/d2x.git/blob - main/fuelcen.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / main / fuelcen.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Functions for refueling centers.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28
29 #include "inferno.h"
30 #include "dxxerror.h"
31 #include "mono.h"
32 #include "3d.h"
33
34
35 // The max number of fuel stations per mine.
36
37 fix Fuelcen_refill_speed = i2f(1);
38 fix Fuelcen_give_amount = i2f(25);
39 fix Fuelcen_max_amount = i2f(100);
40
41 // Every time a robot is created in the morphing code, it decreases capacity of the morpher
42 // by this amount... when capacity gets to 0, no more morphers...
43 fix EnergyToCreateOneRobot = i2f(1);
44
45 #define MATCEN_HP_DEFAULT                       F1_0*500; // Hitpoints
46 #define MATCEN_INTERVAL_DEFAULT F1_0*5; //  5 seconds
47
48 matcen_info RobotCenters[MAX_ROBOT_CENTERS];
49 int Num_robot_centers;
50
51 FuelCenter Station[MAX_NUM_FUELCENS];
52 int Num_fuelcenters = 0;
53
54 segment * PlayerSegment= NULL;
55
56 #ifdef EDITOR
57 char    Special_names[MAX_CENTER_TYPES][11] = {
58         "NOTHING   ",
59         "FUELCEN   ",
60         "REPAIRCEN ",
61         "CONTROLCEN",
62         "ROBOTMAKER",
63         "GOAL_RED",
64         "GOAL_BLUE",
65 };
66 #endif
67
68 //------------------------------------------------------------
69 // Resets all fuel center info
70 void fuelcen_reset()
71 {
72         int i;
73
74         Num_fuelcenters = 0;
75         //mprintf( (0, "All fuel centers reset.\n"));
76
77         for(i=0; i<MAX_SEGMENTS; i++ )
78                 Segment2s[i].special = SEGMENT_IS_NOTHING;
79
80         Num_robot_centers = 0;
81
82 }
83
84 #ifndef NDEBUG          //this is sometimes called by people from the debugger
85 void reset_all_robot_centers()
86 {
87         int i;
88
89         // Remove all materialization centers
90         for (i=0; i<Num_segments; i++)
91                 if (Segment2s[i].special == SEGMENT_IS_ROBOTMAKER) {
92                         Segment2s[i].special = SEGMENT_IS_NOTHING;
93                         Segment2s[i].matcen_num = -1;
94                 }
95 }
96 #endif
97
98 //------------------------------------------------------------
99 // Turns a segment into a fully charged up fuel center...
100 void fuelcen_create( segment *segp)
101 {
102         segment2 *seg2p = s2s2(segp);
103
104         int     station_type;
105
106         station_type = seg2p->special;
107
108         switch( station_type )  {
109         case SEGMENT_IS_NOTHING:
110         case SEGMENT_IS_GOAL_BLUE:
111         case SEGMENT_IS_GOAL_RED:
112                 return;
113         case SEGMENT_IS_FUELCEN:
114         case SEGMENT_IS_REPAIRCEN:
115         case SEGMENT_IS_CONTROLCEN:
116         case SEGMENT_IS_ROBOTMAKER:
117                 break;
118         default:
119                 Error( "Invalid station type %d in fuelcen.c\n", station_type );
120         }
121
122         Assert( (seg2p != NULL) );
123         if ( seg2p == NULL ) return;
124
125         Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
126         Assert( Num_fuelcenters > -1 );
127
128         seg2p->value = Num_fuelcenters;
129         Station[Num_fuelcenters].Type = station_type;
130         Station[Num_fuelcenters].MaxCapacity = Fuelcen_max_amount;
131         Station[Num_fuelcenters].Capacity = Station[Num_fuelcenters].MaxCapacity;
132         Station[Num_fuelcenters].segnum = SEGMENT_NUMBER(segp);
133         Station[Num_fuelcenters].Timer = -1;
134         Station[Num_fuelcenters].Flag = 0;
135 //      Station[Num_fuelcenters].NextRobotType = -1;
136 //      Station[Num_fuelcenters].last_created_obj=NULL;
137 //      Station[Num_fuelcenters].last_created_sig = -1;
138         compute_segment_center(&Station[Num_fuelcenters].Center, segp);
139
140 //      if (station_type == SEGMENT_IS_ROBOTMAKER)
141 //              Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
142
143         //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
144         Num_fuelcenters++;
145 }
146
147 //------------------------------------------------------------
148 // Adds a matcen that already is a special type into the Station array.
149 // This function is separate from other fuelcens because we don't want values reset.
150 void matcen_create( segment *segp)
151 {
152         segment2 *seg2p = s2s2(segp);
153
154         int     station_type = seg2p->special;
155
156         Assert( (seg2p != NULL) );
157         Assert(station_type == SEGMENT_IS_ROBOTMAKER);
158         if ( seg2p == NULL ) return;
159
160         Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
161         Assert( Num_fuelcenters > -1 );
162
163         seg2p->value = Num_fuelcenters;
164         Station[Num_fuelcenters].Type = station_type;
165         Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
166         Station[Num_fuelcenters].MaxCapacity = Station[Num_fuelcenters].Capacity;
167
168         Station[Num_fuelcenters].segnum = SEGMENT_NUMBER(segp);
169         Station[Num_fuelcenters].Timer = -1;
170         Station[Num_fuelcenters].Flag = 0;
171 //      Station[Num_fuelcenters].NextRobotType = -1;
172 //      Station[Num_fuelcenters].last_created_obj=NULL;
173 //      Station[Num_fuelcenters].last_created_sig = -1;
174         compute_segment_center( &Station[Num_fuelcenters].Center, segp );
175
176         seg2p->matcen_num = Num_robot_centers;
177         Num_robot_centers++;
178
179         RobotCenters[seg2p->matcen_num].hit_points = MATCEN_HP_DEFAULT;
180         RobotCenters[seg2p->matcen_num].interval = MATCEN_INTERVAL_DEFAULT;
181         RobotCenters[seg2p->matcen_num].segnum = SEGMENT_NUMBER(segp);
182         RobotCenters[seg2p->matcen_num].fuelcen_num = Num_fuelcenters;
183
184         //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
185         Num_fuelcenters++;
186 }
187
188 //------------------------------------------------------------
189 // Adds a segment that already is a special type into the Station array.
190 void fuelcen_activate( segment * segp, int station_type )
191 {
192         segment2 *seg2p = s2s2(segp);
193
194         seg2p->special = station_type;
195
196         if (seg2p->special == SEGMENT_IS_ROBOTMAKER)
197                 matcen_create( segp);
198         else
199                 fuelcen_create( segp);
200         
201 }
202
203 //      The lower this number is, the more quickly the center can be re-triggered.
204 //      If it's too low, it can mean all the robots won't be put out, but for about 5
205 //      robots, that's not real likely.
206 #define MATCEN_LIFE (i2f(30-2*Difficulty_level))
207
208 //------------------------------------------------------------
209 //      Trigger (enable) the materialization center in segment segnum
210 void trigger_matcen(int segnum)
211 {
212         // -- segment           *segp = &Segments[segnum];
213         segment2                *seg2p = &Segment2s[segnum];
214         vms_vector      pos, delta;
215         FuelCenter      *robotcen;
216         int                     objnum;
217
218         mprintf((0, "Trigger matcen, segment %i\n", segnum));
219
220         Assert(seg2p->special == SEGMENT_IS_ROBOTMAKER);
221         Assert(seg2p->matcen_num < Num_fuelcenters);
222         Assert((seg2p->matcen_num >= 0) && (seg2p->matcen_num <= Highest_segment_index));
223
224         robotcen = &Station[RobotCenters[seg2p->matcen_num].fuelcen_num];
225
226         if (robotcen->Enabled == 1)
227                 return;
228
229         if (!robotcen->Lives)
230                 return;
231
232         //      MK: 11/18/95, At insane, matcens work forever!
233         if (Difficulty_level+1 < NDL)
234                 robotcen->Lives--;
235
236         robotcen->Timer = F1_0*1000;    //      Make sure the first robot gets emitted right away.
237         robotcen->Enabled = 1;                  //      Say this center is enabled, it can create robots.
238         robotcen->Capacity = i2f(Difficulty_level + 3);
239         robotcen->Disable_time = MATCEN_LIFE;
240
241         //      Create a bright object in the segment.
242         pos = robotcen->Center;
243         vm_vec_sub(&delta, &Vertices[Segments[segnum].verts[0]], &robotcen->Center);
244         vm_vec_scale_add2(&pos, &delta, F1_0/2);
245         objnum = obj_create( OBJ_LIGHT, 0, segnum, &pos, NULL, 0, CT_LIGHT, MT_NONE, RT_NONE );
246         if (objnum != -1) {
247                 Objects[objnum].lifeleft = MATCEN_LIFE;
248                 Objects[objnum].ctype.light_info.intensity = i2f(8);    //      Light cast by a fuelcen.
249         } else {
250                 mprintf((1, "Can't create invisible flare for matcen.\n"));
251                 Int3();
252         }
253 //      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)));
254 }
255
256 #ifdef EDITOR
257 //------------------------------------------------------------
258 // Takes away a segment's fuel center properties.
259 //      Deletes the segment point entry in the FuelCenter list.
260 void fuelcen_delete( segment * segp )
261 {
262         segment2 *seg2p = s2s2(segp);
263         int i, j;
264
265 Restart: ;
266
267         seg2p->special = 0;
268
269         for (i=0; i<Num_fuelcenters; i++ )      {
270                 if ( Station[i].segnum == SEGMENT_NUMBER(segp) ) {
271
272                         // If Robot maker is deleted, fix Segments and RobotCenters.
273                         if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
274                                 Num_robot_centers--;
275                                 Assert(Num_robot_centers >= 0);
276
277                                 for (j=seg2p->matcen_num; j<Num_robot_centers; j++)
278                                         RobotCenters[j] = RobotCenters[j+1];
279
280                                 for (j=0; j<Num_fuelcenters; j++) {
281                                         if ( Station[j].Type == SEGMENT_IS_ROBOTMAKER )
282                                                 if ( Segment2s[Station[j].segnum].matcen_num > seg2p->matcen_num )
283                                                         Segment2s[Station[j].segnum].matcen_num--;
284                                 }
285                         }
286
287                         //fix RobotCenters so they point to correct fuelcenter
288                         for (j=0; j<Num_robot_centers; j++ )
289                                 if (RobotCenters[j].fuelcen_num > i)            //this robotcenter's fuelcen is changing
290                                         RobotCenters[j].fuelcen_num--;
291
292                         Num_fuelcenters--;
293                         Assert(Num_fuelcenters >= 0);
294                         for (j=i; j<Num_fuelcenters; j++ )      {
295                                 Station[j] = Station[j+1];
296                                 Segment2s[Station[j].segnum].value = j;
297                         }
298                         goto Restart;
299                 }
300         }
301
302 }
303 #endif
304
305 #define ROBOT_GEN_TIME (i2f(5))
306
307 object * create_morph_robot( segment *segp, vms_vector *object_pos, int object_id)
308 {
309         short           objnum;
310         object  *obj;
311         int             default_behavior;
312
313         Players[Player_num].num_robots_level++;
314         Players[Player_num].num_robots_total++;
315
316         objnum = obj_create(OBJ_ROBOT, object_id, SEGMENT_NUMBER(segp), object_pos,
317                                 &vmd_identity_matrix, Polygon_models[Robot_info[object_id].model_num].rad,
318                                 CT_AI, MT_PHYSICS, RT_POLYOBJ);
319
320         if ( objnum < 0 ) {
321                 mprintf((1, "Can't create morph robot.  Aborting morph.\n"));
322                 Int3();
323                 return NULL;
324         }
325
326         obj = &Objects[objnum];
327
328         //Set polygon-object-specific data
329
330         obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
331         obj->rtype.pobj_info.subobj_flags = 0;
332
333         //set Physics info
334
335         obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
336         obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
337
338         obj->mtype.phys_info.flags |= (PF_LEVELLING);
339
340         obj->shields = Robot_info[obj->id].strength;
341         
342         default_behavior = Robot_info[obj->id].behavior;
343
344         init_ai_object( OBJECT_NUMBER(obj), default_behavior, -1 ); // Note, -1 = segment this robot goes to to hide, should probably be something useful
345
346         create_n_segment_path(obj, 6, -1);              //      Create a 6 segment path from creation point.
347
348         Ai_local_info[objnum].mode = ai_behavior_to_mode(default_behavior);
349
350         return obj;
351 }
352
353 int Num_extry_robots = 15;
354
355 #ifndef NDEBUG
356 int     FrameCount_last_msg = 0;
357 #endif
358
359 //      ----------------------------------------------------------------------------------------------------------
360 void robotmaker_proc( FuelCenter * robotcen )
361 {
362         fix             dist_to_player;
363         vms_vector      cur_object_loc; //, direction;
364         int             matcen_num, segnum, objnum;
365         object  *obj;
366         fix             top_time;
367         vms_vector      direction;
368
369         if (robotcen->Enabled == 0)
370                 return;
371
372         if (robotcen->Disable_time > 0) {
373                 robotcen->Disable_time -= FrameTime;
374                 if (robotcen->Disable_time <= 0) {
375                         mprintf((0, "Robot center #%i gets disabled due to time running out.\n", robotcen-Station));
376                         robotcen->Enabled = 0;
377                 }
378         }
379
380         // mprintf((0, "Capacity of robot maker #%i is %i\n", robotcen - Station, robotcen->Capacity));
381
382         //      No robot making in multiplayer mode.
383 #ifdef NETWORK
384 #ifndef SHAREWARE
385         if ((Game_mode & GM_MULTI) && (!(Game_mode & GM_MULTI_ROBOTS) || !network_i_am_master()))
386                 return;
387 #else
388         if (Game_mode & GM_MULTI)
389                 return;
390 #endif
391 #endif
392
393         // Wait until transmorgafier has capacity to make a robot...
394         if ( robotcen->Capacity <= 0 ) {
395                 return;
396         }
397
398         matcen_num = Segment2s[robotcen->segnum].matcen_num;
399         //mprintf((0, "Robotmaker #%i flags = %8x\n", matcen_num, RobotCenters[matcen_num].robot_flags));
400
401         if ( matcen_num == -1 ) {
402                 mprintf((0, "Non-functional robotcen at %d\n", robotcen->segnum));
403                 return;
404         }
405
406         if (RobotCenters[matcen_num].robot_flags[0]==0 && RobotCenters[matcen_num].robot_flags[1]==0) {
407                 //mprintf((0, "robot_flags = 0 at robot maker #%i\n", RobotCenters[matcen_num].robot_flags));
408                 return;
409         }
410
411         // Wait until we have a free slot for this puppy...
412    //     <<<<<<<<<<<<<<<< Num robots in mine >>>>>>>>>>>>>>>>>>>>>>>>>>    <<<<<<<<<<<< Max robots in mine >>>>>>>>>>>>>>>
413         if ( (Players[Player_num].num_robots_level - Players[Player_num].num_kills_level) >= (Gamesave_num_org_robots + Num_extry_robots ) ) {
414                 #ifndef NDEBUG
415                 if (FrameCount > FrameCount_last_msg + 20) {
416                         mprintf((0, "Cannot morph until you kill one!\n"));
417                         FrameCount_last_msg = FrameCount;
418                 }
419                 #endif
420                 return;
421         }
422
423         robotcen->Timer += FrameTime;
424
425         switch( robotcen->Flag )        {
426         case 0:         // Wait until next robot can generate
427                 if (Game_mode & GM_MULTI)
428                 {
429                         top_time = ROBOT_GEN_TIME;      
430                 }
431                 else
432                 {
433                         dist_to_player = vm_vec_dist_quick( &ConsoleObject->pos, &robotcen->Center );
434                         top_time = dist_to_player/64 + d_rand() * 2 + F1_0*2;
435                         if ( top_time > ROBOT_GEN_TIME )
436                                 top_time = ROBOT_GEN_TIME + d_rand();
437                         if ( top_time < F1_0*2 )
438                                 top_time = F1_0*3/2 + d_rand()*2;
439                 }
440
441                 // mprintf( (0, "Time between morphs %d seconds, dist_to_player = %7.3f\n", f2i(top_time), f2fl(dist_to_player) ));
442
443                 if (robotcen->Timer > top_time )        {
444                         int     count=0;
445                         int     i, my_station_num = (int)(robotcen - Station);
446                         object *obj;
447
448                         //      Make sure this robotmaker hasn't put out its max without having any of them killed.
449                         for (i=0; i<=Highest_object_index; i++)
450                                 if (Objects[i].type == OBJ_ROBOT)
451                                         if ((Objects[i].matcen_creator^0x80) == my_station_num)
452                                                 count++;
453                         if (count > Difficulty_level + 3) {
454                                 mprintf((0, "Cannot morph: center %i has already put out %i robots.\n", my_station_num, count));
455                                 robotcen->Timer /= 2;
456                                 return;
457                         }
458
459                         //      Whack on any robot or player in the matcen segment.
460                         count=0;
461                         segnum = robotcen->segnum;
462                         for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next)    {
463                                 count++;
464                                 if ( count > MAX_OBJECTS )      {
465                                         mprintf((0, "Object list in segment %d is circular.", segnum ));
466                                         Int3();
467                                         return;
468                                 }
469                                 if (Objects[objnum].type==OBJ_ROBOT) {
470                                         collide_robot_and_materialization_center(&Objects[objnum]);
471                                         robotcen->Timer = top_time/2;
472                                         return;
473                                 } else if (Objects[objnum].type==OBJ_PLAYER ) {
474                                         collide_player_and_materialization_center(&Objects[objnum]);
475                                         robotcen->Timer = top_time/2;
476                                         return;
477                                 }
478                         }
479
480                         compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
481                         // HACK!!! The 10 under here should be something equal to the 1/2 the size of the segment.
482                         obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT );
483
484                         if (obj)
485                                 extract_orient_from_segment(&obj->orient,&Segments[robotcen->segnum]);
486
487                         if ( Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1 )               {
488                                 digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 );
489                         }
490                         robotcen->Flag  = 1;
491                         robotcen->Timer = 0;
492
493                 }
494                 break;
495         case 1:                 // Wait until 1/2 second after VCLIP started.
496                 if (robotcen->Timer > (Vclip[VCLIP_MORPHING_ROBOT].play_time/2) )       {
497
498                         robotcen->Capacity -= EnergyToCreateOneRobot;
499                         robotcen->Flag = 0;
500
501                         robotcen->Timer = 0;
502                         compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
503
504                         // If this is the first materialization, set to valid robot.
505                         if (RobotCenters[matcen_num].robot_flags[0] != 0 || RobotCenters[matcen_num].robot_flags[1] != 0) {
506                                 int     type;
507                                 uint    flags;
508                                 sbyte   legal_types[64];   // 64 bits, the width of robot_flags[].
509                                 int     num_types, robot_index, i;
510
511                                 num_types = 0;
512                                 for (i=0;i<2;i++) {
513                                         robot_index = i*32;
514                                         flags = RobotCenters[matcen_num].robot_flags[i];
515                                         while (flags) {
516                                                 if (flags & 1)
517                                                         legal_types[num_types++] = robot_index;
518                                                 flags >>= 1;
519                                                 robot_index++;
520                                         }
521                                 }
522
523                                 //mprintf((0, "Flags = %08x, %2i legal types to morph: \n", RobotCenters[matcen_num].robot_flags, num_types));
524                                 //for (i=0; i<num_types; i++)
525                                 //      mprintf((0, "%2i ", legal_types[i]));
526                                 //mprintf((0, "\n"));
527
528                                 if (num_types == 1)
529                                         type = legal_types[0];
530                                 else
531                                         type = legal_types[(d_rand() * num_types) / 32768];
532
533                                 mprintf((0, "Morph: (type = %i) (seg = %i) (capacity = %08x)\n", type, robotcen->segnum, robotcen->Capacity));
534                                 obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type );
535                                 if (obj != NULL) {
536 #ifndef SHAREWARE
537 #ifdef NETWORK
538                                         if (Game_mode & GM_MULTI)
539                                                 multi_send_create_robot((int)(robotcen - Station), OBJECT_NUMBER(obj), type);
540 #endif
541 #endif
542                                         obj->matcen_creator = (robotcen-Station) | 0x80;
543
544                                         // Make object faces player...
545                                         vm_vec_sub( &direction, &ConsoleObject->pos,&obj->pos );
546                                         vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL);
547         
548                                         morph_start( obj );
549                                         //robotcen->last_created_obj = obj;
550                                         //robotcen->last_created_sig = robotcen->last_created_obj->signature;
551                                 } else
552                                         mprintf((0, "Warning: create_morph_robot returned NULL (no objects left?)\n"));
553
554                         }
555  
556                 }
557                 break;
558         default:
559                 robotcen->Flag = 0;
560                 robotcen->Timer = 0;
561         }
562 }
563
564
565 //-------------------------------------------------------------
566 // Called once per frame, replenishes fuel supply.
567 void fuelcen_update_all()
568 {
569         int i;
570         fix AmountToreplenish;
571         
572         AmountToreplenish = fixmul(FrameTime,Fuelcen_refill_speed);
573
574         for (i=0; i<Num_fuelcenters; i++ )      {
575                 if ( Station[i].Type == SEGMENT_IS_ROBOTMAKER ) {
576                         if (! (Game_suspended & SUSP_ROBOTS))
577                                 robotmaker_proc( &Station[i] );
578                 } else if ( Station[i].Type == SEGMENT_IS_CONTROLCEN )  {
579                         //controlcen_proc( &Station[i] );
580         
581                 } else if ( (Station[i].MaxCapacity > 0) && (PlayerSegment!=&Segments[Station[i].segnum]) )     {
582                         if ( Station[i].Capacity < Station[i].MaxCapacity )     {
583                                 Station[i].Capacity += AmountToreplenish;
584                                 //mprintf( (0, "Fuel center %d replenished to %d.\n", i, f2i(Station[i].Capacity) ));
585                                 if ( Station[i].Capacity >= Station[i].MaxCapacity )            {
586                                         Station[i].Capacity = Station[i].MaxCapacity;
587                                         //gauge_message( "Fuel center is fully recharged!    " );
588                                 }
589                         }
590                 }
591         }
592 }
593
594 //--unused-- //-------------------------------------------------------------
595 //--unused-- // replenishes all fuel supplies.
596 //--unused-- void fuelcen_replenish_all()
597 //--unused-- {
598 //--unused--    int i;
599 //--unused--
600 //--unused--    for (i=0; i<Num_fuelcenters; i++ )      {
601 //--unused--            Station[i].Capacity = Station[i].MaxCapacity;
602 //--unused--    }
603 //--unused--    //mprintf( (0, "All fuel centers are replenished\n" ));
604 //--unused--
605 //--unused-- }
606
607 #define FUELCEN_SOUND_DELAY (f1_0/4)            //play every half second
608
609 //-------------------------------------------------------------
610 fix fuelcen_give_fuel(segment *segp, fix MaxAmountCanTake )
611 {
612         segment2 *seg2p = s2s2(segp);
613
614         static fix last_play_time=0;
615
616         Assert( segp != NULL );
617
618         PlayerSegment = segp;
619
620         if ( (segp) && (seg2p->special==SEGMENT_IS_FUELCEN) )   {
621                 fix amount;
622
623                 detect_escort_goal_accomplished(-4);    //      UGLY! Hack! -4 means went through fuelcen.
624
625 //              if (Station[segp->value].MaxCapacity<=0)        {
626 //                      HUD_init_message( "Fuelcenter %d is destroyed.", segp->value );
627 //                      return 0;
628 //              }
629
630 //              if (Station[segp->value].Capacity<=0)   {
631 //                      HUD_init_message( "Fuelcenter %d is empty.", segp->value );
632 //                      return 0;
633 //              }
634
635                 if (MaxAmountCanTake <= 0 )     {
636 //                      //gauge_message( "Fueled up!");
637                         return 0;
638                 }
639
640                 amount = fixmul(FrameTime,Fuelcen_give_amount);
641
642                 if (amount > MaxAmountCanTake )
643                         amount = MaxAmountCanTake;
644
645 //              if (!(Game_mode & GM_MULTI))
646 //                      if ( Station[segp->value].Capacity < amount  )  {
647 //                              amount = Station[segp->value].Capacity;
648 //                              Station[segp->value].Capacity = 0;
649 //                      } else {
650 //                              Station[segp->value].Capacity -= amount;
651 //                      }
652
653                 if (last_play_time > GameTime)
654                         last_play_time = 0;
655
656                 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
657
658                         digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
659 #ifdef NETWORK
660                         if (Game_mode & GM_MULTI)
661                                 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
662 #endif
663
664                         last_play_time = GameTime;
665                 }
666
667
668                 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
669                 return amount;
670
671         } else {
672                 return 0;
673         }
674 }
675
676 //-------------------------------------------------------------
677 // DM/050904
678 // Repair centers
679 // use same values as fuel centers
680 fix repaircen_give_shields(segment *segp, fix MaxAmountCanTake )
681 {
682         segment2 *seg2p = s2s2(segp);
683         static fix last_play_time=0;
684
685         Assert( segp != NULL );
686         PlayerSegment = segp;
687         if ( (segp) && (seg2p->special==SEGMENT_IS_REPAIRCEN) ) {
688                 fix amount;
689 //             detect_escort_goal_accomplished(-4);    //      UGLY! Hack! -4 means went through fuelcen.
690 //             if (Station[segp->value].MaxCapacity<=0)        {
691 //                     HUD_init_message( "Repaircenter %d is destroyed.", segp->value );
692 //                     return 0;
693 //             }
694 //             if (Station[segp->value].Capacity<=0)   {
695 //                     HUD_init_message( "Repaircenter %d is empty.", segp->value );
696 //                     return 0;
697 //             }
698                 if (MaxAmountCanTake <= 0 ) {
699                         //gauge_message( "Shields restored!");
700                         return 0;
701                 }
702                 amount = fixmul(FrameTime,Fuelcen_give_amount);
703                 if (amount > MaxAmountCanTake )
704                         amount = MaxAmountCanTake;
705 //        if (!(Game_mode & GM_MULTI))
706 //                     if ( Station[segp->value].Capacity < amount  )  {
707 //                             amount = Station[segp->value].Capacity;
708 //                             Station[segp->value].Capacity = 0;
709 //                     } else {
710 //                             Station[segp->value].Capacity -= amount;
711 //                     }
712                 if (last_play_time > GameTime)
713                         last_play_time = 0;
714                 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
715                         digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
716 #ifdef NETWORK
717                         if (Game_mode & GM_MULTI)
718                                 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
719 #endif
720                         last_play_time = GameTime;
721                 }
722 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
723                 return amount;
724         } else {
725                 return 0;
726         }
727 }
728
729 //--unused-- //-----------------------------------------------------------
730 //--unused-- // Damages a fuel center
731 //--unused-- void fuelcen_damage(segment *segp, fix damage )
732 //--unused-- {
733 //--unused--    //int i;
734 //--unused--    // int  station_num = segp->value;
735 //--unused--
736 //--unused--    Assert( segp != NULL );
737 //--unused--    if ( segp == NULL ) return;
738 //--unused--
739 //--unused--    mprintf((0, "Obsolete function fuelcen_damage() called with seg=%i, damage=%7.3f\n", SEGMENT_NUMBER(segp), f2fl(damage)));
740 //--unused--    switch( segp->special ) {
741 //--unused--    case SEGMENT_IS_NOTHING:
742 //--unused--            return;
743 //--unused--    case SEGMENT_IS_ROBOTMAKER:
744 //--unused-- //--               // Robotmaker hit by laser
745 //--unused-- //--               if (Station[station_num].MaxCapacity<=0 )       {
746 //--unused-- //--                       // Shooting a already destroyed materializer
747 //--unused-- //--               } else {
748 //--unused-- //--                       Station[station_num].MaxCapacity -= damage;
749 //--unused-- //--                       if (Station[station_num].Capacity > Station[station_num].MaxCapacity )  {
750 //--unused-- //--                               Station[station_num].Capacity = Station[station_num].MaxCapacity;
751 //--unused-- //--                       }
752 //--unused-- //--                       if (Station[station_num].MaxCapacity <= 0 )     {
753 //--unused-- //--                               Station[station_num].MaxCapacity = 0;
754 //--unused-- //--                               // Robotmaker dead
755 //--unused-- //--                               for (i=0; i<6; i++ )
756 //--unused-- //--                                       segp->sides[i].tmap_num2 = 0;
757 //--unused-- //--                       }
758 //--unused-- //--               }
759 //--unused-- //--               //mprintf( (0, "Materializatormografier has %x capacity left\n", Station[station_num].MaxCapacity ));
760 //--unused--            break;
761 //--unused--    case SEGMENT_IS_FUELCEN:        
762 //--unused-- //--               digi_play_sample( SOUND_REFUEL_STATION_HIT );
763 //--unused-- //--               if (Station[station_num].MaxCapacity>0 )        {
764 //--unused-- //--                       Station[station_num].MaxCapacity -= damage;
765 //--unused-- //--                       if (Station[station_num].Capacity > Station[station_num].MaxCapacity )  {
766 //--unused-- //--                               Station[station_num].Capacity = Station[station_num].MaxCapacity;
767 //--unused-- //--                       }
768 //--unused-- //--                       if (Station[station_num].MaxCapacity <= 0 )     {
769 //--unused-- //--                               Station[station_num].MaxCapacity = 0;
770 //--unused-- //--                               digi_play_sample( SOUND_REFUEL_STATION_DESTROYED );
771 //--unused-- //--                       }
772 //--unused-- //--               } else {
773 //--unused-- //--                       Station[station_num].MaxCapacity = 0;
774 //--unused-- //--               }
775 //--unused-- //--               HUD_init_message( "Fuelcenter %d damaged", station_num );
776 //--unused--            break;
777 //--unused--    case SEGMENT_IS_REPAIRCEN:
778 //--unused--            break;
779 //--unused--    case SEGMENT_IS_CONTROLCEN:
780 //--unused--            break;
781 //--unused--    default:
782 //--unused--            Error( "Invalid type in fuelcen.c" );
783 //--unused--    }
784 //--unused-- }
785
786 //--unused-- // ----------------------------------------------------------------------------------------------------------
787 //--unused-- fixang my_delta_ang(fixang a,fixang b)
788 //--unused-- {
789 //--unused--    fixang delta0,delta1;
790 //--unused--
791 //--unused--    return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1;
792 //--unused--
793 //--unused-- }
794
795 //--unused-- // ----------------------------------------------------------------------------------------------------------
796 //--unused-- //return though which side of seg0 is seg1
797 //--unused-- int john_find_connect_side(int seg0,int seg1)
798 //--unused-- {
799 //--unused--    segment *Seg=&Segments[seg0];
800 //--unused--    int i;
801 //--unused--
802 //--unused--    for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i;
803 //--unused--
804 //--unused--    return -1;
805 //--unused-- }
806
807 //      ----------------------------------------------------------------------------------------------------------
808 //--unused-- vms_angvec start_angles, delta_angles, goal_angles;
809 //--unused-- vms_vector start_pos, delta_pos, goal_pos;
810 //--unused-- int FuelStationSeg;
811 //--unused-- fix current_time,delta_time;
812 //--unused-- int next_side, side_index;
813 //--unused-- int * sidelist;
814
815 //--repair-- int Repairing;
816 //--repair-- vms_vector repair_save_uvec;               //the player's upvec when enter repaircen
817 //--repair-- object *RepairObj=NULL;            //which object getting repaired
818 //--repair-- int disable_repair_center=0;
819 //--repair-- fix repair_rate;
820 //--repair-- #define FULL_REPAIR_RATE i2f(10)
821
822 //--unused-- ubyte save_control_type,save_movement_type;
823
824 //--unused-- int SideOrderBack[] = {WFRONT, WRIGHT, WTOP, WLEFT, WBOTTOM, WBACK};
825 //--unused-- int SideOrderFront[] =  {WBACK, WLEFT, WTOP, WRIGHT, WBOTTOM, WFRONT};
826 //--unused-- int SideOrderLeft[] =  { WRIGHT, WBACK, WTOP, WFRONT, WBOTTOM, WLEFT };
827 //--unused-- int SideOrderRight[] =  { WLEFT, WFRONT, WTOP, WBACK, WBOTTOM, WRIGHT };
828 //--unused-- int SideOrderTop[] =  { WBOTTOM, WLEFT, WBACK, WRIGHT, WFRONT, WTOP };
829 //--unused-- int SideOrderBottom[] =  { WTOP, WLEFT, WFRONT, WRIGHT, WBACK, WBOTTOM };
830
831 //--unused-- int SideUpVector[] = {WBOTTOM, WFRONT, WBOTTOM, WFRONT, WBOTTOM, WBOTTOM };
832
833 //--repair-- // ----------------------------------------------------------------------------------------------------------
834 //--repair-- void refuel_calc_deltas(object *obj, int next_side, int repair_seg)
835 //--repair-- {
836 //--repair--    vms_vector nextcenter, headfvec, *headuvec;
837 //--repair--    vms_matrix goal_orient;
838 //--repair--
839 //--repair--    // Find time for this movement
840 //--repair--    delta_time = F1_0;              // one second...
841 //--repair--            
842 //--repair--    // Find start and goal position
843 //--repair--    start_pos = obj->pos;
844 //--repair--    
845 //--repair--    // Find delta position to get to goal position
846 //--repair--    compute_segment_center(&goal_pos,&Segments[repair_seg]);
847 //--repair--    vm_vec_sub( &delta_pos,&goal_pos,&start_pos);
848 //--repair--    
849 //--repair--    // Find start angles
850 //--repair--    //angles_from_vector(&start_angles,&obj->orient.fvec);
851 //--repair--    vm_extract_angles_matrix(&start_angles,&obj->orient);
852 //--repair--    
853 //--repair--    // Find delta angles to get to goal orientation
854 //--repair--    med_compute_center_point_on_side(&nextcenter,&Segments[repair_seg],next_side);
855 //--repair--    vm_vec_sub(&headfvec,&nextcenter,&goal_pos);
856 //--repair--    //mprintf( (0, "Next_side = %d, Head fvec = %d,%d,%d\n", next_side, headfvec.x, headfvec.y, headfvec.z ));
857 //--repair--
858 //--repair--    if (next_side == 5)                                             //last side
859 //--repair--            headuvec = &repair_save_uvec;
860 //--repair--    else
861 //--repair--            headuvec = &Segments[repair_seg].sides[SideUpVector[next_side]].normals[0];
862 //--repair--
863 //--repair--    vm_vector_2_matrix(&goal_orient,&headfvec,headuvec,NULL);
864 //--repair--    vm_extract_angles_matrix(&goal_angles,&goal_orient);
865 //--repair--    delta_angles.p = my_delta_ang(start_angles.p,goal_angles.p);
866 //--repair--    delta_angles.b = my_delta_ang(start_angles.b,goal_angles.b);
867 //--repair--    delta_angles.h = my_delta_ang(start_angles.h,goal_angles.h);
868 //--repair--    current_time = 0;
869 //--repair--    Repairing = 0;
870 //--repair-- }
871 //--repair--
872 //--repair-- // ----------------------------------------------------------------------------------------------------------
873 //--repair-- //if repairing, cut it short
874 //--repair-- abort_repair_center()
875 //--repair-- {
876 //--repair--    if (!RepairObj || side_index==5)
877 //--repair--            return;
878 //--repair--
879 //--repair--    current_time = 0;
880 //--repair--    side_index = 5;
881 //--repair--    next_side = sidelist[side_index];
882 //--repair--    refuel_calc_deltas(RepairObj, next_side, FuelStationSeg);
883 //--repair-- }
884 //--repair--
885 //--repair-- // ----------------------------------------------------------------------------------------------------------
886 //--repair-- void repair_ship_damage()
887 //--repair-- {
888 //--repair--    //mprintf((0,"Repairing ship damage\n"));
889 //--repair-- }
890 //--repair--
891 //--repair-- // ----------------------------------------------------------------------------------------------------------
892 //--repair-- int refuel_do_repair_effect( object * obj, int first_time, int repair_seg )        {
893 //--repair--
894 //--repair--    obj->mtype.phys_info.velocity.x = 0;                            
895 //--repair--    obj->mtype.phys_info.velocity.y = 0;                            
896 //--repair--    obj->mtype.phys_info.velocity.z = 0;                            
897 //--repair--
898 //--repair--    if (first_time) {
899 //--repair--            int entry_side;
900 //--repair--            current_time = 0;
901 //--repair--
902 //--repair--            digi_play_sample( SOUND_REPAIR_STATION_PLAYER_ENTERING, F1_0 );
903 //--repair--
904 //--repair--            entry_side = john_find_connect_side(repair_seg,obj->segnum );
905 //--repair--            Assert( entry_side > -1 );
906 //--repair--
907 //--repair--            switch( entry_side )    {
908 //--repair--            case WBACK: sidelist = SideOrderBack; break;
909 //--repair--            case WFRONT: sidelist = SideOrderFront; break;
910 //--repair--            case WLEFT: sidelist = SideOrderLeft; break;
911 //--repair--            case WRIGHT: sidelist = SideOrderRight; break;
912 //--repair--            case WTOP: sidelist = SideOrderTop; break;
913 //--repair--            case WBOTTOM: sidelist = SideOrderBottom; break;
914 //--repair--            }
915 //--repair--            side_index = 0;
916 //--repair--            next_side = sidelist[side_index];
917 //--repair--
918 //--repair--            refuel_calc_deltas(obj,next_side, repair_seg);
919 //--repair--    }
920 //--repair--
921 //--repair--    //update shields
922 //--repair--    if (Players[Player_num].shields < MAX_SHIELDS) {        //if above max, don't mess with it
923 //--repair--
924 //--repair--            Players[Player_num].shields += fixmul(FrameTime,repair_rate);
925 //--repair--
926 //--repair--            if (Players[Player_num].shields > MAX_SHIELDS)
927 //--repair--                    Players[Player_num].shields = MAX_SHIELDS;
928 //--repair--    }
929 //--repair--
930 //--repair--    current_time += FrameTime;
931 //--repair--
932 //--repair--    if (current_time >= delta_time )        {
933 //--repair--            vms_angvec av;
934 //--repair--            obj->pos = goal_pos;
935 //--repair--            av      = goal_angles;
936 //--repair--            vm_angles_2_matrix(&obj->orient,&av);
937 //--repair--
938 //--repair--            if (side_index >= 5 )   
939 //--repair--                    return 1;               // Done being repaired...
940 //--repair--
941 //--repair--            if (Repairing==0)               {
942 //--repair--                    //mprintf( (0, "<MACHINE EFFECT ON SIDE %d>\n", next_side ));
943 //--repair--                    //digi_play_sample( SOUND_REPAIR_STATION_FIXING );
944 //--repair--                    Repairing=1;
945 //--repair--
946 //--repair--                    switch( next_side )     {
947 //--repair--                    case 0: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
948 //--repair--                    case 1: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
949 //--repair--                    case 2: digi_play_sample( SOUND_REPAIR_STATION_FIXING_3,F1_0 ); break;
950 //--repair--                    case 3: digi_play_sample( SOUND_REPAIR_STATION_FIXING_4,F1_0 ); break;
951 //--repair--                    case 4: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
952 //--repair--                    case 5: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
953 //--repair--                    }
954 //--repair--            
955 //--repair--                    repair_ship_damage();
956 //--repair--
957 //--repair--            }
958 //--repair--
959 //--repair--            if (current_time >= (delta_time+(F1_0/2)) )     {
960 //--repair--                    current_time = 0;
961 //--repair--                    // Find next side...
962 //--repair--                    side_index++;
963 //--repair--                    if (side_index >= 6 ) return 1;
964 //--repair--                    next_side = sidelist[side_index];
965 //--repair--    
966 //--repair--                    refuel_calc_deltas(obj, next_side, repair_seg);
967 //--repair--            }
968 //--repair--
969 //--repair--    } else {
970 //--repair--            fix factor, p,b,h;      
971 //--repair--            vms_angvec av;
972 //--repair--
973 //--repair--            factor = fixdiv( current_time,delta_time );
974 //--repair--
975 //--repair--            // Find object's current position
976 //--repair--            obj->pos = delta_pos;
977 //--repair--            vm_vec_scale( &obj->pos, factor );
978 //--repair--            vm_vec_add2( &obj->pos, &start_pos );
979 //--repair--                    
980 //--repair--            // Find object's current orientation
981 //--repair--            p       = fixmul(delta_angles.p,factor);
982 //--repair--            b       = fixmul(delta_angles.b,factor);
983 //--repair--            h       = fixmul(delta_angles.h,factor);
984 //--repair--            av.p = (fixang)p + start_angles.p;
985 //--repair--            av.b = (fixang)b + start_angles.b;
986 //--repair--            av.h = (fixang)h + start_angles.h;
987 //--repair--            vm_angles_2_matrix(&obj->orient,&av);
988 //--repair--
989 //--repair--    }
990 //--repair--
991 //--repair--    update_object_seg(obj);         //update segment
992 //--repair--
993 //--repair--    return 0;
994 //--repair-- }
995 //--repair--
996 //--repair-- // ----------------------------------------------------------------------------------------------------------
997 //--repair-- //do the repair center for this frame
998 //--repair-- void do_repair_sequence(object *obj)
999 //--repair-- {
1000 //--repair--    Assert(obj == RepairObj);
1001 //--repair--
1002 //--repair--    if (refuel_do_repair_effect( obj, 0, FuelStationSeg )) {
1003 //--repair--            if (Players[Player_num].shields < MAX_SHIELDS)
1004 //--repair--                    Players[Player_num].shields = MAX_SHIELDS;
1005 //--repair--            obj->control_type = save_control_type;
1006 //--repair--            obj->movement_type = save_movement_type;
1007 //--repair--            disable_repair_center=1;
1008 //--repair--            RepairObj = NULL;
1009 //--repair--
1010 //--repair--
1011 //--repair--            //the two lines below will spit the player out of the rapair center,
1012 //--repair--            //but what happen is that the ship just bangs into the door
1013 //--repair--            //if (obj->movement_type == MT_PHYSICS)
1014 //--repair--            //      vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&obj->orient.fvec,i2f(200));
1015 //--repair--    }
1016 //--repair--
1017 //--repair-- }
1018 //--repair--
1019 //--repair-- // ----------------------------------------------------------------------------------------------------------
1020 //--repair-- //see if we should start the repair center
1021 //--repair-- void check_start_repair_center(object *obj)
1022 //--repair-- {
1023 //--repair--    if (RepairObj != NULL) return;          //already in repair center
1024 //--repair--
1025 //--repair--    if (Lsegments[obj->segnum].special_type & SS_REPAIR_CENTER) {
1026 //--repair--
1027 //--repair--            if (!disable_repair_center) {
1028 //--repair--                    //have just entered repair center
1029 //--repair--
1030 //--repair--                    RepairObj = obj;
1031 //--repair--                    repair_save_uvec = obj->orient.uvec;
1032 //--repair--
1033 //--repair--                    repair_rate = fixmuldiv(FULL_REPAIR_RATE,(MAX_SHIELDS - Players[Player_num].shields),MAX_SHIELDS);
1034 //--repair--
1035 //--repair--                    save_control_type = obj->control_type;
1036 //--repair--                    save_movement_type = obj->movement_type;
1037 //--repair--
1038 //--repair--                    obj->control_type = CT_REPAIRCEN;
1039 //--repair--                    obj->movement_type = MT_NONE;
1040 //--repair--
1041 //--repair--                    FuelStationSeg  = Lsegments[obj->segnum].special_segment;
1042 //--repair--                    Assert(FuelStationSeg != -1);
1043 //--repair--
1044 //--repair--                    if (refuel_do_repair_effect( obj, 1, FuelStationSeg )) {
1045 //--repair--                            Int3();         //can this happen?
1046 //--repair--                            obj->control_type = CT_FLYING;
1047 //--repair--                            obj->movement_type = MT_PHYSICS;
1048 //--repair--                    }
1049 //--repair--            }
1050 //--repair--    }
1051 //--repair--    else
1052 //--repair--            disable_repair_center=0;
1053 //--repair--
1054 //--repair-- }
1055
1056 //      --------------------------------------------------------------------------------------------
1057 void disable_matcens(void)
1058 {
1059         int     i;
1060
1061         for (i=0; i<Num_robot_centers; i++) {
1062                 Station[i].Enabled = 0;
1063                 Station[i].Disable_time = 0;
1064         }
1065 }
1066
1067 //      --------------------------------------------------------------------------------------------
1068 //      Initialize all materialization centers.
1069 //      Give them all the right number of lives.
1070 void init_all_matcens(void)
1071 {
1072         int     i;
1073
1074         for (i=0; i<Num_fuelcenters; i++)
1075                 if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
1076                         Station[i].Lives = 3;
1077                         Station[i].Enabled = 0;
1078                         Station[i].Disable_time = 0;
1079 #ifndef NDEBUG
1080 {
1081                         //      Make sure this fuelcen is pointed at by a matcen.
1082                         int     j;
1083                         for (j=0; j<Num_robot_centers; j++) {
1084                                 if (RobotCenters[j].fuelcen_num == i)
1085                                         break;
1086                         }
1087                         Assert(j != Num_robot_centers);
1088 }
1089 #endif
1090
1091                 }
1092
1093 #ifndef NDEBUG
1094         //      Make sure all matcens point at a fuelcen
1095         for (i=0; i<Num_robot_centers; i++) {
1096                 int     fuelcen_num = RobotCenters[i].fuelcen_num;
1097
1098                 Assert(fuelcen_num < Num_fuelcenters);
1099                 Assert(Station[fuelcen_num].Type == SEGMENT_IS_ROBOTMAKER);
1100         }
1101 #endif
1102
1103 }
1104
1105 #ifdef NETWORK
1106 extern void multi_send_capture_bonus (char);
1107
1108 void fuelcen_check_for_goal(segment *segp)
1109 {
1110         segment2 *seg2p = s2s2(segp);
1111
1112         Assert( segp != NULL );
1113         Assert (Game_mode & GM_CAPTURE);
1114
1115         if (seg2p->special==SEGMENT_IS_GOAL_BLUE )      {
1116
1117                         if ((get_team(Player_num)==TEAM_BLUE) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1118                          {
1119                                 mprintf ((0,"In goal segment BLUE\n"));
1120
1121                                 multi_send_capture_bonus (Player_num);
1122                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1123                                 maybe_drop_net_powerup (POW_FLAG_RED);
1124                          }
1125                  }
1126         if ( seg2p->special==SEGMENT_IS_GOAL_RED) {
1127
1128                         if ((get_team(Player_num)==TEAM_RED) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1129                          {              
1130                                 mprintf ((0,"In goal segment RED\n"));
1131                                 multi_send_capture_bonus (Player_num);
1132                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1133                                 maybe_drop_net_powerup (POW_FLAG_BLUE);
1134                          }
1135                  }
1136   }
1137
1138 void fuelcen_check_for_hoard_goal(segment *segp)
1139 {
1140         segment2 *seg2p = s2s2(segp);
1141
1142         Assert( segp != NULL );
1143         Assert (Game_mode & GM_HOARD);
1144
1145    if (Player_is_dead)
1146                 return;
1147
1148         if (seg2p->special==SEGMENT_IS_GOAL_BLUE || seg2p->special==SEGMENT_IS_GOAL_RED  )      
1149         {
1150                 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
1151                 {
1152                                 mprintf ((0,"In orb goal!\n"));
1153                                 multi_send_orb_bonus (Player_num);
1154                                 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1155                                 Players[Player_num].secondary_ammo[PROXIMITY_INDEX]=0;
1156       }
1157         }
1158
1159 }
1160
1161 #endif
1162
1163 #ifndef FAST_FILE_IO
1164 /*
1165  * reads an old_matcen_info structure from a CFILE
1166  */
1167 void old_matcen_info_read(old_matcen_info *mi, CFILE *fp)
1168 {
1169         mi->robot_flags = cfile_read_int(fp);
1170         mi->hit_points = cfile_read_fix(fp);
1171         mi->interval = cfile_read_fix(fp);
1172         mi->segnum = cfile_read_short(fp);
1173         mi->fuelcen_num = cfile_read_short(fp);
1174 }
1175
1176 /*
1177  * reads a matcen_info structure from a CFILE
1178  */
1179 void matcen_info_read(matcen_info *mi, CFILE *fp)
1180 {
1181         mi->robot_flags[0] = cfile_read_int(fp);
1182         mi->robot_flags[1] = cfile_read_int(fp);
1183         mi->hit_points = cfile_read_fix(fp);
1184         mi->interval = cfile_read_fix(fp);
1185         mi->segnum = cfile_read_short(fp);
1186         mi->fuelcen_num = cfile_read_short(fp);
1187 }
1188 #endif
1189
1190 void matcen_info_write(matcen_info *mi, short version, PHYSFS_file *fp)
1191 {
1192         PHYSFS_writeSLE32(fp, mi->robot_flags[0]);
1193         if (version >= 27)
1194                 PHYSFS_writeSLE32(fp, mi->robot_flags[1]);
1195         PHYSFSX_writeFix(fp, mi->hit_points);
1196         PHYSFSX_writeFix(fp, mi->interval);
1197         PHYSFS_writeSLE16(fp, mi->segnum);
1198         PHYSFS_writeSLE16(fp, mi->fuelcen_num);
1199 }