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.
16 * Functions for refueling centers.
31 #include "game.h" // For FrameTime
59 // The max number of fuel stations per mine.
61 fix Fuelcen_refill_speed = i2f(1);
62 fix Fuelcen_give_amount = i2f(25);
63 fix Fuelcen_max_amount = i2f(100);
65 // Every time a robot is created in the morphing code, it decreases capacity of the morpher
66 // by this amount... when capacity gets to 0, no more morphers...
67 fix EnergyToCreateOneRobot = i2f(1);
69 #define MATCEN_HP_DEFAULT F1_0*500; // Hitpoints
70 #define MATCEN_INTERVAL_DEFAULT F1_0*5; // 5 seconds
72 matcen_info RobotCenters[MAX_ROBOT_CENTERS];
73 int Num_robot_centers;
75 FuelCenter Station[MAX_NUM_FUELCENS];
76 int Num_fuelcenters = 0;
78 segment * PlayerSegment= NULL;
81 char Special_names[MAX_CENTER_TYPES][11] = {
92 //------------------------------------------------------------
93 // Resets all fuel center info
99 //mprintf( (0, "All fuel centers reset.\n"));
101 for(i=0; i<MAX_SEGMENTS; i++ )
102 Segment2s[i].special = SEGMENT_IS_NOTHING;
104 Num_robot_centers = 0;
108 #ifndef NDEBUG //this is sometimes called by people from the debugger
109 void reset_all_robot_centers()
113 // Remove all materialization centers
114 for (i=0; i<Num_segments; i++)
115 if (Segment2s[i].special == SEGMENT_IS_ROBOTMAKER) {
116 Segment2s[i].special = SEGMENT_IS_NOTHING;
117 Segment2s[i].matcen_num = -1;
122 //------------------------------------------------------------
123 // Turns a segment into a fully charged up fuel center...
124 void fuelcen_create( segment *segp)
126 segment2 *seg2p = s2s2(segp);
130 station_type = seg2p->special;
132 switch( station_type ) {
133 case SEGMENT_IS_NOTHING:
134 case SEGMENT_IS_GOAL_BLUE:
135 case SEGMENT_IS_GOAL_RED:
137 case SEGMENT_IS_FUELCEN:
138 case SEGMENT_IS_REPAIRCEN:
139 case SEGMENT_IS_CONTROLCEN:
140 case SEGMENT_IS_ROBOTMAKER:
143 Error( "Invalid station type %d in fuelcen.c\n", station_type );
146 Assert( (seg2p != NULL) );
147 if ( seg2p == NULL ) return;
149 Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
150 Assert( Num_fuelcenters > -1 );
152 seg2p->value = Num_fuelcenters;
153 Station[Num_fuelcenters].Type = station_type;
154 Station[Num_fuelcenters].MaxCapacity = Fuelcen_max_amount;
155 Station[Num_fuelcenters].Capacity = Station[Num_fuelcenters].MaxCapacity;
156 Station[Num_fuelcenters].segnum = SEGMENT_NUMBER(segp);
157 Station[Num_fuelcenters].Timer = -1;
158 Station[Num_fuelcenters].Flag = 0;
159 // Station[Num_fuelcenters].NextRobotType = -1;
160 // Station[Num_fuelcenters].last_created_obj=NULL;
161 // Station[Num_fuelcenters].last_created_sig = -1;
162 compute_segment_center(&Station[Num_fuelcenters].Center, segp);
164 // if (station_type == SEGMENT_IS_ROBOTMAKER)
165 // Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
167 //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
171 //------------------------------------------------------------
172 // Adds a matcen that already is a special type into the Station array.
173 // This function is separate from other fuelcens because we don't want values reset.
174 void matcen_create( segment *segp)
176 segment2 *seg2p = s2s2(segp);
178 int station_type = seg2p->special;
180 Assert( (seg2p != NULL) );
181 Assert(station_type == SEGMENT_IS_ROBOTMAKER);
182 if ( seg2p == NULL ) return;
184 Assert( Num_fuelcenters < MAX_NUM_FUELCENS );
185 Assert( Num_fuelcenters > -1 );
187 seg2p->value = Num_fuelcenters;
188 Station[Num_fuelcenters].Type = station_type;
189 Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3);
190 Station[Num_fuelcenters].MaxCapacity = Station[Num_fuelcenters].Capacity;
192 Station[Num_fuelcenters].segnum = SEGMENT_NUMBER(segp);
193 Station[Num_fuelcenters].Timer = -1;
194 Station[Num_fuelcenters].Flag = 0;
195 // Station[Num_fuelcenters].NextRobotType = -1;
196 // Station[Num_fuelcenters].last_created_obj=NULL;
197 // Station[Num_fuelcenters].last_created_sig = -1;
198 compute_segment_center( &Station[Num_fuelcenters].Center, segp );
200 seg2p->matcen_num = Num_robot_centers;
203 RobotCenters[seg2p->matcen_num].hit_points = MATCEN_HP_DEFAULT;
204 RobotCenters[seg2p->matcen_num].interval = MATCEN_INTERVAL_DEFAULT;
205 RobotCenters[seg2p->matcen_num].segnum = SEGMENT_NUMBER(segp);
206 RobotCenters[seg2p->matcen_num].fuelcen_num = Num_fuelcenters;
208 //mprintf( (0, "Segment %d is assigned to be fuel center %d.\n", Station[Num_fuelcenters].segnum, Num_fuelcenters ));
212 //------------------------------------------------------------
213 // Adds a segment that already is a special type into the Station array.
214 void fuelcen_activate( segment * segp, int station_type )
216 segment2 *seg2p = s2s2(segp);
218 seg2p->special = station_type;
220 if (seg2p->special == SEGMENT_IS_ROBOTMAKER)
221 matcen_create( segp);
223 fuelcen_create( segp);
227 // The lower this number is, the more quickly the center can be re-triggered.
228 // If it's too low, it can mean all the robots won't be put out, but for about 5
229 // robots, that's not real likely.
230 #define MATCEN_LIFE (i2f(30-2*Difficulty_level))
232 //------------------------------------------------------------
233 // Trigger (enable) the materialization center in segment segnum
234 void trigger_matcen(int segnum)
236 // -- segment *segp = &Segments[segnum];
237 segment2 *seg2p = &Segment2s[segnum];
238 vms_vector pos, delta;
239 FuelCenter *robotcen;
242 mprintf((0, "Trigger matcen, segment %i\n", segnum));
244 Assert(seg2p->special == SEGMENT_IS_ROBOTMAKER);
245 Assert(seg2p->matcen_num < Num_fuelcenters);
246 Assert((seg2p->matcen_num >= 0) && (seg2p->matcen_num <= Highest_segment_index));
248 robotcen = &Station[RobotCenters[seg2p->matcen_num].fuelcen_num];
250 if (robotcen->Enabled == 1)
253 if (!robotcen->Lives)
256 // MK: 11/18/95, At insane, matcens work forever!
257 if (Difficulty_level+1 < NDL)
260 robotcen->Timer = F1_0*1000; // Make sure the first robot gets emitted right away.
261 robotcen->Enabled = 1; // Say this center is enabled, it can create robots.
262 robotcen->Capacity = i2f(Difficulty_level + 3);
263 robotcen->Disable_time = MATCEN_LIFE;
265 // Create a bright object in the segment.
266 pos = robotcen->Center;
267 vm_vec_sub(&delta, &Vertices[Segments[segnum].verts[0]], &robotcen->Center);
268 vm_vec_scale_add2(&pos, &delta, F1_0/2);
269 objnum = obj_create( OBJ_LIGHT, 0, segnum, &pos, NULL, 0, CT_LIGHT, MT_NONE, RT_NONE );
271 Objects[objnum].lifeleft = MATCEN_LIFE;
272 Objects[objnum].ctype.light_info.intensity = i2f(8); // Light cast by a fuelcen.
274 mprintf((1, "Can't create invisible flare for matcen.\n"));
277 // 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)));
281 //------------------------------------------------------------
282 // Takes away a segment's fuel center properties.
283 // Deletes the segment point entry in the FuelCenter list.
284 void fuelcen_delete( segment * segp )
286 segment2 *seg2p = s2s2(segp);
293 for (i=0; i<Num_fuelcenters; i++ ) {
294 if ( Station[i].segnum == SEGMENT_NUMBER(segp) ) {
296 // If Robot maker is deleted, fix Segments and RobotCenters.
297 if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
299 Assert(Num_robot_centers >= 0);
301 for (j=seg2p->matcen_num; j<Num_robot_centers; j++)
302 RobotCenters[j] = RobotCenters[j+1];
304 for (j=0; j<Num_fuelcenters; j++) {
305 if ( Station[j].Type == SEGMENT_IS_ROBOTMAKER )
306 if ( Segment2s[Station[j].segnum].matcen_num > seg2p->matcen_num )
307 Segment2s[Station[j].segnum].matcen_num--;
311 //fix RobotCenters so they point to correct fuelcenter
312 for (j=0; j<Num_robot_centers; j++ )
313 if (RobotCenters[j].fuelcen_num > i) //this robotcenter's fuelcen is changing
314 RobotCenters[j].fuelcen_num--;
317 Assert(Num_fuelcenters >= 0);
318 for (j=i; j<Num_fuelcenters; j++ ) {
319 Station[j] = Station[j+1];
320 Segment2s[Station[j].segnum].value = j;
329 #define ROBOT_GEN_TIME (i2f(5))
331 object * create_morph_robot( segment *segp, vms_vector *object_pos, int object_id)
335 int default_behavior;
337 Players[Player_num].num_robots_level++;
338 Players[Player_num].num_robots_total++;
340 objnum = obj_create(OBJ_ROBOT, object_id, SEGMENT_NUMBER(segp), object_pos,
341 &vmd_identity_matrix, Polygon_models[Robot_info[object_id].model_num].rad,
342 CT_AI, MT_PHYSICS, RT_POLYOBJ);
345 mprintf((1, "Can't create morph robot. Aborting morph.\n"));
350 obj = &Objects[objnum];
352 //Set polygon-object-specific data
354 obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
355 obj->rtype.pobj_info.subobj_flags = 0;
359 obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
360 obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
362 obj->mtype.phys_info.flags |= (PF_LEVELLING);
364 obj->shields = Robot_info[obj->id].strength;
366 default_behavior = Robot_info[obj->id].behavior;
368 init_ai_object( OBJECT_NUMBER(obj), default_behavior, -1 ); // Note, -1 = segment this robot goes to to hide, should probably be something useful
370 create_n_segment_path(obj, 6, -1); // Create a 6 segment path from creation point.
372 Ai_local_info[objnum].mode = ai_behavior_to_mode(default_behavior);
377 int Num_extry_robots = 15;
380 int FrameCount_last_msg = 0;
383 // ----------------------------------------------------------------------------------------------------------
384 void robotmaker_proc( FuelCenter * robotcen )
387 vms_vector cur_object_loc; //, direction;
388 int matcen_num, segnum, objnum;
391 vms_vector direction;
393 if (robotcen->Enabled == 0)
396 if (robotcen->Disable_time > 0) {
397 robotcen->Disable_time -= FrameTime;
398 if (robotcen->Disable_time <= 0) {
399 mprintf((0, "Robot center #%i gets disabled due to time running out.\n", robotcen-Station));
400 robotcen->Enabled = 0;
404 // mprintf((0, "Capacity of robot maker #%i is %i\n", robotcen - Station, robotcen->Capacity));
406 // No robot making in multiplayer mode.
409 if ((Game_mode & GM_MULTI) && (!(Game_mode & GM_MULTI_ROBOTS) || !network_i_am_master()))
412 if (Game_mode & GM_MULTI)
417 // Wait until transmorgafier has capacity to make a robot...
418 if ( robotcen->Capacity <= 0 ) {
422 matcen_num = Segment2s[robotcen->segnum].matcen_num;
423 //mprintf((0, "Robotmaker #%i flags = %8x\n", matcen_num, RobotCenters[matcen_num].robot_flags));
425 if ( matcen_num == -1 ) {
426 mprintf((0, "Non-functional robotcen at %d\n", robotcen->segnum));
430 if (RobotCenters[matcen_num].robot_flags[0]==0 && RobotCenters[matcen_num].robot_flags[1]==0) {
431 //mprintf((0, "robot_flags = 0 at robot maker #%i\n", RobotCenters[matcen_num].robot_flags));
435 // Wait until we have a free slot for this puppy...
436 // <<<<<<<<<<<<<<<< Num robots in mine >>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<< Max robots in mine >>>>>>>>>>>>>>>
437 if ( (Players[Player_num].num_robots_level - Players[Player_num].num_kills_level) >= (Gamesave_num_org_robots + Num_extry_robots ) ) {
439 if (FrameCount > FrameCount_last_msg + 20) {
440 mprintf((0, "Cannot morph until you kill one!\n"));
441 FrameCount_last_msg = FrameCount;
447 robotcen->Timer += FrameTime;
449 switch( robotcen->Flag ) {
450 case 0: // Wait until next robot can generate
451 if (Game_mode & GM_MULTI)
453 top_time = ROBOT_GEN_TIME;
457 dist_to_player = vm_vec_dist_quick( &ConsoleObject->pos, &robotcen->Center );
458 top_time = dist_to_player/64 + d_rand() * 2 + F1_0*2;
459 if ( top_time > ROBOT_GEN_TIME )
460 top_time = ROBOT_GEN_TIME + d_rand();
461 if ( top_time < F1_0*2 )
462 top_time = F1_0*3/2 + d_rand()*2;
465 // mprintf( (0, "Time between morphs %d seconds, dist_to_player = %7.3f\n", f2i(top_time), f2fl(dist_to_player) ));
467 if (robotcen->Timer > top_time ) {
469 int i, my_station_num = robotcen-Station;
472 // Make sure this robotmaker hasn't put out its max without having any of them killed.
473 for (i=0; i<=Highest_object_index; i++)
474 if (Objects[i].type == OBJ_ROBOT)
475 if ((Objects[i].matcen_creator^0x80) == my_station_num)
477 if (count > Difficulty_level + 3) {
478 mprintf((0, "Cannot morph: center %i has already put out %i robots.\n", my_station_num, count));
479 robotcen->Timer /= 2;
483 // Whack on any robot or player in the matcen segment.
485 segnum = robotcen->segnum;
486 for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) {
488 if ( count > MAX_OBJECTS ) {
489 mprintf((0, "Object list in segment %d is circular.", segnum ));
493 if (Objects[objnum].type==OBJ_ROBOT) {
494 collide_robot_and_materialization_center(&Objects[objnum]);
495 robotcen->Timer = top_time/2;
497 } else if (Objects[objnum].type==OBJ_PLAYER ) {
498 collide_player_and_materialization_center(&Objects[objnum]);
499 robotcen->Timer = top_time/2;
504 compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
505 // HACK!!! The 10 under here should be something equal to the 1/2 the size of the segment.
506 obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT );
509 extract_orient_from_segment(&obj->orient,&Segments[robotcen->segnum]);
511 if ( Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1 ) {
512 digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 );
519 case 1: // Wait until 1/2 second after VCLIP started.
520 if (robotcen->Timer > (Vclip[VCLIP_MORPHING_ROBOT].play_time/2) ) {
522 robotcen->Capacity -= EnergyToCreateOneRobot;
526 compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]);
528 // If this is the first materialization, set to valid robot.
529 if (RobotCenters[matcen_num].robot_flags[0] != 0 || RobotCenters[matcen_num].robot_flags[1] != 0) {
532 sbyte legal_types[64]; // 64 bits, the width of robot_flags[].
533 int num_types, robot_index, i;
538 flags = RobotCenters[matcen_num].robot_flags[i];
541 legal_types[num_types++] = robot_index;
547 //mprintf((0, "Flags = %08x, %2i legal types to morph: \n", RobotCenters[matcen_num].robot_flags, num_types));
548 //for (i=0; i<num_types; i++)
549 // mprintf((0, "%2i ", legal_types[i]));
550 //mprintf((0, "\n"));
553 type = legal_types[0];
555 type = legal_types[(d_rand() * num_types) / 32768];
557 mprintf((0, "Morph: (type = %i) (seg = %i) (capacity = %08x)\n", type, robotcen->segnum, robotcen->Capacity));
558 obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type );
562 if (Game_mode & GM_MULTI)
563 multi_send_create_robot(robotcen-Station, OBJECT_NUMBER(obj), type);
566 obj->matcen_creator = (robotcen-Station) | 0x80;
568 // Make object faces player...
569 vm_vec_sub( &direction, &ConsoleObject->pos,&obj->pos );
570 vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL);
573 //robotcen->last_created_obj = obj;
574 //robotcen->last_created_sig = robotcen->last_created_obj->signature;
576 mprintf((0, "Warning: create_morph_robot returned NULL (no objects left?)\n"));
589 //-------------------------------------------------------------
590 // Called once per frame, replenishes fuel supply.
591 void fuelcen_update_all()
594 fix AmountToreplenish;
596 AmountToreplenish = fixmul(FrameTime,Fuelcen_refill_speed);
598 for (i=0; i<Num_fuelcenters; i++ ) {
599 if ( Station[i].Type == SEGMENT_IS_ROBOTMAKER ) {
600 if (! (Game_suspended & SUSP_ROBOTS))
601 robotmaker_proc( &Station[i] );
602 } else if ( Station[i].Type == SEGMENT_IS_CONTROLCEN ) {
603 //controlcen_proc( &Station[i] );
605 } else if ( (Station[i].MaxCapacity > 0) && (PlayerSegment!=&Segments[Station[i].segnum]) ) {
606 if ( Station[i].Capacity < Station[i].MaxCapacity ) {
607 Station[i].Capacity += AmountToreplenish;
608 //mprintf( (0, "Fuel center %d replenished to %d.\n", i, f2i(Station[i].Capacity) ));
609 if ( Station[i].Capacity >= Station[i].MaxCapacity ) {
610 Station[i].Capacity = Station[i].MaxCapacity;
611 //gauge_message( "Fuel center is fully recharged! " );
618 //--unused-- //-------------------------------------------------------------
619 //--unused-- // replenishes all fuel supplies.
620 //--unused-- void fuelcen_replenish_all()
624 //--unused-- for (i=0; i<Num_fuelcenters; i++ ) {
625 //--unused-- Station[i].Capacity = Station[i].MaxCapacity;
627 //--unused-- //mprintf( (0, "All fuel centers are replenished\n" ));
631 #define FUELCEN_SOUND_DELAY (f1_0/4) //play every half second
633 //-------------------------------------------------------------
634 fix fuelcen_give_fuel(segment *segp, fix MaxAmountCanTake )
636 segment2 *seg2p = s2s2(segp);
638 static fix last_play_time=0;
640 Assert( segp != NULL );
642 PlayerSegment = segp;
644 if ( (segp) && (seg2p->special==SEGMENT_IS_FUELCEN) ) {
647 detect_escort_goal_accomplished(-4); // UGLY! Hack! -4 means went through fuelcen.
649 // if (Station[segp->value].MaxCapacity<=0) {
650 // HUD_init_message( "Fuelcenter %d is destroyed.", segp->value );
654 // if (Station[segp->value].Capacity<=0) {
655 // HUD_init_message( "Fuelcenter %d is empty.", segp->value );
659 if (MaxAmountCanTake <= 0 ) {
660 // //gauge_message( "Fueled up!");
664 amount = fixmul(FrameTime,Fuelcen_give_amount);
666 if (amount > MaxAmountCanTake )
667 amount = MaxAmountCanTake;
669 // if (!(Game_mode & GM_MULTI))
670 // if ( Station[segp->value].Capacity < amount ) {
671 // amount = Station[segp->value].Capacity;
672 // Station[segp->value].Capacity = 0;
674 // Station[segp->value].Capacity -= amount;
677 if (last_play_time > GameTime)
680 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
682 digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
684 if (Game_mode & GM_MULTI)
685 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
688 last_play_time = GameTime;
692 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
700 //-------------------------------------------------------------
703 // use same values as fuel centers
704 fix repaircen_give_shields(segment *segp, fix MaxAmountCanTake )
706 segment2 *seg2p = s2s2(segp);
707 static fix last_play_time=0;
709 Assert( segp != NULL );
710 PlayerSegment = segp;
711 if ( (segp) && (seg2p->special==SEGMENT_IS_REPAIRCEN) ) {
713 // detect_escort_goal_accomplished(-4); // UGLY! Hack! -4 means went through fuelcen.
714 // if (Station[segp->value].MaxCapacity<=0) {
715 // HUD_init_message( "Repaircenter %d is destroyed.", segp->value );
718 // if (Station[segp->value].Capacity<=0) {
719 // HUD_init_message( "Repaircenter %d is empty.", segp->value );
722 if (MaxAmountCanTake <= 0 ) {
723 //gauge_message( "Shields restored!");
726 amount = fixmul(FrameTime,Fuelcen_give_amount);
727 if (amount > MaxAmountCanTake )
728 amount = MaxAmountCanTake;
729 // if (!(Game_mode & GM_MULTI))
730 // if ( Station[segp->value].Capacity < amount ) {
731 // amount = Station[segp->value].Capacity;
732 // Station[segp->value].Capacity = 0;
734 // Station[segp->value].Capacity -= amount;
736 if (last_play_time > GameTime)
738 if (GameTime > last_play_time+FUELCEN_SOUND_DELAY) {
739 digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 );
741 if (Game_mode & GM_MULTI)
742 multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2);
744 last_play_time = GameTime;
746 //HUD_init_message( "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) );
753 //--unused-- //-----------------------------------------------------------
754 //--unused-- // Damages a fuel center
755 //--unused-- void fuelcen_damage(segment *segp, fix damage )
757 //--unused-- //int i;
758 //--unused-- // int station_num = segp->value;
760 //--unused-- Assert( segp != NULL );
761 //--unused-- if ( segp == NULL ) return;
763 //--unused-- mprintf((0, "Obsolete function fuelcen_damage() called with seg=%i, damage=%7.3f\n", SEGMENT_NUMBER(segp), f2fl(damage)));
764 //--unused-- switch( segp->special ) {
765 //--unused-- case SEGMENT_IS_NOTHING:
767 //--unused-- case SEGMENT_IS_ROBOTMAKER:
768 //--unused-- //-- // Robotmaker hit by laser
769 //--unused-- //-- if (Station[station_num].MaxCapacity<=0 ) {
770 //--unused-- //-- // Shooting a already destroyed materializer
771 //--unused-- //-- } else {
772 //--unused-- //-- Station[station_num].MaxCapacity -= damage;
773 //--unused-- //-- if (Station[station_num].Capacity > Station[station_num].MaxCapacity ) {
774 //--unused-- //-- Station[station_num].Capacity = Station[station_num].MaxCapacity;
776 //--unused-- //-- if (Station[station_num].MaxCapacity <= 0 ) {
777 //--unused-- //-- Station[station_num].MaxCapacity = 0;
778 //--unused-- //-- // Robotmaker dead
779 //--unused-- //-- for (i=0; i<6; i++ )
780 //--unused-- //-- segp->sides[i].tmap_num2 = 0;
783 //--unused-- //-- //mprintf( (0, "Materializatormografier has %x capacity left\n", Station[station_num].MaxCapacity ));
785 //--unused-- case SEGMENT_IS_FUELCEN:
786 //--unused-- //-- digi_play_sample( SOUND_REFUEL_STATION_HIT );
787 //--unused-- //-- if (Station[station_num].MaxCapacity>0 ) {
788 //--unused-- //-- Station[station_num].MaxCapacity -= damage;
789 //--unused-- //-- if (Station[station_num].Capacity > Station[station_num].MaxCapacity ) {
790 //--unused-- //-- Station[station_num].Capacity = Station[station_num].MaxCapacity;
792 //--unused-- //-- if (Station[station_num].MaxCapacity <= 0 ) {
793 //--unused-- //-- Station[station_num].MaxCapacity = 0;
794 //--unused-- //-- digi_play_sample( SOUND_REFUEL_STATION_DESTROYED );
796 //--unused-- //-- } else {
797 //--unused-- //-- Station[station_num].MaxCapacity = 0;
799 //--unused-- //-- HUD_init_message( "Fuelcenter %d damaged", station_num );
801 //--unused-- case SEGMENT_IS_REPAIRCEN:
803 //--unused-- case SEGMENT_IS_CONTROLCEN:
805 //--unused-- default:
806 //--unused-- Error( "Invalid type in fuelcen.c" );
810 //--unused-- // ----------------------------------------------------------------------------------------------------------
811 //--unused-- fixang my_delta_ang(fixang a,fixang b)
813 //--unused-- fixang delta0,delta1;
815 //--unused-- return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1;
819 //--unused-- // ----------------------------------------------------------------------------------------------------------
820 //--unused-- //return though which side of seg0 is seg1
821 //--unused-- int john_find_connect_side(int seg0,int seg1)
823 //--unused-- segment *Seg=&Segments[seg0];
826 //--unused-- for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i;
828 //--unused-- return -1;
831 // ----------------------------------------------------------------------------------------------------------
832 //--unused-- vms_angvec start_angles, delta_angles, goal_angles;
833 //--unused-- vms_vector start_pos, delta_pos, goal_pos;
834 //--unused-- int FuelStationSeg;
835 //--unused-- fix current_time,delta_time;
836 //--unused-- int next_side, side_index;
837 //--unused-- int * sidelist;
839 //--repair-- int Repairing;
840 //--repair-- vms_vector repair_save_uvec; //the player's upvec when enter repaircen
841 //--repair-- object *RepairObj=NULL; //which object getting repaired
842 //--repair-- int disable_repair_center=0;
843 //--repair-- fix repair_rate;
844 //--repair-- #define FULL_REPAIR_RATE i2f(10)
846 //--unused-- ubyte save_control_type,save_movement_type;
848 //--unused-- int SideOrderBack[] = {WFRONT, WRIGHT, WTOP, WLEFT, WBOTTOM, WBACK};
849 //--unused-- int SideOrderFront[] = {WBACK, WLEFT, WTOP, WRIGHT, WBOTTOM, WFRONT};
850 //--unused-- int SideOrderLeft[] = { WRIGHT, WBACK, WTOP, WFRONT, WBOTTOM, WLEFT };
851 //--unused-- int SideOrderRight[] = { WLEFT, WFRONT, WTOP, WBACK, WBOTTOM, WRIGHT };
852 //--unused-- int SideOrderTop[] = { WBOTTOM, WLEFT, WBACK, WRIGHT, WFRONT, WTOP };
853 //--unused-- int SideOrderBottom[] = { WTOP, WLEFT, WFRONT, WRIGHT, WBACK, WBOTTOM };
855 //--unused-- int SideUpVector[] = {WBOTTOM, WFRONT, WBOTTOM, WFRONT, WBOTTOM, WBOTTOM };
857 //--repair-- // ----------------------------------------------------------------------------------------------------------
858 //--repair-- void refuel_calc_deltas(object *obj, int next_side, int repair_seg)
860 //--repair-- vms_vector nextcenter, headfvec, *headuvec;
861 //--repair-- vms_matrix goal_orient;
863 //--repair-- // Find time for this movement
864 //--repair-- delta_time = F1_0; // one second...
866 //--repair-- // Find start and goal position
867 //--repair-- start_pos = obj->pos;
869 //--repair-- // Find delta position to get to goal position
870 //--repair-- compute_segment_center(&goal_pos,&Segments[repair_seg]);
871 //--repair-- vm_vec_sub( &delta_pos,&goal_pos,&start_pos);
873 //--repair-- // Find start angles
874 //--repair-- //angles_from_vector(&start_angles,&obj->orient.fvec);
875 //--repair-- vm_extract_angles_matrix(&start_angles,&obj->orient);
877 //--repair-- // Find delta angles to get to goal orientation
878 //--repair-- med_compute_center_point_on_side(&nextcenter,&Segments[repair_seg],next_side);
879 //--repair-- vm_vec_sub(&headfvec,&nextcenter,&goal_pos);
880 //--repair-- //mprintf( (0, "Next_side = %d, Head fvec = %d,%d,%d\n", next_side, headfvec.x, headfvec.y, headfvec.z ));
882 //--repair-- if (next_side == 5) //last side
883 //--repair-- headuvec = &repair_save_uvec;
885 //--repair-- headuvec = &Segments[repair_seg].sides[SideUpVector[next_side]].normals[0];
887 //--repair-- vm_vector_2_matrix(&goal_orient,&headfvec,headuvec,NULL);
888 //--repair-- vm_extract_angles_matrix(&goal_angles,&goal_orient);
889 //--repair-- delta_angles.p = my_delta_ang(start_angles.p,goal_angles.p);
890 //--repair-- delta_angles.b = my_delta_ang(start_angles.b,goal_angles.b);
891 //--repair-- delta_angles.h = my_delta_ang(start_angles.h,goal_angles.h);
892 //--repair-- current_time = 0;
893 //--repair-- Repairing = 0;
896 //--repair-- // ----------------------------------------------------------------------------------------------------------
897 //--repair-- //if repairing, cut it short
898 //--repair-- abort_repair_center()
900 //--repair-- if (!RepairObj || side_index==5)
903 //--repair-- current_time = 0;
904 //--repair-- side_index = 5;
905 //--repair-- next_side = sidelist[side_index];
906 //--repair-- refuel_calc_deltas(RepairObj, next_side, FuelStationSeg);
909 //--repair-- // ----------------------------------------------------------------------------------------------------------
910 //--repair-- void repair_ship_damage()
912 //--repair-- //mprintf((0,"Repairing ship damage\n"));
915 //--repair-- // ----------------------------------------------------------------------------------------------------------
916 //--repair-- int refuel_do_repair_effect( object * obj, int first_time, int repair_seg ) {
918 //--repair-- obj->mtype.phys_info.velocity.x = 0;
919 //--repair-- obj->mtype.phys_info.velocity.y = 0;
920 //--repair-- obj->mtype.phys_info.velocity.z = 0;
922 //--repair-- if (first_time) {
923 //--repair-- int entry_side;
924 //--repair-- current_time = 0;
926 //--repair-- digi_play_sample( SOUND_REPAIR_STATION_PLAYER_ENTERING, F1_0 );
928 //--repair-- entry_side = john_find_connect_side(repair_seg,obj->segnum );
929 //--repair-- Assert( entry_side > -1 );
931 //--repair-- switch( entry_side ) {
932 //--repair-- case WBACK: sidelist = SideOrderBack; break;
933 //--repair-- case WFRONT: sidelist = SideOrderFront; break;
934 //--repair-- case WLEFT: sidelist = SideOrderLeft; break;
935 //--repair-- case WRIGHT: sidelist = SideOrderRight; break;
936 //--repair-- case WTOP: sidelist = SideOrderTop; break;
937 //--repair-- case WBOTTOM: sidelist = SideOrderBottom; break;
939 //--repair-- side_index = 0;
940 //--repair-- next_side = sidelist[side_index];
942 //--repair-- refuel_calc_deltas(obj,next_side, repair_seg);
945 //--repair-- //update shields
946 //--repair-- if (Players[Player_num].shields < MAX_SHIELDS) { //if above max, don't mess with it
948 //--repair-- Players[Player_num].shields += fixmul(FrameTime,repair_rate);
950 //--repair-- if (Players[Player_num].shields > MAX_SHIELDS)
951 //--repair-- Players[Player_num].shields = MAX_SHIELDS;
954 //--repair-- current_time += FrameTime;
956 //--repair-- if (current_time >= delta_time ) {
957 //--repair-- vms_angvec av;
958 //--repair-- obj->pos = goal_pos;
959 //--repair-- av = goal_angles;
960 //--repair-- vm_angles_2_matrix(&obj->orient,&av);
962 //--repair-- if (side_index >= 5 )
963 //--repair-- return 1; // Done being repaired...
965 //--repair-- if (Repairing==0) {
966 //--repair-- //mprintf( (0, "<MACHINE EFFECT ON SIDE %d>\n", next_side ));
967 //--repair-- //digi_play_sample( SOUND_REPAIR_STATION_FIXING );
968 //--repair-- Repairing=1;
970 //--repair-- switch( next_side ) {
971 //--repair-- case 0: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
972 //--repair-- case 1: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
973 //--repair-- case 2: digi_play_sample( SOUND_REPAIR_STATION_FIXING_3,F1_0 ); break;
974 //--repair-- case 3: digi_play_sample( SOUND_REPAIR_STATION_FIXING_4,F1_0 ); break;
975 //--repair-- case 4: digi_play_sample( SOUND_REPAIR_STATION_FIXING_1,F1_0 ); break;
976 //--repair-- case 5: digi_play_sample( SOUND_REPAIR_STATION_FIXING_2,F1_0 ); break;
979 //--repair-- repair_ship_damage();
983 //--repair-- if (current_time >= (delta_time+(F1_0/2)) ) {
984 //--repair-- current_time = 0;
985 //--repair-- // Find next side...
986 //--repair-- side_index++;
987 //--repair-- if (side_index >= 6 ) return 1;
988 //--repair-- next_side = sidelist[side_index];
990 //--repair-- refuel_calc_deltas(obj, next_side, repair_seg);
993 //--repair-- } else {
994 //--repair-- fix factor, p,b,h;
995 //--repair-- vms_angvec av;
997 //--repair-- factor = fixdiv( current_time,delta_time );
999 //--repair-- // Find object's current position
1000 //--repair-- obj->pos = delta_pos;
1001 //--repair-- vm_vec_scale( &obj->pos, factor );
1002 //--repair-- vm_vec_add2( &obj->pos, &start_pos );
1004 //--repair-- // Find object's current orientation
1005 //--repair-- p = fixmul(delta_angles.p,factor);
1006 //--repair-- b = fixmul(delta_angles.b,factor);
1007 //--repair-- h = fixmul(delta_angles.h,factor);
1008 //--repair-- av.p = (fixang)p + start_angles.p;
1009 //--repair-- av.b = (fixang)b + start_angles.b;
1010 //--repair-- av.h = (fixang)h + start_angles.h;
1011 //--repair-- vm_angles_2_matrix(&obj->orient,&av);
1015 //--repair-- update_object_seg(obj); //update segment
1017 //--repair-- return 0;
1020 //--repair-- // ----------------------------------------------------------------------------------------------------------
1021 //--repair-- //do the repair center for this frame
1022 //--repair-- void do_repair_sequence(object *obj)
1024 //--repair-- Assert(obj == RepairObj);
1026 //--repair-- if (refuel_do_repair_effect( obj, 0, FuelStationSeg )) {
1027 //--repair-- if (Players[Player_num].shields < MAX_SHIELDS)
1028 //--repair-- Players[Player_num].shields = MAX_SHIELDS;
1029 //--repair-- obj->control_type = save_control_type;
1030 //--repair-- obj->movement_type = save_movement_type;
1031 //--repair-- disable_repair_center=1;
1032 //--repair-- RepairObj = NULL;
1035 //--repair-- //the two lines below will spit the player out of the rapair center,
1036 //--repair-- //but what happen is that the ship just bangs into the door
1037 //--repair-- //if (obj->movement_type == MT_PHYSICS)
1038 //--repair-- // vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&obj->orient.fvec,i2f(200));
1043 //--repair-- // ----------------------------------------------------------------------------------------------------------
1044 //--repair-- //see if we should start the repair center
1045 //--repair-- void check_start_repair_center(object *obj)
1047 //--repair-- if (RepairObj != NULL) return; //already in repair center
1049 //--repair-- if (Lsegments[obj->segnum].special_type & SS_REPAIR_CENTER) {
1051 //--repair-- if (!disable_repair_center) {
1052 //--repair-- //have just entered repair center
1054 //--repair-- RepairObj = obj;
1055 //--repair-- repair_save_uvec = obj->orient.uvec;
1057 //--repair-- repair_rate = fixmuldiv(FULL_REPAIR_RATE,(MAX_SHIELDS - Players[Player_num].shields),MAX_SHIELDS);
1059 //--repair-- save_control_type = obj->control_type;
1060 //--repair-- save_movement_type = obj->movement_type;
1062 //--repair-- obj->control_type = CT_REPAIRCEN;
1063 //--repair-- obj->movement_type = MT_NONE;
1065 //--repair-- FuelStationSeg = Lsegments[obj->segnum].special_segment;
1066 //--repair-- Assert(FuelStationSeg != -1);
1068 //--repair-- if (refuel_do_repair_effect( obj, 1, FuelStationSeg )) {
1069 //--repair-- Int3(); //can this happen?
1070 //--repair-- obj->control_type = CT_FLYING;
1071 //--repair-- obj->movement_type = MT_PHYSICS;
1076 //--repair-- disable_repair_center=0;
1080 // --------------------------------------------------------------------------------------------
1081 void disable_matcens(void)
1085 for (i=0; i<Num_robot_centers; i++) {
1086 Station[i].Enabled = 0;
1087 Station[i].Disable_time = 0;
1091 // --------------------------------------------------------------------------------------------
1092 // Initialize all materialization centers.
1093 // Give them all the right number of lives.
1094 void init_all_matcens(void)
1098 for (i=0; i<Num_fuelcenters; i++)
1099 if (Station[i].Type == SEGMENT_IS_ROBOTMAKER) {
1100 Station[i].Lives = 3;
1101 Station[i].Enabled = 0;
1102 Station[i].Disable_time = 0;
1105 // Make sure this fuelcen is pointed at by a matcen.
1107 for (j=0; j<Num_robot_centers; j++) {
1108 if (RobotCenters[j].fuelcen_num == i)
1111 Assert(j != Num_robot_centers);
1118 // Make sure all matcens point at a fuelcen
1119 for (i=0; i<Num_robot_centers; i++) {
1120 int fuelcen_num = RobotCenters[i].fuelcen_num;
1122 Assert(fuelcen_num < Num_fuelcenters);
1123 Assert(Station[fuelcen_num].Type == SEGMENT_IS_ROBOTMAKER);
1130 extern void multi_send_capture_bonus (char);
1132 void fuelcen_check_for_goal(segment *segp)
1134 segment2 *seg2p = s2s2(segp);
1136 Assert( segp != NULL );
1137 Assert (Game_mode & GM_CAPTURE);
1139 if (seg2p->special==SEGMENT_IS_GOAL_BLUE ) {
1141 if ((get_team(Player_num)==TEAM_BLUE) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1143 mprintf ((0,"In goal segment BLUE\n"));
1145 multi_send_capture_bonus (Player_num);
1146 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1147 maybe_drop_net_powerup (POW_FLAG_RED);
1150 if ( seg2p->special==SEGMENT_IS_GOAL_RED) {
1152 if ((get_team(Player_num)==TEAM_RED) && (Players[Player_num].flags & PLAYER_FLAGS_FLAG))
1154 mprintf ((0,"In goal segment RED\n"));
1155 multi_send_capture_bonus (Player_num);
1156 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1157 maybe_drop_net_powerup (POW_FLAG_BLUE);
1162 void fuelcen_check_for_hoard_goal(segment *segp)
1164 segment2 *seg2p = s2s2(segp);
1166 Assert( segp != NULL );
1167 Assert (Game_mode & GM_HOARD);
1172 if (seg2p->special==SEGMENT_IS_GOAL_BLUE || seg2p->special==SEGMENT_IS_GOAL_RED )
1174 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
1176 mprintf ((0,"In orb goal!\n"));
1177 multi_send_orb_bonus (Player_num);
1178 Players[Player_num].flags &=(~(PLAYER_FLAGS_FLAG));
1179 Players[Player_num].secondary_ammo[PROXIMITY_INDEX]=0;
1187 #ifndef FAST_FILE_IO
1189 * reads an old_matcen_info structure from a CFILE
1191 void old_matcen_info_read(old_matcen_info *mi, CFILE *fp)
1193 mi->robot_flags = cfile_read_int(fp);
1194 mi->hit_points = cfile_read_fix(fp);
1195 mi->interval = cfile_read_fix(fp);
1196 mi->segnum = cfile_read_short(fp);
1197 mi->fuelcen_num = cfile_read_short(fp);
1201 * reads a matcen_info structure from a CFILE
1203 void matcen_info_read(matcen_info *mi, CFILE *fp)
1205 mi->robot_flags[0] = cfile_read_int(fp);
1206 mi->robot_flags[1] = cfile_read_int(fp);
1207 mi->hit_points = cfile_read_fix(fp);
1208 mi->interval = cfile_read_fix(fp);
1209 mi->segnum = cfile_read_short(fp);
1210 mi->fuelcen_num = cfile_read_short(fp);
1214 void matcen_info_write(matcen_info *mi, short version, PHYSFS_file *fp)
1216 PHYSFS_writeSLE32(fp, mi->robot_flags[0]);
1218 PHYSFS_writeSLE32(fp, mi->robot_flags[1]);
1219 PHYSFSX_writeFix(fp, mi->hit_points);
1220 PHYSFSX_writeFix(fp, mi->interval);
1221 PHYSFS_writeSLE16(fp, mi->segnum);
1222 PHYSFS_writeSLE16(fp, mi->fuelcen_num);