/* server/entities/powerups.qc powerup logic Copyright (C) 2021 NZ:P Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ .float zombie_drop_id; .float flashtime; .float flash_step; // the powerup's model string(float type) getPowerupModel = { switch(type) { case 1: return "models/pu/maxammo!.mdl"; break; case 2: return "models/pu/x2!.mdl"; break; case 3: return "models/pu/instakill!.mdl"; break; case 4: return "models/pu/nuke!.mdl"; break; case 5: return "models/pu/carpenter!.mdl"; break; case 6: return "models/pu/perkbottle!.mdl"; break; default: return ""; break; } } // the powerup's pick up voice clip string(float type) getPowerupVO = { switch(type) { case 1: return "sounds/pu/maxammo.wav"; break; case 2: return "sounds/pu/double_points.wav"; break; case 3: return "sounds/pu/insta_kill.wav"; break; case 4: return "sounds/pu/nuke.wav"; break; case 5: return "sounds/pu/carpenter.wav"; break; default: return ""; break; } } void() maxammo = { entity tempe, temp; tempe = find (world, classname, "player"); while (tempe) { if (!tempe.downed) { if (tempe.weapon) { tempe.currentammo = getWeaponAmmo(tempe.weapon); if (!tempe.currentmag) { temp = self; self = tempe; W_Reload(S_BOTH); self = temp; } } if (tempe.secondaryweapon) tempe.secondaryammo = getWeaponAmmo(tempe.secondaryweapon); tempe.primary_grenades = 4; if (tempe.grenades & 2) tempe.secondary_grenades = 2; } #ifdef PC ScrollText("MAX AMMO!", tempe); #endif #ifdef PSP nzp_maxammo(); #endif tempe = find (tempe, classname, "player"); } } void() nuke_finalize = { entity players; // give 'The F Bomb' #ifndef NX if (self.kills == 1) { GiveAchievement(4); } #endif // award points players = find(world,classname,"player"); while(players) { addmoney(players, 400*nuke_powerups_activated, 1); players = find(players,classname,"player"); } nuke_powerup_active = false; } void() do_nuke_kill = { // back up ourselves entity oldself; oldself = self; // switch to goaldummy, is goaldummy world? if (self.goaldummy == world) { nuke_finalize(); remove(self); return; } else { self = self.goaldummy; } // kill a target self.th_die(); // restore self self = oldself; // increment kills self.kills++; // find new target self.goaldummy = findfloat(self.goaldummy, iszomb, 1); self.nextthink = (rint((random() * 6) + 1)/10) + time; // random number from 0.1 to 0.7 } void() nuke = { // if there's already one active, just increment the point multiplier if (nuke_powerup_active == true) { nuke_powerups_activated++; return; } // mark nuke as being active, to prevent zombie damage and spawning. nuke_powerup_active = true; nuke_powerup_spawndelay = time + 3; nuke_powerups_activated = 1; // create our watcher entity entity nuke_watcher; nuke_watcher = spawn(); nuke_watcher.goaldummy = findfloat(world, iszomb, 1); nuke_watcher.think = do_nuke_kill; nuke_watcher.nextthink = (rint((random() * 6) + 1)/10) + time; // random number from 0.1 to 0.7 } void() carpenter = { local entity oldself; local entity who; oldself = self; who = find(world,classname,"window"); while(who != world) { if(who.health < 6 && who.health != -10)//-10 is for boardless windows { self = who; window_carpenter_1 (); who.health = 6; self = oldself; } who = find(who,classname,"window"); } who = find(world,classname,"player"); while(who) { addmoney(who, 200, 1); who = find(who,classname,"player"); } total_windows_down = 0; } void(entity who) give_perkdrop_logic = { // Return here if we already have all of the Perks if ((who.perks & P_REVIVE) && (who.perks & P_JUG) && (who.perks & P_SPEED) && (who.perks & P_DOUBLE) && (who.perks & P_FLOP) && (who.perks & P_STAMIN) && (who.perks & P_DEAD) && (who.perks & P_MULE)) { return; } local float perk; perk = 0; while(perk == 0) { local float num; num = rint((random() * 7)) + 1; switch(num) { case 1: if (!(who.perks & P_JUG)) { perk = 1; } break; case 2: if (!(who.perks & P_DOUBLE)) { perk = 2; } break; case 3: if (!(who.perks & P_SPEED)) { perk = 4; } break; case 4: if (!(who.perks & P_REVIVE)) { perk = 8; } break; case 5: if (!(who.perks & P_FLOP)) { perk = 16; } break; case 6: if (!(who.perks & P_STAMIN)) { perk = 32; } break; case 7: if (!(who.perks & P_DEAD)) { perk = 64; } break; case 8: if (!(who.perks & P_MULE)) { perk = 128; } break; default: break; } who.perks = who.perks | perk; } SetPerk(who, who.perks); } void() give_perk = { // Individual Power-Up if (self.style == 1) { give_perkdrop_logic(other); } // OUR Power-Up else { local entity who; who = find(world, classname, "player"); while(who) { give_perkdrop_logic(who); who = find(who, classname, "player"); } } } void() powerup_flash = { if(self.flash_step == 0) { self.flash_step = 1; self.flashtime = time + 3; self.nextthink = time + 0.6; } else if(self.flash_step == 1) { self.nextthink = time + 0.6; if(self.flashtime < time) { self.flash_step = 2; self.nextthink = time + 0.3; self.flashtime = time + 3; } } else if(self.flash_step == 2) { self.nextthink = time + 0.3; if(self.flashtime < time) { self.flash_step = 3; self.nextthink = time + 0.15; self.flashtime = time + 3; } } else if(self.flash_step == 3) { self.nextthink = time + 0.15; if(self.flashtime < time) { // moto - we used to setmodel blank here too, but it caused errors with the sprite. remove(self.owner); remove(self); return; } } if(self.model == "") { setmodel(self, getPowerupModel(self.zombie_drop_id)); } else { setmodel(self,""); } }; void() powerup_play_sound = { // play the VO clip if its not the perk bottle if (self.zombie_drop_id != 6) sound(self, CHAN_VOICE, self.powerup_vo, 1, ATTN_NONE); // finally, remove the (invisible/inactive) powerup. remove(self); } void() powerup_touch = { local float t; t = random(); if(other.classname == "player") { // pickup sound sound(self.owner,CHAN_VOICE,"sounds/pu/pickup.wav",1,ATTN_NONE); // add a slight delay before VO play self.think = powerup_play_sound; self.nextthink = time + 1; // hide powerup until we remove (after sound) setmodel(self, ""); self.effects = 0; self.touch = SUB_Null; remove(self.owner); // slight screen flash stuffcmd(other, "bf\n"); // powerup effects switch(self.zombie_drop_id) { // max ammo case 1: maxammo(); break; // double points case 2: x2_finished = time + 30; other.x2_icon = true; break; // insta kill case 3: instakill_finished = time + 30; other.insta_icon = true; break; // nuke case 4: nuke(); break; // carpenter case 5: carpenter(); break; // free perk case 6: give_perk(); break; // broken! default: centerprint(other, strcat("INVALID POWER-UP ID: ", ftos(self.zombie_drop_id))); break; } } }; void() sparkle_think = { local float f; f = self.frame; local float r; while(f == self.frame) { r = random(); r = ((r > 0.2) ? 1 : 0) + ((r > 0.4) ? 1 : 0) + ((r > 0.6) ? 1 : 0) + ((r > 0.8) ? 1 : 0); f = r; } self.frame = f; self.think = sparkle_think; self.nextthink = time + 0.1; if(self.calc_time <= time) { sound(self,CHAN_VOICE,"sounds/pu/powerup.wav",0.6,ATTN_NORM); self.calc_time = time + 2.998; } }; // // GetPowerupID() // Returns a powerup id, checks if the game allows for // one and if requirements for said powerup are met. // float() GetPowerupID = { float found; float carpenter_able; float perk_able; float id; id = carpenter_able = perk_able = 0; // Check if we can get a carpenter or a free perk drop if (total_windows_down >= 5) carpenter_able = true; if (rounds >= 15) perk_able = true; float total_powerups = 5; // nuke, insta, 2x, maxammo, carpenter, free perk // Start ID loop found = false; while(found == false) { float t = random(); // loop through all IDs for (float i = 0; i < total_powerups + 1; i++) { // check if the ID we got was viable if (t > (i/total_powerups)) { switch(i) { case 1: found = true; id = i; break; case 2: found = true; id = i; break; case 3: found = true; id = i; break; case 4: found = true; id = i; break; case 5: if (carpenter_able) { found = true; id = i; } break; case 6: /*if (perk_able) { found = true; id = i; }*/ break; default: break; } } } } return id; } float last_pu; void(vector where, float type) Spawn_Powerup = { entity new_powerup; float id; new_powerup = spawn(); new_powerup.origin = where; setorigin(new_powerup, new_powerup.origin); new_powerup.solid = SOLID_TRIGGER; new_powerup.classname = "item_powerup"; setsize (new_powerup, VEC_HULL_MIN, VEC_HULL_MAX); new_powerup.movetype = MOVETYPE_NONE; Light_Green(new_powerup); //=================== Sparkle Effects ===================== entity twlt_Sparkle; twlt_Sparkle = spawn(); new_powerup.owner = twlt_Sparkle; //just a reference so power up can delete the sparkle later on setorigin(twlt_Sparkle,where); #ifndef PC setmodel(twlt_Sparkle,"models/sprites/sprkle.spr"); #endif twlt_Sparkle.think = sparkle_think; twlt_Sparkle.nextthink = time + 0.1; sound(twlt_Sparkle,CHAN_VOICE,"sounds/pu/powerup.wav",0.6,ATTN_NORM); sound(new_powerup,CHAN_AUTO,"sounds/pu/drop.wav",1,ATTN_NONE); //======================================================== // Specific Power-Ups (for dogs) if (type) { setmodel(new_powerup, getPowerupModel(type)); new_powerup.zombie_drop_id = type; new_powerup.powerup_vo = getPowerupVO(type); } else { // Grab a powerup ID id = GetPowerupID(); // Should perk drops be individual? if (id == 6) { // Yes! if (random() > (1/2)) { // Set Style and make light Blue to symbolize it is an individual drop // TODO: Make a sprite too?? new_powerup.style = 1; Light_None(new_powerup); Light_Blue(new_powerup); } // No! else { // failsafe new_powerup.style = 0; } } // finally, assign the id and model to our id. setmodel(new_powerup, getPowerupModel(id)); new_powerup.zombie_drop_id = id; new_powerup.powerup_vo = getPowerupVO(id); } last_pu = new_powerup.zombie_drop_id; new_powerup.touch = powerup_touch; new_powerup.think = powerup_flash; new_powerup.nextthink = time + 21; totalpowerups++; }