/*====================================================== ENGINEER.QC Custom TeamFortress v3.1 (c) TeamFortress Software Pty Ltd 2/3/97 (c) William Kerney 4/14/00 (c) Craig Hauser 4/14/00 ======================================================== Weapons and functions for the ENGINEER class and associated weaponry =======================================================*/ #include "defs.qh" #include "menu.qh" float modelindex_tesla; //CH // Weapon Functions void() LaserBolt_Touch; void() LaserBolt_Think; void() W_FireLaser; // EMP Grenade Functions void() EMPExplode; void() EMPGrenadeTouch; void() EMPGrenadeExplode; // Building Functions void() TeamFortress_EngineerBuild; void(float objtobuild) TeamFortress_Build; void() TeamFortress_FinishedBuilding; void() T_Dispenser; void() Dispenser_Die; void(entity disp) Engineer_UseDispenser; void(entity gun) Engineer_UseSentryGun; void(entity cam) Engineer_UseCamera; void() CheckDistance; //WK void() Sentry_Touch; float(float myteam) HasFlag; //- OfN void(entity field) Field_Built; //========================================================================= // Laserbolt think function void() LaserBolt_Think = { if (time > self.heat) { dremove(self); return; } self.solid = SOLID_TRIGGER; self.movetype = MOVETYPE_FLYMISSILE; self.velocity = self.oldorigin; self.touch = LaserBolt_Touch; setmodel(self, "progs/e_spike2.mdl"); self.nextthink = time + 1.0; self.think = SUB_Remove; }; //========================================================================= // Laserbolt touch function. Just moves through the player and comes out // the other side. void() LaserBolt_Touch = { local vector org; if (time > self.heat) { dremove(self); return; } if (other == self.owner) return; if (other == self.enemy && self.enemy != world) return; // don't explode on same person twice if (pointcontents(self.origin) == CONTENT_SKY) { dremove(self); return; } //WK Sweep mines at point of impact GuerillaMineSweep(self.origin); org = self.origin - 8*normalize(self.velocity); if (other.health) { SpawnBlood (org, 15); deathmsg = DMSG_LASERBOLT; TF_T_Damage (other, self, self.enemy, 25, 0, TF_TD_ELECTRICITY); self.velocity = self.oldorigin; self.owner = other; setmodel (self, string_null); self.touch = SUB_Null; // self.solid = SOLID_NOT; // self.movetype = MOVETYPE_NOCLIP; self.nextthink = time + 0.1; self.think = LaserBolt_Think; return; } else { //WK Fly through walls! setmodel (self, string_null); self.touch = SUB_Null; self.solid = SOLID_NOT; self.movetype = MOVETYPE_NOCLIP; self.nextthink = time + 0.1; self.think = LaserBolt_Think; return; WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_SPIKE); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); multicast (self.origin, MULTICAST_PHS); } dremove(self); }; //========================================================================= // Fire a laserbolt void() W_FireLaser = { local vector vec, org; self.currentammo = self.ammo_nails = self.ammo_nails - 1; makevectors(self.v_angle); org = self.origin + (v_forward * 8); vec = aim(self, 10000); vec = normalize(vec); newmis = spawn(); newmis.owner = self; newmis.enemy = self; // The real owner newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_TRIGGER; setmodel (newmis, "progs/e_spike1.mdl"); setsize (newmis, '0 0 0', '0 0 0'); setorigin (newmis, org + '0 0 16'); newmis.velocity = vec * 1500; newmis.angles = vectoangles(newmis.velocity); newmis.oldorigin = newmis.velocity; newmis.nextthink = time + 1.5; newmis.heat = time + 1.5; newmis.think = SUB_Remove; newmis.touch = LaserBolt_Touch; }; //========================================================================= // Ammo/Weapon exploded by the EMP grenade void() EMPExplode = { local float expsize; expsize = 10; // Weapon? if (self.touch == weapon_touch) expsize = 60; else if (self.classname == "item_shells") expsize = 50 + self.aflag; else if (self.classname == "item_spikes") expsize = 40; else if (self.classname == "item_rockets") expsize = 100 + (self.aflag * 4); else if (self.classname == "item_cells") expsize = 100 + (self.aflag * 3); else if (self.classname == "item_weapon") expsize = 60; else { RPrint("EMPExplode: Attempting to explode a "); RPrint(self.classname); RPrint("\n"); return; } deathmsg = DMSG_GREN_EMP_AMMO; T_RadiusDamage (self, self.enemy, expsize, world); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); multicast (self.origin, MULTICAST_PHS); // Respawn Respawn_Item(self, self.enemy); }; //========================================================================= // Touch Function for EMP Grenade void() EMPGrenadeTouch = { // If the EMP Grenade hits a player, it just bounces off sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; //========================================================================= // EMP Grenade explode function, for when the PRIMETIME runs out void() EMPGrenadeExplode = { local float expsize; local entity te, oldself; local float total_exp; //CH Slice gave idea of an emp gren getting rated based on blast so i added.. total_exp = 0; WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_TAREXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); multicast (self.origin, MULTICAST_PHS); // Find all ammo in the area te = findradius(self.origin, 240); while (te) { if (!CanDamage(te,self)) // OfN SUB_Null(); else if (te.touch == ammo_touch || te.touch == weapon_touch) // Ammo/Weapon? { // Make sure it isn't picked up in the next second te.solid = SOLID_NOT; te.enemy = self.owner; te.nextthink = time + 1 + (random() * 2); te.think = EMPExplode; } // Detpack? else if (te.think == TeamFortress_DetpackExplode) { //te.solid = SOLID_NOT; te.nextthink = time + 225 * random() + 30; //WK Scramble the detpack's timer. :) dremove(te.oldenemy); // Countdown ent } // Pipebomb? else if (te.classname == "pipebomb") { te.nextthink = time + 0.1 + random(); } // Mine? else if (te.classname == "grenade" && te.netname == "land_mine") { te.think = GuerillaExplode; te.nextthink = time + 0.1; } // Building? else if (IsBuilding(te)) { total_exp = total_exp + 120; TF_T_Damage(te,self,self.owner, 120, 0, TF_TD_OTHER); } // Ammobox? else if (te.classname == "ammobox") { expsize = 0; expsize = expsize + (te.ammo_shells * 0.75); expsize = expsize + ((te.ammo_rockets * 0.75) * 2); expsize = expsize + ((te.ammo_cells * 0.75) * 2); if (expsize > 0) { te.solid = SOLID_NOT; // Damage player and explode deathmsg = DMSG_GREN_EMP; total_exp = total_exp + expsize; if (expsize > 300) //CH so they are not too powerfull //WK was 500 expsize = 300; T_RadiusDamage (te, self.owner, expsize, te); te.think = SUB_Remove; te.nextthink = time + 0.1; WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, te.origin_x); WriteCoord (MSG_BROADCAST, te.origin_y); WriteCoord (MSG_BROADCAST, te.origin_z); multicast (te.origin, MULTICAST_PHS); } } // Backpack/Player? else if ((te.classname == "player") || (te.classname=="monster_army") || (te.touch == BackpackTouch)) { expsize = 0; // calculate explosion size expsize = expsize + (te.ammo_shells * 0.75); expsize = expsize + ((te.ammo_rockets * 0.75) * 2); if (!(te.weapons_carried & WEAP_SPANNER || te.touch == BackpackTouch)) expsize = expsize + (te.ammo_cells * 0.75); if (expsize > 0) { // Damage player and explode deathmsg = DMSG_GREN_EMP; total_exp = total_exp + expsize; //WK Make players not explode radially! if (te.touch == BackpackTouch) T_RadiusDamage (te, self.owner, expsize / 2, te); //WK Dampen backpack damage if (te.touch != BackpackTouch) { TF_T_Damage (te, self, self.owner, expsize, 0, TF_TD_EXPLOSION); // Remove ammo te.ammo_shells = ceil(te.ammo_shells * 0.25); te.ammo_rockets = ceil(te.ammo_rockets * 0.25); if (!(te.cutf_items & CUTF_SENTRYGUN || te.tf_items & NIT_TESLA)) te.ammo_cells = ceil(te.ammo_cells * 0.25); if (te.classname=="player") { // Update console oldself = self; self = te; W_SetCurrentAmmo(); self = oldself; WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, te.origin_x); WriteCoord (MSG_BROADCAST, te.origin_y); WriteCoord (MSG_BROADCAST, te.origin_z); multicast (te.origin, MULTICAST_PHS); } } else { te.think = SUB_Remove; te.nextthink = time + 0.1; } WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, te.origin_x); WriteCoord (MSG_BROADCAST, te.origin_y); WriteCoord (MSG_BROADCAST, te.origin_z); multicast (te.origin, MULTICAST_PHS); } } te = te.chain; } sound (self, CHAN_WEAPON, "weapons/gren_emp.wav", 1, ATTN_NORM); //- OfN - cool sound! :) if (total_exp > 0) {//CH Thanks Slice for the idea :) sprint(self.owner,PRINT_HIGH, "Your EMP grenade inflicted "); local string st; st = ftos(total_exp); sprint(self.owner,PRINT_HIGH, st); sprint(self.owner,PRINT_HIGH, " damage\n"); } #ifdef DEMO_STUFF // Remove any camera's locks on this missile if (self.enemy) CamProjectileLockOff(); #endif dremove(self); }; //========================================================================= // Tests whether a team is allowed to build or not float(float myteam) HasFlag = { if ( mapname != "steal4d" ) return TRUE; if (myteam == team_with_flag){ return TRUE; } return FALSE; }; //========================================================================= // Function handling the Engineer's build impulse void() TeamFortress_EngineerBuild = { local entity te; // Can't build in the air // WK Yes you can, why not? You can do it by pulling up this menu anyway /* if (!(self.flags & FL_ONGROUND)) { CenterPrint(self, "You can't build in the air!\n\n"); return; } */ if (self.is_detpacking == 1) { CenterPrint(self, "You can't build while detpacking\n"); return; } if (self.is_feigning == 1) { CenterPrint(self, "You can't build while feigning\n"); return; } // Pop up the menu if (self.is_building == 0) { // Check to see if they've got enuf metal to build anything if (self.ammo_cells < BUILD_COST_CAMERA && self.has_dispenser == FALSE && self.has_sentry == FALSE && self.has_tesla == FALSE && self.has_camera == FALSE && self.has_teleporter == FALSE && self.has_sensor == FALSE && self.has_fieldgen == FALSE) { CenterPrint(self, "You don't have enough metal to \nbuild anything.\n\n"); return; } self.current_menu = MENU_ENGINEER; self.menu_count = MENU_REFRESH_RATE; } else if (self.is_building == 1) { sprint(self, PRINT_HIGH, "You stop building.\n"); self.is_building = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); // Remove the timer te = find(world, netname, "build_timer"); while (te) { if (te.owner == self) { dremove(te); te = world; } else { te = find(te, netname, "build_timer"); } } self.current_weapon = self.weapon; W_SetCurrentAmmo(); } }; float(entity obj, entity builder) CheckArea = { local vector src, end; local float pos; // Check the origin pos = pointcontents(obj.origin); if (pos == CONTENT_SOLID || pos == CONTENT_SKY) return FALSE; // Check the surrounding area src_x = obj.origin_x + obj.maxs_x + 16; src_y = obj.origin_y + obj.maxs_y + 16; src_z = obj.origin_z + obj.maxs_z + 16; // check upwards more pos = pointcontents(src); if (pos == CONTENT_SOLID || pos == CONTENT_SKY) return FALSE; end_x = obj.origin_x + obj.mins_x - 16; end_y = obj.origin_y + obj.mins_y - 16; end_z = obj.origin_z + obj.mins_z - 16; traceline (src, end, TRUE, obj); if (trace_fraction != 1) return FALSE; pos = pointcontents(end); if (pos == CONTENT_SOLID || pos == CONTENT_SKY) return FALSE; // extend the size a little src_x = obj.origin_x + obj.mins_x - 16; src_y = obj.origin_y + obj.maxs_y + 16; src_z = obj.origin_z + obj.maxs_z + 16; pos = pointcontents(src); if (pos == CONTENT_SOLID || pos == CONTENT_SKY) return FALSE; end_x = obj.origin_x + obj.maxs_x + 16; end_y = obj.origin_y + obj.mins_y - 16; end_z = obj.origin_z + obj.mins_z - 16; // check downwards less traceline (src, end, TRUE, obj); if (trace_fraction != 1) return FALSE; pos = pointcontents(end); if (pos == CONTENT_SOLID || pos == CONTENT_SKY) return FALSE; // Trace a line from the player to the object too traceline(builder.origin, obj.origin, TRUE, builder); if (trace_fraction != 1) return FALSE; // may add in more checks later return TRUE; }; ////////////////////////////////////////////////////////////////////////// // rehashed version of TF_Build void(float objtobuild) TeamFortress_Build = { local float btime; local vector mins, maxs; local entity obj; obj = spawn(); // get an origin makevectors(self.v_angle); v_forward_z = 0; v_forward = normalize(v_forward) * 64; if (objtobuild == BUILD_FIELDGEN) //- OfN - Field generators must be lined up to work obj.origin = WhereGen(self.origin + v_forward); else obj.origin = self.origin + v_forward; //WK Cheat Fix if (self.is_feigning) { sprint(self, PRINT_HIGH, "Try standing up first.\n"); return; } //OfN - Cheat Fix, heh if (self.is_haxxxoring) { sprint(self, PRINT_HIGH, "You can't build while hacking.\n"); return; } if (objtobuild == BUILD_DISPENSER) { if (self.has_dispenser) { sprint(self, PRINT_HIGH, "You can only have one dispenser.\nTry dismantling your old one.\n"); return; } if (!(self.cutf_items & CUTF_DISPENSER)) { sprint(self, PRINT_HIGH, "You must buy the dispenser before you can build it.\n"); return; } mins = '-8 -8 0'; maxs = '8 8 24'; #ifdef no_new_dispenser obj.mdl = "progs/disp.mdl"; #else obj.mdl = "progs/disp2.mdl"; #endif obj.netname = "dispenser"; btime = time + BUILD_TIME_DISPENSER; } else if (objtobuild == BUILD_SENTRYGUN) { if (self.has_sentry) { sprint(self, PRINT_HIGH, "You can only have one sentry gun.\nTry dismantling your old one.\n"); return; } if (!(self.cutf_items & CUTF_SENTRYGUN)) { sprint(self, PRINT_HIGH, "You must buy a sentrygun before you can build one.\n"); return; } mins = '-16 -16 0'; maxs = '16 16 48'; //obj.mdl = "progs/turrbase.mdl"; obj.mdl = "progs/trrbs2.mdl"; obj.netname = "sentrygun"; btime = time + BUILD_TIME_SENTRYGUN; } else if (objtobuild == BUILD_TESLA) { if (self.has_tesla) { sprint(self, PRINT_HIGH, "You can only have one tesla gun.\nTry dismantling your old one.\n"); return; } if (!(self.tf_items & NIT_TESLA)) { sprint(self, PRINT_HIGH, "You must buy a tesla sentry before you can build one.\n"); return; } // mins = '-16 -16 0'; //- OfN commented by mins = '-16 -16 -25'; // maxs = '16 16 48'; //WK 62 is better, but crashes? maxs = '16 16 23'; //obj.mdl = "progs/newtesla.mdl"; obj.mdl = "progs/coil.mdl"; obj.netname = "tesla"; // obj.origin = obj.origin + '0 0 25'; btime = time + BUILD_TIME_TESLA; } else if (objtobuild == BUILD_SECURITY_CAMERA) { if (self.has_camera) { sprint(self, PRINT_HIGH, "You can only have one security camera.\nTry dismantling your old one.\n"); return; } if (!(self.tf_items & NIT_SECURITY_CAMERA)) { sprint(self, PRINT_HIGH, "You must buy a security camera before you can build one.\n"); return; } Security_Camera_Spawn(); } else if (objtobuild == BUILD_TELEPORTER) { if (self.has_teleporter >= 2) { sprint(self, PRINT_HIGH, "You can only have 2 teleporters.\nTry dismantling an old one.\n"); return; } if (!(self.tf_items & NIT_TELEPORTER)) { sprint(self, PRINT_HIGH, "You must buy a teleporter before you can build one.\n"); return; } mins = '-16 -16 0'; maxs = '16 16 4'; obj.mdl = "progs/telepad.mdl"; obj.netname = "teleporter"; btime = time + BUILD_TIME_TELEPORTER; } else if (objtobuild == BUILD_FIELDGEN) { if (self.has_fieldgen >= 2) { sprint(self, PRINT_HIGH, "You already have 2 field generators.\nTry dismantling an old one.\n"); return; } if (!(self.cutf_items & CUTF_FIELDGEN)) { sprint(self, PRINT_HIGH, "You must buy a field generator before you can build one.\n"); return; } mins = '-6 -6 0'; maxs = '6 6 54'; obj.mdl = "progs/ffgen2.mdl"; obj.netname = "field generator"; btime = time + BUILD_TIME_FIELDGEN; } if (objtobuild != BUILD_SECURITY_CAMERA) { checkmove(obj.origin + '0 0 8', mins, maxs, obj.origin - '0 0 128', 0, self); if (trace_fraction == 1 || trace_allsolid) { sprint(self, PRINT_HIGH, "Not enough room to build here\n"); dremove(obj); return; } obj.origin = trace_endpos; obj.flags = obj.flags | FL_ONGROUND; obj.movetype = MOVETYPE_TOSS; obj.owner = self; obj.classname = "timer"; obj.netname = "build_timer"; obj.nextthink = btime; obj.think = TeamFortress_FinishedBuilding; obj.colormap = self.colormap; obj.weapon = objtobuild; obj.angles_y = anglemod(self.angles_y + 180); obj.solid = SOLID_BBOX; setmodel (obj, obj.mdl); setsize (obj, mins, maxs); setorigin (obj, obj.origin); if (objtobuild==BUILD_TESLA) { obj.skin = self.team_no; if (self.team_no==3) obj.skin=0; else if (self.team_no==4) obj.skin=3; } self.is_building = 1; makeImmune(self,time + 2); //self.immune_to_check = time + 2; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; // Save the current weapon and remove it self.weapon = self.current_weapon; self.current_weapon = 0; self.weaponmodel = ""; self.weaponframe = 0; TeamFortress_SetSpeed(self); } }; void() DispenserThink = { local float iI; // is Improved? iI=1; if (self.num_mines & IMPROVED_ONE) iI=2; // dispenser refilling itself 5% if (!(self.is_malfunctioning & SCREWUP_THREE)) // SB { self.ammo_shells = self.ammo_shells + rint((BUILD_DISPENSER_MAX_SHELLS*iI) / 10); self.ammo_cells = self.ammo_cells + rint((BUILD_DISPENSER_MAX_CELLS*iI) / 10); self.ammo_nails = self.ammo_nails + rint((BUILD_DISPENSER_MAX_NAILS*iI) / 10); self.ammo_rockets = self.ammo_rockets + rint((BUILD_DISPENSER_MAX_ROCKETS*iI) / 10); self.armorvalue = self.armorvalue + rint((BUILD_DISPENSER_MAX_ARMOR*iI) / 10); if (self.ammo_shells > BUILD_DISPENSER_MAX_SHELLS*iI) self.ammo_shells = BUILD_DISPENSER_MAX_SHELLS*iI; if (self.ammo_nails > BUILD_DISPENSER_MAX_NAILS*iI) self.ammo_nails = BUILD_DISPENSER_MAX_NAILS*iI; if (self.ammo_rockets > BUILD_DISPENSER_MAX_ROCKETS*iI) self.ammo_rockets = BUILD_DISPENSER_MAX_ROCKETS*iI; if (self.ammo_cells > BUILD_DISPENSER_MAX_CELLS*iI) self.ammo_cells = BUILD_DISPENSER_MAX_CELLS*iI; if (self.armorvalue > BUILD_DISPENSER_MAX_ARMOR*iI) self.armorvalue = BUILD_DISPENSER_MAX_ARMOR*iI; } self.nextthink = time + 10; }; void() TeamFortress_FinishedBuilding = { local entity tmpself; local entity oldself; local float current_yaw; local vector source; if (self.owner.is_building != 1) return; oldself = self; self = self.owner; oldself.owner = world; oldself.real_owner = self; self.is_building = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.current_weapon = self.weapon; self.StatusRefreshTime = time + 0.1; TeamFortress_SetSpeed(self); if (oldself.weapon == BUILD_DISPENSER) { self.has_dispenser = TRUE; sprint (self, PRINT_HIGH, "You finish building the dispenser.\n"); teamprefixsprint(self.team_no,self); //- OfN teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a Dispenser.\n"); self.ammo_cells = self.ammo_cells - BUILD_COST_DISPENSER; // Create the dispenser oldself.classname = "building_dispenser"; oldself.netname = "dispenser"; oldself.blocked = T_Dispenser; // Actual touch function oldself.touch = T_Dispenser; oldself.max_health = BUILD_HEALTH_DISPENSER; oldself.health = BUILD_HEALTH_DISPENSER; oldself.think = DispenserThink; oldself.nextthink = time + 5; oldself.th_die = Dispenser_Die; // Death function #ifdef no_new_dispenser oldself.mdl = "progs/disp.mdl"; // Actual mdl #else oldself.mdl = "progs/disp2.mdl"; // Actual mdl #endif oldself.team_no = self.team_no; oldself.num_mines=0; // OfN - reset HACKER improvements oldself.real_owner = self; // The Engineer owns this item oldself.colormap = self.colormap; // Set the Color oldself.takedamage = DAMAGE_AIM; oldself.owner = world; // Put some ammo in the Dispenser oldself.ammo_shells = ceil(self.ammo_shells * 0.25); oldself.ammo_nails = ceil(self.ammo_nails * 0.25); oldself.ammo_rockets = ceil(self.ammo_rockets * 0.25); oldself.ammo_cells = ceil(self.ammo_cells * 0.25); oldself.armorvalue = ceil(self.armorvalue * 0.25); // Remove ours self.ammo_shells = ceil(self.ammo_shells * 0.75); self.ammo_nails = ceil(self.ammo_nails * 0.75); self.ammo_rockets = ceil(self.ammo_rockets * 0.75); self.ammo_cells = ceil(self.ammo_cells * 0.75); self.armorvalue = ceil(self.armorvalue * 0.75); oldself.solid = SOLID_BBOX; setmodel(oldself, oldself.mdl); } else if (oldself.weapon == BUILD_SENTRYGUN) { //CH special sbar for eng. self.StatusBarScreen = 1; self.has_sentry = TRUE; sprint (self, PRINT_HIGH, "You finish building the sentry gun.\n"); teamprefixsprint(self.team_no,self); //- OfN teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a Sentry Gun.\n"); oldself.classname = "building_sentrygun_base"; oldself.netname = "sentry gun"; oldself.takedamage = 0; oldself.th_die = Sentry_Die; // Death function self.ammo_cells = self.ammo_cells - BUILD_COST_SENTRYGUN; setsize (oldself, '-16 -16 0', '16 16 4'); // '-16 -16 0' '16 16 4' newmis = spawn(); newmis.classname = "building_sentrygun"; newmis.health = BUILD_HEALTH_SENTRYGUN; newmis.max_health = newmis.health; newmis.tf_items = NIT_KEVLAR; //Start with kevlar armor newmis.armorclass = AT_SAVESHOT; //kevlar armor newmis.weapon = 1; // Level 1 Turret newmis.th_die = Sentry_Die; // Death function newmis.th_pain = Sentry_Pain; //newmis.mdl = "progs/turrgun.mdl"; newmis.mdl = "progs/trrgn2.mdl"; sound (oldself, CHAN_ITEM, "weapons/turrset.wav", 1, ATTN_NORM); newmis.solid = SOLID_BBOX; setmodel(newmis, newmis.mdl); setsize (newmis, '-16 -16 0', '16 16 48'); setorigin(newmis, oldself.origin + '0 0 8'); newmis.real_owner = oldself.real_owner; // The Engineer owns this item newmis.trigger_field = oldself; oldself.oldenemy = newmis; newmis.movetype = MOVETYPE_STEP; oldself.colormap = self.colormap; // Set the Base Color newmis.colormap = self.colormap; // Set the Color newmis.skin = self.team_no - 1; newmis.takedamage = DAMAGE_AIM; newmis.velocity = '0 0 -8'; newmis.frags = 0; //CH how many people has your sent killed? newmis.team_no = self.team_no; newmis.think = lvl1_sentry_stand; newmis.nextthink = time + 0.5; newmis.touch = Sentry_Touch; // Rotate Details newmis.yaw_speed = 10; //Turn rate newmis.heat = 0; // Turn Right newmis.angles_x = 0; newmis.angles_y = ceil(oldself.angles_y); //CH remove decimal newmis.angles_z = 0; newmis.angles_y = ((ceil(newmis.angles_y / 10)) * 10); //CH set last int to 0 newmis.waitmin = anglemod(newmis.angles_y - 50); newmis.waitmax = anglemod(newmis.angles_y + 50); // Give the Gun some ammo newmis.ammo_shells = 75; //WK newmis.maxammo_shells = 100; newmis.maxammo_rockets = 20; newmis.num_mines=0; // OfN - reset HACKER improvements newmis.attack_finished=time; //- controls time after loosing track of enemy to not be rotating newmis.has_holo=0; } else if (oldself.weapon == BUILD_TESLA) { //CH special sbar for eng. self.StatusBarScreen = 4; self.has_tesla = TRUE; sprint (self, PRINT_HIGH, "You finish building the tesla.\n"); teamprefixsprint(self.team_no,self); //- OfN teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a tesla.\n"); sound (oldself, CHAN_ITEM, "weapons/guerilla_set.wav", 1, ATTN_NORM); oldself.classname = "building_tesla"; oldself.netname = "tesla"; oldself.takedamage = DAMAGE_AIM; oldself.solid = SOLID_BBOX; oldself.th_die = Tesla_Die; // Death function oldself.th_pain = Tesla_Pain; self.ammo_cells = self.ammo_cells - BUILD_COST_TESLA; oldself.health = BUILD_HEALTH_TESLA; oldself.movetype = MOVETYPE_TOSS; oldself.colormap = self.colormap; // Set the Base Color oldself.team_no = self.team_no; //- OfN - //oldself.think = Tesla_Idle; oldself.think = tsla_on1; //oldself.nextthink = time + 2; oldself.nextthink = time + 0.1; oldself.has_holo = time + 2; // next Tesla_Idle run oldself.job = 0; // this flag will determine which frame animation is currently on //oldself.job_finished = time; // change for frame animation purposes, instead of increasing its nextthing during charging oldself.no_grenades_1 = FALSE; // first think reset oldself.no_grenades_2 = 0; // cloak touch delay reset oldself.touch = Tesla_Touch; oldself.enemy = world; oldself.oldenemy = world; //CH for sbar //Set all initial tesla values here oldself.maxammo_shells = 0; //Voltage == 0 oldself.maxammo_nails = 0; //Amps == 0 oldself.maxammo_rockets = 0; //Battery == 0 oldself.max_health = 150; oldself.ammo_cells = MAXCELLS0; //Initial ammo allocation oldself.maxammo_cells = MAXCELLS0; //Initial maxammo oldself.tf_items = NIT_CERAMIC; //Start with shock armor oldself.armorclass = AT_SAVEELECTRICITY; //Shock armor if (self.tf_items & NIT_TESLA_UPGRADE) { oldself.has_sentry = 6; //Normal Upgrades oldself.has_tesla = 2; //Misc Upgrade } else { oldself.has_sentry = 4; //Normal Upgrades oldself.has_tesla = 1; //Misc Upgrade } oldself.has_teleporter = 0; //CH for frag related upgrades if (!(self.weapons_carried & WEAP_SPANNER)) { //No spanner oldself.ammo_shells = 1; oldself.ammo_nails = 2; oldself.ammo_rockets = 1; oldself.has_sentry = oldself.has_sentry - 4; //Take away 3 oldself.max_health = 225; oldself.ammo_cells = MAXCELLS1; //Initial ammo allocation oldself.maxammo_cells = MAXCELLS1; } oldself.health = oldself.max_health; oldself.waitmin = (oldself.ammo_shells + 2) * (oldself.ammo_nails + 2); oldself.waitmax = FALSE; //No target yet oldself.frags = 0; //CH how many people has your sent killed? oldself.lip = 0; //WK How many tinkers have been done modelindex_tesla = oldself.modelindex; //CH oldself.num_mines=0; // OfN - reset HACKER improvements oldself.is_haxxxoring=0; // isnt flying } else if (oldself.weapon == BUILD_TELEPORTER) { self.has_teleporter = (self.has_teleporter + 1); sprint (self, PRINT_HIGH, "You finish building the Teleporter Pad.\n"); teamprefixsprint(self.team_no,self); //- OfN teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a Teleporter Pad.\n"); sound (oldself, CHAN_ITEM, "weapons/guerilla_set.wav", 1, ATTN_NORM); self.ammo_cells = self.ammo_cells - BUILD_COST_TELEPORTER; // Create the teleporter oldself.classname = "building_teleporter"; oldself.netname = "teleporter"; // oldself.blocked = Teleporter_touch; // Actual touch function oldself.touch = Teleporter_touch; oldself.max_health = BUILD_HEALTH_TELEPORTER; oldself.health = BUILD_HEALTH_TELEPORTER; oldself.th_die = Teleporter_Die; // Death function oldself.mdl = "progs/telepad.mdl"; // Actual mdl oldself.team_no = self.team_no; oldself.maxammo_cells = 200; //CH Max of 20 teleports oldself.ammo_cells = 100; //CH start not at full oldself.real_owner = self; // The Engineer owns this item oldself.colormap = self.colormap; // Set the Color oldself.takedamage = DAMAGE_AIM; oldself.owner = world; oldself.movetype = MOVETYPE_TOSS; oldself.solid = SOLID_BBOX; setmodel(oldself, oldself.mdl); setsize (oldself, '-16 -16 0', '16 16 4'); setorigin(oldself, oldself.origin); //CH does jump oldself.heat = 4; //dont come on for 4 seconds oldself.think = Teleporter_heat_think; oldself.nextthink = time + 1; oldself.spawnflags = 4; //CH cause extensive checks for height oldself.num_mines=0; // OfN - reset HACKER improvements } else if (oldself.weapon == BUILD_FIELDGEN) { self.has_fieldgen = (self.has_fieldgen + 1); sprint (self, PRINT_HIGH, "You finish building the Field Generator.\n"); teamprefixsprint(self.team_no,self); //- OfN teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a Field Generator.\n"); sound (oldself, CHAN_ITEM, "weapons/guerilla_set.wav", 1, ATTN_NORM); self.ammo_cells = self.ammo_cells - BUILD_COST_FIELDGEN; // Create the teleporter oldself.classname = "building_fieldgen"; oldself.netname = "field generator"; // oldself.blocked = Teleporter_touch; // Actual touch function //oldself.touch = Teleporter_touch; oldself.max_health = BUILD_HEALTH_FIELDGEN; oldself.health = BUILD_HEALTH_FIELDGEN; oldself.th_die = FieldGen_Die; // Death function oldself.mdl = "progs/ffgen2.mdl"; // Actual mdl oldself.team_no = self.team_no; oldself.maxammo_cells = 100; //CH Max of 20 field recharges oldself.ammo_cells = 75; //CH start not at full*/ oldself.real_owner = self; // The Engineer owns this item oldself.colormap = self.colormap; // Set the Color oldself.takedamage = DAMAGE_AIM; oldself.owner = world; oldself.movetype = MOVETYPE_TOSS; oldself.solid = SOLID_BBOX; oldself.angles = '0 0 0'; setmodel(oldself, oldself.mdl); oldself.spawnflags = 4; //CH cause extensive checks for height oldself.is_malfunctioning = 0; oldself.num_mines=0; // OfN - reset HACKER improvements Field_Built(oldself); } W_SetCurrentAmmo(); }; //========================================================================= // Dispenser Touch function. Allows players to get stuff from the Dispenser. void() T_Dispenser = { local entity dist_checker; if (other.classname != "player") return; if (self.is_malfunctioning & SCREWUP_ONE) return; if (self.is_malfunctioning & SCREWUP_TWO) TF_T_Damage(self, self, self, 200, 0, TF_TD_OTHER); // Ignore any engineer working on this dispenser if (other.building == world && other.building_wait < time) { // Pop up the menu other.current_menu = MENU_DISPENSER; other.menu_count = MENU_REFRESH_RATE; other.building = self; // Start a Distance checker, which removes the menu if the player // gets too far away from the Dispenser. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = other; dist_checker.enemy = self; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; } }; //============================================================ // this is needed to avoid stack overflow void() Dispenser_Explode = { T_RadiusDamage(self.demon_one, self.demon_one, self.has_holo, world); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.demon_one.origin_x); WriteCoord (MSG_BROADCAST, self.demon_one.origin_y); WriteCoord (MSG_BROADCAST, self.demon_one.origin_z); multicast (self.demon_one.origin, MULTICAST_PHS); dremove(self.demon_one); dremove(self); // remove explosion timer for this dispenser }; void() Dispenser_Die = { local float damg; self.real_owner.has_dispenser = FALSE; damg = self.ammo_cells * 0.25; damg = damg + self.ammo_nails * 0.1; damg = damg + self.ammo_shells * 0.2; damg = damg + self.ammo_rockets / 2; //- OfN causes overflow so we need a timer for dispenser explosion newmis = spawn(); newmis.has_holo = damg; newmis.demon_one = self; newmis.nextthink = time + 0.1; newmis.think = Dispenser_Explode; /*T_RadiusDamage(self, self, damg, world); // OfN - Fixme, stack overflow??*/ sprint(self.real_owner, PRINT_HIGH, "Your dispenser was destroyed.\n"); #ifdef no_new_dispenser ThrowGib("progs/dgib1.mdl", -30); ThrowGib("progs/dgib2.mdl", -50); ThrowGib("progs/dgib3.mdl", -50); #else ThrowGib("progs/d2gib1.mdl", -30); ThrowGib("progs/d2gib2.mdl", -50); ThrowGib("progs/d2gib3.mdl", -50); #endif }; //========================================================================= // Engineer has used a Spanner on the Dispenser void(entity disp) Engineer_UseDispenser = { local entity dist_checker; local string st; // Print the dispenser's details sprint (self, PRINT_HIGH, "Dispenser has "); st = ftos(disp.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(disp.max_health); sprint(self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " èåáìôè\n"); st = ftos(disp.ammo_shells); sprint (self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " óèåììó, "); st = ftos(disp.ammo_nails); sprint (self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " îáéìó, "); st = ftos(disp.ammo_rockets); sprint (self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " òïãëåôó\n"); st = ftos(disp.ammo_cells); sprint (self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " ãåììó, and "); st = ftos(disp.armorvalue); sprint (self, PRINT_HIGH, st); sprint (self, PRINT_HIGH, " áòíïò\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_DISPENSER; self.menu_count = MENU_REFRESH_RATE; self.building = disp; // Start a Distance checker, which removes the menu if the player // gets too far away from the Dispenser. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = disp; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //========================================================================= // Engineer has used a Spanner on the SentryGun void(entity gun) Engineer_UseSentryGun = { local entity dist_checker; local string st; // Print the gun's details sprint(self, PRINT_HIGH, "Ìåöåì "); st = Return_Colored_Num(gun.weapon); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " Sentry Gun has "); st = ftos(gun.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(gun.max_health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " èåáìôè, "); st = ftos(gun.ammo_shells); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " óèåììó"); if (gun.weapon == 3) { st = ftos(gun.ammo_rockets); sprint(self, PRINT_HIGH, ", "); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " òïãëåôó"); } sprint(self, PRINT_HIGH, "\n"); sprint(self, PRINT_HIGH, "Sentry Gun ÆÒÁÇÓ: "); //CH Displays kills of sent st = ftos(gun.frags); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_SENTRYGUN; self.menu_count = MENU_REFRESH_RATE; self.building = gun; //dodgy if (teamplay != 0 && !Teammate(self.building.real_owner.team_no,self.team_no)) { Menu_EngineerFix_SentryGun_Input(5); return; } // Start a Distance checker, which removes the menu if the player // gets too far away from the sentry. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = gun; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //////////////////////////////////////////////// // Engineer has used a Spanner on the Tesla void(entity gun) Engineer_UseTesla = { local entity dist_checker; local string st; // Print the gun's details sprint(self, PRINT_HIGH, "Èåáìôè:"); st = ftos(gun.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(gun.max_health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " Ãåììó:"); st = ftos(gun.ammo_cells); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(gun.maxammo_cells); sprint(self, PRINT_HIGH, st); st = ftos(gun.has_sentry); sprint(self, PRINT_HIGH, " Îïòíáì Ups Left:"); sprint(self, PRINT_HIGH, st); st = ftos(gun.has_tesla); sprint(self, PRINT_HIGH, " Íéóã Ups Left:"); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "\n"); sprint(self, PRINT_HIGH, "Öïìôáçå:"); st = ftos(gun.ammo_shells); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " Áíðåòáçå:"); st = ftos(gun.ammo_nails); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " Ðï÷åò Óõððìù:"); st = ftos(gun.ammo_rockets); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "\n"); if (gun.tf_items) { local float num; num = 0; if (gun.tf_items & NIT_TURRET) { sprint(self, PRINT_HIGH, "TeslaTurret(tm). "); num = num + 1; } if (gun.tf_items & NIT_SCANNER) { sprint(self, PRINT_HIGH, "Improved Targeter. "); num = num + 1; } if (gun.tf_items & NIT_AUTOID) { sprint(self, PRINT_HIGH, "Spy Detector. "); num = num + 1; } if (gun.tf_items & NIT_KEVLAR) { sprint(self, PRINT_HIGH, "Kevlar Armor. "); num = num + 1; } if (gun.tf_items & NIT_BLAST) { sprint(self, PRINT_HIGH, "Blast Armor. "); num = num + 1; } if (gun.tf_items & NIT_ASBESTOS) { sprint(self, PRINT_HIGH, "Asbestos Armor. "); num = num + 1; } if (gun.tf_items & NIT_TELEPORTER) { sprint(self, PRINT_HIGH, "Upgrades from frags. "); num = num + 1; } if (gun.tf_items & NIT_TESLA_CLOAKING) { sprint(self, PRINT_HIGH, "Cloaking Device. "); num = num + 1; } if (num != 0) sprint(self, PRINT_HIGH, "\n"); } sprint(self, PRINT_HIGH, "Tesla Sentry ÆÒÁÇÓ: "); //CH Displays kills of tesla st = ftos(gun.frags); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_TESLA; self.menu_count = MENU_REFRESH_RATE; self.building = gun; // dodgy if (teamplay != 0 && !Teammate(self.building.real_owner.team_no, self.team_no)) { Menu_EngineerFix_Tesla_Input(8); return; } // Start a Distance checker, which removes the menu if the player // gets too far away from the tesla. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = gun; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //================= void(entity cam) Engineer_UseSensor = { local entity dist_checker; local string st; sprint(self, PRINT_HIGH, "Motion Sensor has "); st = ftos(cam.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(ceil(cam.max_health)); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " èåáìôè\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_SENSOR; self.menu_count = MENU_REFRESH_RATE; self.building = cam; if (teamplay != 0 && !Teammate(self.building.real_owner.team_no, self.team_no)) { Menu_EngineerFix_Sensor_Input(3); return; } // Start a Distance checker, which removes the menu if the player // gets too far away from the camera. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = cam; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //================= void(entity cam) Engineer_UseCamera = { local entity dist_checker; local string st; sprint(self, PRINT_HIGH, "Security Camera has "); st = ftos(cam.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(ceil(cam.max_health)); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " èåáìôè\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_CAMERA; self.menu_count = MENU_REFRESH_RATE; self.building = cam; if (teamplay != 0 && !Teammate(self.building.real_owner.team_no,self.team_no)) { Menu_EngineerFix_Camera_Input(3); return; } // Start a Distance checker, which removes the menu if the player // gets too far away from the camera. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = cam; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //================= void(entity tele) Engineer_UseTeleporter = { local entity dist_checker; local string st; sprint(self, PRINT_HIGH, "Teleporter Pad has "); st = ftos(tele.health); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(ceil(tele.max_health)); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " èåáìôè "); st = ftos(tele.ammo_cells); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, "¯"); st = ftos(ceil(tele.maxammo_cells)); sprint(self, PRINT_HIGH, st); sprint(self, PRINT_HIGH, " ãåììó\n"); // Pop up the menu self.current_menu = MENU_ENGINEER_FIX_TELEPORTER; self.menu_count = MENU_REFRESH_RATE; self.building = tele; if (teamplay != 0 && !Teammate(self.building.real_owner.team_no,self.team_no)) { Menu_EngineerFix_Teleporter_Input(4); return; } // Start a Distance checker, which removes the menu if the player // gets too far away from the teleporter. dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; dist_checker.enemy = tele; dist_checker.think = CheckDistance; dist_checker.nextthink = time + 0.3; }; //========================================================================= // Think function for the timer which checks the distance between the // Engineer and the building he's using void() CheckDistance = { local vector dist; // Check to see if the Engineer's spanner'ed a different building // without leaving the area of this one. if (self.owner.building != self.enemy) { dremove(self); return; } dist = self.enemy.origin - self.owner.origin; //WK if (vlen(dist) > 64) if (vlen(dist) > 98) { CenterPrint(self.owner, "\n"); self.owner.menu_count = MENU_REFRESH_RATE; self.owner.current_menu = MENU_DEFAULT; self.owner.building = world; dremove(self); return; } self.nextthink = time + 0.3; };