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