From: Samual Date: Tue, 26 Apr 2011 03:42:16 +0000 (-0400) Subject: Lots of updates from when I was on vacation/had some free time. Almost done now. X-Git-Tag: xonotic-v0.7.0~240^2~173 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=0240a9a6c9c7e28d4c81765c927dc07e1e9e9d6b;p=xonotic%2Fxonotic-data.pk3dir.git Lots of updates from when I was on vacation/had some free time. Almost done now. Start work for use of mutator hook for frags, move things around in the file for better compilation, change some small comments and typos, add some missing things for damage, re-write pickup_dropped handler, re-write flagthink method, re-write respawnflag method, add playerdamage mutator hook. --- diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 657ba48e5..679e03429 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -208,7 +208,7 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype) } f = 0; } - else if(g_ctf) + else if(g_ctf) // FIXCTF { if(g_ctf_ignore_frags) f = 0; @@ -712,15 +712,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself } - // CTF: reduce damage/force - if(g_ctf) - if(targ == attacker) - if(targ.flagcarried) - { - damage = damage * autocvar_g_ctf_flagcarrier_selfdamage; - force = force * autocvar_g_ctf_flagcarrier_selfforce; - } - if(g_runematch) { // apply strength rune diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index 1d49eeedc..8d3c1b993 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -32,16 +32,12 @@ float ctf_captureshield_max_ratio; // punish at most 30% of each team float ctf_captureshield_force; // push force of the shield // declare functions so they can be used in any order in the file +/* void ctf_FlagTouch(void); void ctf_FlagThink(void); void ctf_SetupFlag(float, entity); void ctf_RespawnFlag(entity); -float ctf_CaptureShield_CheckStatus(entity); -void ctf_CaptureShield_Update(entity, float); -float ctf_CaptureShield_Customize(void); -void ctf_CaptureShield_Touch(void); -void ctf_CaptureShield_Spawn(entity); - +*/ // ================== // Misc CTF functions @@ -73,6 +69,100 @@ void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for } +// ======================= +// CaptureShield Functions +// ======================= + +float ctf_CaptureShield_CheckStatus(entity p) +{ + float s, se; + entity e; + float players_worseeq, players_total; + + if(ctf_captureshield_max_ratio <= 0) + return FALSE; + + s = PlayerScore_Add(p, SP_SCORE, 0); + if(s >= -ctf_captureshield_min_negscore) + return FALSE; + + players_total = players_worseeq = 0; + FOR_EACH_PLAYER(e) + { + if(e.team != p.team) + continue; + se = PlayerScore_Add(e, SP_SCORE, 0); + if(se <= s) + ++players_worseeq; + ++players_total; + } + + // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse + // use this rule here + + if(players_worseeq >= players_total * ctf_captureshield_max_ratio) + return FALSE; + + return TRUE; +} + +void ctf_CaptureShield_Update(entity player, float wanted_status) +{ + float updated_status = ctf_CaptureShield_CheckStatus(player); + if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only + { + if(updated_status) // TODO csqc notifier for this // Samual: How? + centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again."); + else + centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed."); + + player.ctf_captureshielded = updated_status; + } +} + +float ctf_CaptureShield_Customize() +{ + if not(other.ctf_captureshielded) + return FALSE; + if(self.team == other.team) + return FALSE; + return TRUE; +} + +void ctf_CaptureShield_Touch() +{ + if not(other.ctf_captureshielded) + return; + if(self.team == other.team) + return; + vector mymid; + vector othermid; + mymid = (self.absmin + self.absmax) * 0.5; + othermid = (other.absmin + other.absmax) * 0.5; + Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force); + centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again."); +} + +void ctf_CaptureShield_Spawn(entity flag) +{ + entity e; + e = spawn(); + e.enemy = self; + e.team = self.team; + e.touch = ctf_CaptureShield_Touch; + e.customizeentityforclient = ctf_CaptureShield_Customize; + e.classname = "ctf_captureshield"; + e.effects = EF_ADDITIVE; + e.movetype = MOVETYPE_NOCLIP; + e.solid = SOLID_TRIGGER; + e.avelocity = '7 0 11'; + setorigin(e, self.origin); + setmodel(e, "models/ctf/shield.md3"); + e.scale = 0.5; + setsize(e, e.scale * e.mins, e.scale * e.maxs); +} + + // ============== // Event Handlers // ============== @@ -92,7 +182,6 @@ void ctf_Handle_Drop(entity player) // make sure this works flag.movetype = MOVETYPE_TOSS; flag.solid = SOLID_TRIGGER; flag.takedamage = DAMAGE_YES; - //flag.flags = FL_ITEM; // does this need set? same as above. // eh wtf is with these weird values? flag.velocity = ('0 0 200' + ('0 100 0' * crandom()) + ('100 0 0' * crandom())); flag.pain_finished = time + autocvar_g_ctf_flag_returntime; // replace this later @@ -114,10 +203,10 @@ void ctf_Handle_Drop(entity player) // make sure this works WaypointSprite_Ping(player.wps_flagcarrier); WaypointSprite_Kill(player.wps_flagcarrier); - // + // captureshield ctf_CaptureShield_Update(player, 0); // shield only - // eh? + // check if the flag will fall off the map trace_startsolid = FALSE; tracebox(flag.origin, flag.mins, flag.maxs, flag.origin, TRUE, flag); if(trace_startsolid) @@ -195,7 +284,7 @@ void ctf_Handle_Return(entity flag, entity player) // make sure this works } // waypointsprites - WaypointSprite_Kill(player.wps_flagdropped); + WaypointSprite_Kill(flag.wps_flagdropped); // reset the flag ctf_RespawnFlag(flag); @@ -205,7 +294,7 @@ void ctf_Handle_Pickup_Base(entity flag, entity player) // make sure this works { entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players string verbosename; // holds the name of the player OR no name at all for printing in the centerprints - + // attach the flag to the player flag.owner = player; player.flagcarried = flag; @@ -214,6 +303,7 @@ void ctf_Handle_Pickup_Base(entity flag, entity player) // make sure this works // set up the flag flag.movetype = MOVETYPE_NONE; + flag.takedamage = DAMAGE_NO; flag.solid = SOLID_NOT; flag.angles = '0 0 0'; flag.ctf_pickuptime = time; // used for timing runs @@ -254,50 +344,58 @@ void ctf_Handle_Pickup_Base(entity flag, entity player) // make sure this works WaypointSprite_Ping(player.wps_flagcarrier); } -void ctf_Handle_Pickup_Dropped(entity flag, entity player) // todo: re-write this +void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this works { - /* - if(flag.waypointsprite_attachedforcarrier) - WaypointSprite_DetachCarrier(flag); + // declarations + float returnscore = bound(0, (flag.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1); // can this be division by zero? + entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players + string verbosename; // holds the name of the player OR no name at all for printing in the centerprints - if (autocvar_g_ctf_flag_pickup_effects) // field pickup effect - pointparticles(particleeffectnum("smoke_ring"), 0.5 * (flag.absmin + flag.absmax), '0 0 0', 1); - - // pick up - flag.solid = SOLID_NOT; - setorigin(flag, flag.origin); // relink + // attach the flag to the player flag.owner = player; player.flagcarried = flag; - flag.cnt = FLAG_CARRY; + setattachment(flag, player, ""); + setorigin(flag, FLAG_CARRY_POS); + + // set up the flag + flag.movetype = MOVETYPE_NONE; + flag.takedamage = DAMAGE_NO; + flag.solid = SOLID_NOT; + flag.angles = '0 0 0'; + flag.ctf_pickuptime = time; // used for timing runs + flag.ctf_pickupid = player.playerid; + flag.ctf_status = FLAG_CARRY; + + // messages and sounds Send_KillNotification (player.netname, flag.netname, "", INFO_PICKUPFLAG, MSG_INFO); - //bprint(player.netname, "^7 picked up the ", flag.netname, "\n"); - - float f; - f = bound(0, (flag.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1); - //print("factor is ", ftos(f), "\n"); - f = ctf_ReadScore("score_pickup_dropped_late") * (1-f) - + ctf_ReadScore("score_pickup_dropped_early") * f; - f = floor(f + 0.5); - flag.dropperid = player.playerid; - //print("score is ", ftos(f), "\n"); - - UpdateFrags(player, f); - PlayerScore_Add(player, SP_CTF_PICKUPS, 1); - LogCTF("pickup", flag.team, player); sound (player, CHAN_AUTO, flag.noise, VOL_BASE, ATTN_NONE); + ctf_EventLog("pickup", flag.team, player); + verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat("(", player.netname, ")") : ""); + FOR_EACH_PLAYER(tmp_player) + if(tmp_player.team == flag.team) + centerprint(tmp_player, strcat("The enemy ", verbosename, "got your flag! Retrieve it!")); + else if((tmp_player.team == player.team) && (tmp_player != player)) + centerprint(tmp_player, strcat("Your team mate ", verbosename, "got the flag! Protect them!")); - FOR_EACH_PLAYER(player) - if(player.team == flag.team) - centerprint(player, "The enemy got your flag! Retrieve it!"); + // scoring + returnscore = floor((ctf_ReadScore("score_pickup_dropped_late") * (1-returnscore) + ctf_ReadScore("score_pickup_dropped_early") * returnscore) + 0.5); + print("score is ", ftos(returnscore), "\n"); + PlayerTeamScore_AddScore(player, returnscore); + PlayerScore_Add(player, SP_CTF_PICKUPS, 1); - flag.movetype = MOVETYPE_NONE; // flag must have MOVETYPE_NONE here, playerwise it will drop through the floor... - setorigin(flag, FLAG_CARRY_POS); - setattachment(flag, player, ""); - flag.damageforcescale = 0; - flag.takedamage = DAMAGE_NO; - WaypointSprite_AttachCarrier("flagcarrier", player); - WaypointSprite_UpdateTeamRadar(player.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 1 0'); - */ + // effects + if (autocvar_g_ctf_flag_pickup_effects) // field pickup effect + { + pointparticles(particleeffectnum("smoke_ring"), 0.5 * (flag.absmin + flag.absmax), '0 0 0', 1); + } + + // waypoints + WaypointSprite_Kill(flag.wps_flagdropped); + WaypointSprite_Spawn("flagcarrier", 0, 0, player, '0 0 64', world, player.team, player, wps_flagcarrier, FALSE); // (COLOR_TEAM1 + COLOR_TEAM2 - flag.team) + WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent) * 2); + WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent)); + WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, '1 1 0'); + WaypointSprite_Ping(player.wps_flagcarrier); } @@ -305,6 +403,146 @@ void ctf_Handle_Pickup_Dropped(entity flag, entity player) // todo: re-write thi // Main Flag Functions // =================== +void ctf_FlagThink() // make sure this works +{ + // declarations + entity tmp_entity; + + self.nextthink = time + 0.1; + + // captureshield + if(self == ctf_worldflaglist) // only for the first flag + FOR_EACH_CLIENT(tmp_entity) + ctf_CaptureShield_Update(tmp_entity, 1); // release shield only + + // sanity checks + if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished + dprint("wtf the flag got squished?\n"); + tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self); + if(!trace_startsolid) // can we resize it without getting stuck? + setsize(self, FLAG_MIN, FLAG_MAX); } + + if(self.owner.classname != "player" || (self.owner.deadflag) || (self.owner.flagcarried != self)) { + dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n"); + ctf_Handle_Drop(self.owner); + return; } + + // main think method + switch(self.ctf_status) + { + case FLAG_BASE: // nothing to do here + return; + + case FLAG_DROPPED: + // flag fallthrough? FIXME remove this if bug is really fixed now + if(self.origin_z < -131072) + { + dprint("FLAG FALLTHROUGH just happened\n"); + self.pain_finished = 0; + } + setattachment(self, world, ""); + if(time > self.pain_finished) + { + bprint("The ", self.netname, " has returned to base\n"); + sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE); + ctf_EventLog("returned", self.team, world); + ctf_RespawnFlag(self); + } + return; + + case FLAG_CARRY: + if((self.owner) && (self.speedrunning) && (ctf_captimerecord) && (time >= self.ctf_pickuptime + ctf_captimerecord)) + { + bprint("The ", self.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); + sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE); + + self.owner.impulse = 141; // returning! + + tmp_entity = self; + self = self.owner; + ctf_RespawnFlag(tmp_entity); + ImpulseCommands(); + self = tmp_entity; + } + return; + + default: + dprint("Think: Flag exists with no status?\n"); + return; // this should never happen + } +} + +void ctf_FlagTouch() +{ + if(gameover) { return; } + if(!self) { return; } + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) + { // The flag fell off the map, respawn it since players can't get to it + //ctf_RespawnFlag(self); + return; + } + if(other.deadflag != DEAD_NO) { return; } + if(other.classname != "player") + { // The flag just touched an object, most likely the world + pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1); + sound(self, CHAN_AUTO, "keepaway/touch.wav", VOL_BASE, ATTN_NORM); + return; + } + else if(self.wait > time) { return; } + + switch(self.ctf_status) + { + case FLAG_BASE: + if((other.team == self.team) && (other.flagcarried) && (other.flagcarried.team != self.team)) + ctf_Handle_Capture(self, other); // other just captured the enemies flag to his base + else if((other.team != self.team) && (!other.flagcarried) && (!other.ctf_captureshielded)) + ctf_Handle_Pickup_Base(self, other); // other just stole the enemies flag + break; + + case FLAG_DROPPED: + if(other.team == self.team) + ctf_Handle_Return(self, other); // other just returned his own flag + else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect))) + ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag + break; + + case FLAG_CARRY: + dprint("Someone touched a flag even though it was being carried?\n"); + break; + + default: + dprint("Flag exists with no status?\n"); + break; // this should never happen + } +} + +void ctf_RespawnFlag(entity flag) // make sure this works +{ + if(flag.classname != "item_flag_team") { backtrace("ctf_RespawnFlag was called incorrectly."); return; } + + // reset the player (if there is one) + if((flag.owner) && (flag.owner.flagcarried == flag)) + { + WaypointSprite_Kill(flag.wps_flagcarrier); + flag.owner.flagcarried = world; + + if(flag.speedrunning) + ctf_FakeTimeLimit(flag.owner, -1); + } + + // reset the flag + setattachment(flag, world, ""); + setorigin(flag, flag.dropped_origin); // replace with flag.ctf_spawnorigin + flag.movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS); + flag.takedamage = DAMAGE_NO; + flag.solid = SOLID_TRIGGER; + flag.velocity = '0 0 0'; + flag.angles = flag.mangle; + flag.ctf_status = FLAG_BASE; + flag.flags = FL_ITEM; + flag.owner = world; +} + void ctf_Reset() { if(self.owner) @@ -381,7 +619,6 @@ void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag if(!flag.noise2) { flag.noise2 = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag if(!flag.noise3) { flag.noise3 = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match. if(!flag.noise4) { flag.noise4 = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_dropped.wav"); } - //if(!flag.noise5) { flag.noise5 = "ctf/flag_touch.wav"; } // precache precache_sound(flag.noise); @@ -389,7 +626,6 @@ void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag precache_sound(flag.noise2); precache_sound(flag.noise3); precache_sound(flag.noise4); - //precache_sound(flag.noise5); precache_model(flag.model); precache_model("models/ctf/shield.md3"); precache_model("models/ctf/shockwavetransring.md3"); @@ -407,264 +643,22 @@ void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag ctf_CaptureShield_Spawn(flag); } -void ctf_RespawnFlag(entity flag) // todo: re-write this -{ - //if((self) && (!flag) { flag = self } - if(flag.classname != "item_flag_team") { backtrace("ctf_RespawnFlag was called incorrectly."); return; } - - if(flag.owner) - if(flag.owner.flagcarried == flag) - { - WaypointSprite_DetachCarrier(flag.owner); - flag.owner.flagcarried = world; - - if(flag.speedrunning) - ctf_FakeTimeLimit(flag.owner, -1); - } - flag.owner = world; - - if(flag.waypointsprite_attachedforcarrier) - WaypointSprite_DetachCarrier(flag); - - setattachment(flag, world, ""); - flag.damageforcescale = 0; - flag.takedamage = DAMAGE_NO; - flag.movetype = MOVETYPE_NONE; - if(!flag.noalign) - flag.movetype = MOVETYPE_TOSS; - flag.velocity = '0 0 0'; - flag.solid = SOLID_TRIGGER; - // TODO: play a sound here - setorigin(flag, flag.dropped_origin); - flag.angles = flag.mangle; - flag.ctf_status = FLAG_BASE; - flag.owner = world; - flag.flags = FL_ITEM; // clear FL_ONGROUND and any other junk // there shouldn't be any "junk" set on this... look into it and make sure it's kept clean. -} - -void ctf_FlagThink() // todo: re-write this -{ - local entity e; - - self.nextthink = time + 0.1; - - // sorry, we have to reset the flag size if it got squished by something - if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) - { - // if we can grow back, grow back - tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self); - if(!trace_startsolid) - setsize(self, FLAG_MIN, FLAG_MAX); - } - - if(self == ctf_worldflaglist) // only for the first flag - { - FOR_EACH_CLIENT(e) - ctf_CaptureShield_Update(e, 1); // release shield only - } - - if(self.speedrunning) - if(self.ctf_status == FLAG_CARRY) - { - if(self.owner) - if(ctf_captimerecord) - if(time >= self.ctf_pickuptime + ctf_captimerecord) - { - bprint("The ", self.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); - - sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE); - self.owner.impulse = 141; // returning! - - e = self; - self = self.owner; - ctf_RespawnFlag(e); - ImpulseCommands(); - self = e; - return; - } - } - - if(self.ctf_status == FLAG_BASE) - return; - - if(self.ctf_status == FLAG_DROPPED) - { - // flag fallthrough? FIXME remove this if bug is really fixed now - if(self.origin_z < -131072) - { - dprint("FLAG FALLTHROUGH just happened\n"); - self.pain_finished = 0; - } - setattachment(self, world, ""); - if(time > self.pain_finished) - { - bprint("The ", self.netname, " has returned to base\n"); - sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE); - ctf_EventLog("returned", self.team, world); - ctf_RespawnFlag(self); - } - return; - } - - e = self.owner; - if(e.classname != "player" || (e.deadflag) || (e.flagcarried != self)) - { - dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n"); - ctf_Handle_Drop(e); - return; - } -} - -void ctf_FlagTouch() -{ - if(gameover) { return; } - if(!self) { return; } - if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) - { // The flag fell off the map, respawn it since players can't get to it - //ctf_RespawnFlag(self); - return; - } - if(other.deadflag != DEAD_NO) { return; } - if(other.classname != "player") - { // The flag just touched an object, most likely the world - pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1); - sound(self, CHAN_AUTO, "keepaway/touch.wav", VOL_BASE, ATTN_NORM); - return; - } - else if(self.wait > time) { return; } - - switch(self.ctf_status) - { - case FLAG_BASE: - if((other.team == self.team) && (other.flagcarried) && (other.flagcarried.team != self.team)) - ctf_Handle_Capture(self, other); // other just captured the enemies flag to his base - else if((other.team != self.team) && (!other.flagcarried) && (!other.ctf_captureshielded)) - ctf_Handle_Pickup_Base(self, other); // other just stole the enemies flag - break; - - case FLAG_DROPPED: - if(other.team == self.team) - ctf_Handle_Return(self, other); // other just returned his own flag - else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect))) - ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag - break; - - case FLAG_CARRY: - default: - dprint("Someone touched a flag even though it was being carried? wtf?\n"); - break; // this should never happen - } -} - - -// ======================= -// CaptureShield Functions -// ======================= - -float ctf_CaptureShield_CheckStatus(entity p) // check to see -{ - float s, se; - entity e; - float players_worseeq, players_total; - - if(ctf_captureshield_max_ratio <= 0) - return FALSE; - - s = PlayerScore_Add(p, SP_SCORE, 0); - if(s >= -ctf_captureshield_min_negscore) - return FALSE; - - players_total = players_worseeq = 0; - FOR_EACH_PLAYER(e) - { - if(e.team != p.team) - continue; - se = PlayerScore_Add(e, SP_SCORE, 0); - if(se <= s) - ++players_worseeq; - ++players_total; - } - - // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse - // use this rule here - - if(players_worseeq >= players_total * ctf_captureshield_max_ratio) - return FALSE; - - return TRUE; -} - -void ctf_CaptureShield_Update(entity player, float wanted_status) -{ - float updated_status = ctf_CaptureShield_CheckStatus(player); - if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only - { - if(updated_status) // TODO csqc notifier for this // Samual: How? - centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again."); - else - centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed."); - - player.ctf_captureshielded = updated_status; - } -} - -float ctf_CaptureShield_Customize() -{ - if not(other.ctf_captureshielded) - return FALSE; - if(self.team == other.team) - return FALSE; - return TRUE; -} - -void ctf_CaptureShield_Touch() -{ - if not(other.ctf_captureshielded) - return; - if(self.team == other.team) - return; - vector mymid; - vector othermid; - mymid = (self.absmin + self.absmax) * 0.5; - othermid = (other.absmin + other.absmax) * 0.5; - Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force); - centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again."); -} - -void ctf_CaptureShield_Spawn(entity flag) -{ - entity e; - e = spawn(); - e.enemy = self; - e.team = self.team; - e.touch = ctf_CaptureShield_Touch; - e.customizeentityforclient = ctf_CaptureShield_Customize; - e.classname = "ctf_captureshield"; - e.effects = EF_ADDITIVE; - e.movetype = MOVETYPE_NOCLIP; - e.solid = SOLID_TRIGGER; - e.avelocity = '7 0 11'; - setorigin(e, self.origin); - setmodel(e, "models/ctf/shield.md3"); - e.scale = 0.5; - setsize(e, e.scale * e.mins, e.scale * e.maxs); -} - // ============== // Hook Functions // ============== +// g_ctf_ignore_frags + MUTATOR_HOOKFUNCTION(ctf_RemovePlayer) { - if(self.flagcarried) { ctf_Handle_Drop(self); } // figure this out - + if(self.flagcarried) { ctf_Handle_Drop(self); } return 0; } MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink) { - local entity flag; + entity flag; // initially clear items so they can be set as necessary later. self.items &~= (IT_RED_FLAG_CARRYING | IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST @@ -677,7 +671,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink) // scan through all the flags and notify the client about them for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) { - if(flag.ctf_status == FLAG_CARRY) + if(flag.ctf_status == FLAG_CARRY) if(flag.owner == self) self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag else @@ -692,6 +686,30 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink) return 0; } +MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc +{ /* + if(frag_attacker.flagcarried) // if the attacker is a flagcarrier + { + if(frag_target == frag_attacker) // damage done to yourself + { + frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor; + frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor; + } + else // damage done to noncarriers + { + frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor; + frag_force *= autocvar_g_ctf_flagcarrier_forcefactor; + } + }*/ + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill) +{ + frag_score = 0; // no frags counted in keepaway + return (g_ctf_ignore_frags); // you deceptive little bugger ;3 This needs to be true in order for this function to even count. +} + // ========== // Spawnfuncs @@ -797,7 +815,7 @@ void spawnfunc_ctf_team() // code from here on is just to support maps that don't have flag and team entities void ctf_SpawnTeam (string teamname, float teamcolor) { - local entity oldself; + entity oldself; oldself = self; self = spawn(); self.classname = "ctf_team"; @@ -832,6 +850,7 @@ void ctf_Initialize() ScoreRules_ctf(); + // does it really need to be delayed? todo: Find out with a map that is broken. ctf_DelayedInit(); //InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE); } @@ -842,9 +861,9 @@ MUTATOR_DEFINITION(gamemode_ctf) MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDies, ctf_RemovePlayer, CBC_ORDER_ANY); - //MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY); + MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY); - //MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY); //MUTATOR_HOOK(PlayerPowerups, ctf_PlayerPowerups, CBC_ORDER_ANY); MUTATOR_ONADD