1 /* $Id: powerup.c,v 1.8 2004-08-28 23:17:45 schaffner Exp $ */
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.
17 * Code for powerup objects.
63 #include "gr.h" // for powerup outline drawing
64 #include "editor/editor.h"
67 int N_powerup_types = 0;
68 powerup_type_info Powerup_info[MAX_POWERUP_TYPES];
70 //process this powerup for this frame
71 void do_powerup_frame(object *obj)
74 vclip_info *vci = &obj->rtype.vclip_info;
75 vclip *vc = &Vclip[vci->vclip_num];
77 fudge = (FrameTime * ((obj-Objects)&3)) >> 4;
79 vci->frametime -= FrameTime+fudge;
81 while (vci->frametime < 0 ) {
83 vci->frametime += vc->frame_time;
90 if (vci->framenum >= vc->num_frames)
93 if (vci->framenum < 0)
94 vci->framenum = vc->num_frames-1;
97 if (obj->lifeleft <= 0) {
98 object_create_explosion(obj->segnum, &obj->pos, F1_0*7/2, VCLIP_POWERUP_DISAPPEARANCE );
100 if ( Vclip[VCLIP_POWERUP_DISAPPEARANCE].sound_num > -1 )
101 digi_link_sound_to_object( Vclip[VCLIP_POWERUP_DISAPPEARANCE].sound_num, obj-Objects, 0, F1_0);
106 extern fix blob_vertices[];
108 // blob_vertices has 3 vertices in it, 4th must be computed
109 void draw_blob_outline(void)
113 v3x = blob_vertices[4] - blob_vertices[2] + blob_vertices[0];
114 v3y = blob_vertices[5] - blob_vertices[3] + blob_vertices[1];
116 gr_setcolor(BM_XRGB(63, 63, 63));
118 mprintf((0, "[%7.3f %7.3f] [%7.3f %7.3f] [%7.3f %7.3f]\n", f2fl(blob_vertices[0]), f2fl(blob_vertices[1]), f2fl(blob_vertices[2]), f2fl(blob_vertices[3]), f2fl(blob_vertices[4]), f2fl(blob_vertices[5]) ));
120 gr_line(blob_vertices[0], blob_vertices[1], blob_vertices[2], blob_vertices[3]);
121 gr_line(blob_vertices[2], blob_vertices[3], blob_vertices[4], blob_vertices[5]);
122 gr_line(blob_vertices[4], blob_vertices[5], v3x, v3y);
124 gr_line(v3x, v3y, blob_vertices[0], blob_vertices[1]);
128 void draw_powerup(object *obj)
131 blob_vertices[0] = 0x80000;
134 draw_object_blob(obj, Vclip[obj->rtype.vclip_info.vclip_num].frames[obj->rtype.vclip_info.framenum] );
137 if ((Function_mode == FMODE_EDITOR) && (Cur_object_index == obj-Objects))
138 if (blob_vertices[0] != 0x80000)
144 //void mprintf_powerup_info(void)
147 //mprintf((0, "Powerup: %s\n", text));
148 //for (i=0; i<5; i++) {
149 // char has_text[12];
151 // if (Players[Player_num].primary_weapon_flags & (1 << i))
152 // strcpy(has_text,"PRESENT");
154 // strcpy(has_text,"NOPE ");
157 // mprintf((0, "Weapon %i = %s, ammo = %6i, name = %s\n", i, has_text, Players[Player_num].primary_ammo[i], Primary_weapon_names[i]));
160 //for (i=0; i<5; i++) {
161 // char has_text[12];
163 // if (Players[Player_num].secondary_weapon_flags & (1 << i))
164 // strcpy(has_text,"PRESENT");
166 // strcpy(has_text,"NOPE ");
168 // mprintf((0, "Weapon %i = %s, ammo = %6i, name = %s\n", i, has_text, Players[Player_num].secondary_ammo[i], Secondary_weapon_names[i]));
172 void powerup_basic(int redadd, int greenadd, int blueadd, int score, char *format, ...)
177 va_start(args, format );
178 vsprintf(text, format, args);
181 PALETTE_FLASH_ADD(redadd,greenadd,blueadd);
183 HUD_init_message(text);
185 //mprintf_powerup_info();
187 add_points_to_score(score);
192 // Give the megawow powerup!
193 void do_megawow_powerup(int quantity)
197 powerup_basic(30, 0, 30, 1, "MEGA-WOWIE-ZOWIE!");
198 Players[Player_num].primary_weapon_flags = 0xffff ^ HAS_FLAG(SUPER_LASER_INDEX); //no super laser
199 Players[Player_num].secondary_weapon_flags = 0xffff;
201 for (i=0; i<MAX_PRIMARY_WEAPONS; i++)
202 Players[Player_num].primary_ammo[i] = VULCAN_AMMO_MAX;
205 Players[Player_num].secondary_ammo[i] = quantity;
207 for (i=3; i<MAX_SECONDARY_WEAPONS; i++)
208 Players[Player_num].secondary_ammo[i] = quantity/5;
210 if (Newdemo_state == ND_STATE_RECORDING)
211 newdemo_record_laser_level(Players[Player_num].laser_level, MAX_LASER_LEVEL);
213 Players[Player_num].energy = F1_0*200;
214 Players[Player_num].shields = F1_0*200;
215 Players[Player_num].flags |= PLAYER_FLAGS_QUAD_LASERS;
216 Players[Player_num].laser_level = MAX_SUPER_LASER_LEVEL;
218 if (Game_mode & GM_HOARD)
219 Players[Player_num].secondary_ammo[PROXIMITY_INDEX] = 12;
222 update_laser_weapon_info();
227 int pick_up_energy(void)
231 if (Players[Player_num].energy < MAX_ENERGY) {
233 boost = 3*F1_0 + 3*F1_0*(NDL - Difficulty_level);
234 if (Difficulty_level == 0)
236 Players[Player_num].energy += boost;
237 if (Players[Player_num].energy > MAX_ENERGY)
238 Players[Player_num].energy = MAX_ENERGY;
239 powerup_basic(15,15,7, ENERGY_SCORE, "%s %s %d",TXT_ENERGY,TXT_BOOSTED_TO,f2ir(Players[Player_num].energy));
242 HUD_init_message(TXT_MAXED_OUT,TXT_ENERGY);
247 int pick_up_vulcan_ammo(void)
251 int pwsave = Primary_weapon; // Ugh, save selected primary weapon around the picking up of the ammo. I apologize for this code. Matthew A. Toschlog
252 if (pick_up_ammo(CLASS_PRIMARY, VULCAN_INDEX, VULCAN_AMMO_AMOUNT)) {
253 powerup_basic(7, 14, 21, VULCAN_AMMO_SCORE, "%s!", TXT_VULCAN_AMMO);
256 max = Primary_ammo_max[VULCAN_INDEX];
257 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
259 HUD_init_message("%s %d %s!",TXT_ALREADY_HAVE,f2i((unsigned) VULCAN_AMMO_SCALE * (unsigned) max),TXT_VULCAN_ROUNDS);
262 Primary_weapon = pwsave;
267 extern void invalidate_escort_goal(void);
268 extern char GetKeyValue(char);
269 extern void check_to_use_primary(int);
270 extern void multi_send_got_flag (char);
272 int Headlight_active_default=1; //is headlight on when picked up?
273 extern int PlayerMessage;
275 // returns true if powerup consumed
276 int do_powerup(object *obj)
279 int special_used=0; //for when hitting vulcan cannon gets vulcan ammo
280 char temp_string[50];
283 if ((Player_is_dead) || (ConsoleObject->type == OBJ_GHOST) || (Players[Player_num].shields < 0))
286 if (obj->ctype.powerup_info.creation_time > GameTime) //gametime wrapped!
287 obj->ctype.powerup_info.creation_time = 0; //allow player to pick up
289 if ((obj->ctype.powerup_info.flags & PF_SPAT_BY_PLAYER) && obj->ctype.powerup_info.creation_time>0 && GameTime<obj->ctype.powerup_info.creation_time+i2f(2))
290 return 0; //not enough time elapsed
292 PlayerMessage=0; // Prevent messages from going to HUD if -PlayerMessages switch is set
296 Players[Player_num].lives++;
297 powerup_basic(15, 15, 15, 0, TXT_EXTRA_LIFE);
301 used = pick_up_energy();
303 case POW_SHIELD_BOOST:
304 if (Players[Player_num].shields < MAX_SHIELDS) {
305 fix boost = 3*F1_0 + 3*F1_0*(NDL - Difficulty_level);
306 if (Difficulty_level == 0)
308 Players[Player_num].shields += boost;
309 if (Players[Player_num].shields > MAX_SHIELDS)
310 Players[Player_num].shields = MAX_SHIELDS;
311 powerup_basic(0, 0, 15, SHIELD_SCORE, "%s %s %d",TXT_SHIELD,TXT_BOOSTED_TO,f2ir(Players[Player_num].shields));
314 HUD_init_message(TXT_MAXED_OUT,TXT_SHIELD);
317 if (Players[Player_num].laser_level >= MAX_LASER_LEVEL) {
318 //Players[Player_num].laser_level = MAX_LASER_LEVEL;
319 HUD_init_message(TXT_MAXED_OUT,TXT_LASER);
321 if (Newdemo_state == ND_STATE_RECORDING)
322 newdemo_record_laser_level(Players[Player_num].laser_level, Players[Player_num].laser_level + 1);
323 Players[Player_num].laser_level++;
324 powerup_basic(10, 0, 10, LASER_SCORE, "%s %s %d",TXT_LASER,TXT_BOOSTED_TO, Players[Player_num].laser_level+1);
325 update_laser_weapon_info();
326 pick_up_primary (LASER_INDEX);
329 if (!used && !(Game_mode & GM_MULTI) )
330 used = pick_up_energy();
333 used=pick_up_secondary(CONCUSSION_INDEX,1);
336 used=pick_up_secondary(CONCUSSION_INDEX,4);
340 if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY)
343 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
345 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
346 Players[Player_num].flags |= PLAYER_FLAGS_BLUE_KEY;
347 powerup_basic(0, 0, 15, KEY_SCORE, "%s %s",TXT_BLUE,TXT_ACCESS_GRANTED);
348 if (Game_mode & GM_MULTI)
352 invalidate_escort_goal();
355 if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY)
358 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
360 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
361 Players[Player_num].flags |= PLAYER_FLAGS_RED_KEY;
362 powerup_basic(15, 0, 0, KEY_SCORE, "%s %s",TXT_RED,TXT_ACCESS_GRANTED);
363 if (Game_mode & GM_MULTI)
367 invalidate_escort_goal();
370 if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY)
373 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
375 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
376 Players[Player_num].flags |= PLAYER_FLAGS_GOLD_KEY;
377 powerup_basic(15, 15, 7, KEY_SCORE, "%s %s",TXT_YELLOW,TXT_ACCESS_GRANTED);
378 if (Game_mode & GM_MULTI)
382 invalidate_escort_goal();
385 if (!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) {
386 Players[Player_num].flags |= PLAYER_FLAGS_QUAD_LASERS;
387 powerup_basic(15, 15, 7, QUAD_FIRE_SCORE, "%s!",TXT_QUAD_LASERS);
388 update_laser_weapon_info();
391 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,TXT_QUAD_LASERS);
392 if (!used && !(Game_mode & GM_MULTI) )
393 used = pick_up_energy();
396 case POW_VULCAN_WEAPON:
397 case POW_GAUSS_WEAPON: {
398 int ammo = obj->ctype.powerup_info.count;
400 used = pick_up_primary((obj->id==POW_VULCAN_WEAPON)?VULCAN_INDEX:GAUSS_INDEX);
402 //didn't get the weapon (because we already have it), but
403 //maybe snag some of the ammo. if single-player, grab all the ammo
404 //and remove the powerup. If multi-player take ammo in excess of
405 //the amount in a powerup, and leave the rest.
407 if ((Game_mode & GM_MULTI) )
408 ammo -= VULCAN_AMMO_AMOUNT; //don't let take all ammo
412 ammo_used = pick_up_ammo(CLASS_PRIMARY, VULCAN_INDEX, ammo);
413 obj->ctype.powerup_info.count -= ammo_used;
414 if (!used && ammo_used) {
415 powerup_basic(7, 14, 21, VULCAN_AMMO_SCORE, "%s!", TXT_VULCAN_AMMO);
417 id = POW_VULCAN_AMMO; //set new id for making sound at end of this function
418 if (obj->ctype.powerup_info.count == 0)
419 used = 1; //say used if all ammo taken
426 case POW_SPREADFIRE_WEAPON:
427 used = pick_up_primary(SPREADFIRE_INDEX);
428 if (!used && !(Game_mode & GM_MULTI) )
429 used = pick_up_energy();
431 case POW_PLASMA_WEAPON:
432 used = pick_up_primary(PLASMA_INDEX);
433 if (!used && !(Game_mode & GM_MULTI) )
434 used = pick_up_energy();
436 case POW_FUSION_WEAPON:
437 used = pick_up_primary(FUSION_INDEX);
438 if (!used && !(Game_mode & GM_MULTI) )
439 used = pick_up_energy();
442 case POW_HELIX_WEAPON:
443 used = pick_up_primary(HELIX_INDEX);
444 if (!used && !(Game_mode & GM_MULTI) )
445 used = pick_up_energy();
448 case POW_PHOENIX_WEAPON:
449 used = pick_up_primary(PHOENIX_INDEX);
450 if (!used && !(Game_mode & GM_MULTI) )
451 used = pick_up_energy();
454 case POW_OMEGA_WEAPON:
455 used = pick_up_primary(OMEGA_INDEX);
457 Omega_charge = obj->ctype.powerup_info.count;
458 if (!used && !(Game_mode & GM_MULTI) )
459 used = pick_up_energy();
462 case POW_PROXIMITY_WEAPON:
463 used=pick_up_secondary(PROXIMITY_INDEX,4);
465 case POW_SMARTBOMB_WEAPON:
466 used=pick_up_secondary(SMART_INDEX,1);
468 case POW_MEGA_WEAPON:
469 used=pick_up_secondary(MEGA_INDEX,1);
471 case POW_SMISSILE1_1:
472 used=pick_up_secondary(SMISSILE1_INDEX,1);
474 case POW_SMISSILE1_4:
475 used=pick_up_secondary(SMISSILE1_INDEX,4);
477 case POW_GUIDED_MISSILE_1:
478 used=pick_up_secondary(GUIDED_INDEX,1);
480 case POW_GUIDED_MISSILE_4:
481 used=pick_up_secondary(GUIDED_INDEX,4);
484 used=pick_up_secondary(SMART_MINE_INDEX,4);
486 case POW_MERCURY_MISSILE_1:
487 used=pick_up_secondary(SMISSILE4_INDEX,1);
489 case POW_MERCURY_MISSILE_4:
490 used=pick_up_secondary(SMISSILE4_INDEX,4);
492 case POW_EARTHSHAKER_MISSILE:
493 used=pick_up_secondary(SMISSILE5_INDEX,1);
495 case POW_VULCAN_AMMO:
496 used = pick_up_vulcan_ammo();
498 case POW_HOMING_AMMO_1:
499 used=pick_up_secondary(HOMING_INDEX,1);
501 case POW_HOMING_AMMO_4:
502 used=pick_up_secondary(HOMING_INDEX,4);
505 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
506 HUD_init_message("%s %s!",TXT_ALREADY_ARE,TXT_CLOAKED);
509 Players[Player_num].cloak_time = GameTime; // Not! changed by awareness events (like player fires laser).
510 Players[Player_num].flags |= PLAYER_FLAGS_CLOAKED;
513 if (Game_mode & GM_MULTI)
516 powerup_basic(-10,-10,-10, CLOAK_SCORE, "%s!",TXT_CLOAKING_DEVICE);
520 case POW_INVULNERABILITY:
521 if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) {
522 HUD_init_message("%s %s!",TXT_ALREADY_ARE,TXT_INVULNERABLE);
525 Players[Player_num].invulnerable_time = GameTime;
526 Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE;
527 powerup_basic(7, 14, 21, INVULNERABILITY_SCORE, "%s!",TXT_INVULNERABILITY);
533 do_megawow_powerup(50);
539 if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL) {
540 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,"the FULL MAP");
541 if (!(Game_mode & GM_MULTI) )
542 used = pick_up_energy();
544 Players[Player_num].flags |= PLAYER_FLAGS_MAP_ALL;
545 powerup_basic(15, 0, 15, 0, "FULL MAP!");
551 if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER) {
552 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,"the Converter");
553 if (!(Game_mode & GM_MULTI) )
554 used = pick_up_energy();
556 Players[Player_num].flags |= PLAYER_FLAGS_CONVERTER;
557 // DPH: anyone know what the hell this is supposed to do? it's always true =)
558 /* if ((GetKeyValue(54))<255)
560 sprintf (temp_string,"Energy->Shield converter! (Press %c to use)",key_to_ascii(GetKeyValue(54)));
561 powerup_basic(15, 0, 15, 0, temp_string);
564 powerup_basic(15, 0, 15, 0, "Energy -> shield converter!"); */
571 case POW_SUPER_LASER:
572 if (Players[Player_num].laser_level >= MAX_SUPER_LASER_LEVEL) {
573 Players[Player_num].laser_level = MAX_SUPER_LASER_LEVEL;
574 HUD_init_message("SUPER LASER MAXED OUT!");
576 int old_level=Players[Player_num].laser_level;
578 if (Players[Player_num].laser_level <= MAX_LASER_LEVEL)
579 Players[Player_num].laser_level = MAX_LASER_LEVEL;
580 Players[Player_num].laser_level++;
581 if (Newdemo_state == ND_STATE_RECORDING)
582 newdemo_record_laser_level(old_level, Players[Player_num].laser_level);
583 powerup_basic(10, 0, 10, LASER_SCORE, "Super Boost to Laser level %d",Players[Player_num].laser_level+1);
584 update_laser_weapon_info();
585 if (Primary_weapon!=LASER_INDEX)
586 check_to_use_primary (SUPER_LASER_INDEX);
589 if (!used && !(Game_mode & GM_MULTI) )
590 used = pick_up_energy();
594 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK) {
595 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,"the Ammo rack");
596 if (!(Game_mode & GM_MULTI) )
597 used = pick_up_energy();
600 Players[Player_num].flags |= PLAYER_FLAGS_AMMO_RACK;
602 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
604 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
605 powerup_basic(15, 0, 15, 0, "AMMO RACK!");
610 case POW_AFTERBURNER:
611 if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER) {
612 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,"the Afterburner");
613 if (!(Game_mode & GM_MULTI) )
614 used = pick_up_energy();
617 Players[Player_num].flags |= PLAYER_FLAGS_AFTERBURNER;
619 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
621 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
622 powerup_basic(15, 15, 15, 0, "AFTERBURNER!");
623 Afterburner_charge = f1_0;
629 if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) {
630 HUD_init_message("%s %s!",TXT_ALREADY_HAVE,"the Headlight boost");
631 if (!(Game_mode & GM_MULTI) )
632 used = pick_up_energy();
636 Players[Player_num].flags |= PLAYER_FLAGS_HEADLIGHT;
638 multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0);
640 digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 );
641 sprintf(msg,"HEADLIGHT BOOST! (Headlight is %s)",Headlight_active_default?"ON":"OFF");
642 powerup_basic(15, 0, 15, 0, msg );
643 if (Headlight_active_default)
644 Players[Player_num].flags |= PLAYER_FLAGS_HEADLIGHT_ON;
647 if (Game_mode & GM_MULTI)
648 multi_send_flags (Player_num);
655 if (Game_mode & GM_CAPTURE)
656 if (get_team(Player_num) == TEAM_RED) {
657 powerup_basic(15, 0, 15, 0, "BLUE FLAG!");
658 Players[Player_num].flags |= PLAYER_FLAGS_FLAG;
660 multi_send_got_flag (Player_num);
665 if (Game_mode & GM_HOARD)
666 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]<12) {
667 powerup_basic(15, 0, 15, 0, "Orb!!!");
668 Players[Player_num].secondary_ammo[PROXIMITY_INDEX]++;
669 Players[Player_num].flags |= PLAYER_FLAGS_FLAG;
671 multi_send_got_orb (Player_num);
676 if (Game_mode & GM_CAPTURE)
677 if (get_team(Player_num) == TEAM_BLUE) {
678 powerup_basic(15, 0, 15, 0, "RED FLAG!");
679 Players[Player_num].flags |= PLAYER_FLAGS_FLAG;
681 multi_send_got_flag (Player_num);
686 // case POW_HOARD_ORB:
693 //always say used, until physics problem (getting stuck on unused powerup)
694 //is solved. Note also the break statements above that are commented out
697 if ((used || special_used) && Powerup_info[id].hit_sound > -1 ) {
699 if (Game_mode & GM_MULTI) // Added by Rob, take this out if it turns out to be not good for net games!
700 multi_send_play_sound(Powerup_info[id].hit_sound, F1_0);
702 digi_play_sample( Powerup_info[id].hit_sound, F1_0 );
703 detect_escort_goal_accomplished(obj-Objects);
714 * reads n powerup_type_info structs from a CFILE
716 extern int powerup_type_info_read_n(powerup_type_info *pti, int n, CFILE *fp)
720 for (i = 0; i < n; i++) {
721 pti[i].vclip_num = cfile_read_int(fp);
722 pti[i].hit_sound = cfile_read_int(fp);
723 pti[i].size = cfile_read_fix(fp);
724 pti[i].light = cfile_read_fix(fp);