X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fgamemode_keepaway.qc;h=8acb81fb8bf1c2b334b4d0a6ff767db8b19a69c9;hp=27fb396ad2c7f86867b94296796cfa6d53885740;hb=7eb1015823c7b86bd36ad10be79701239e695dec;hpb=7c62768eab4fee3b2b0281afded2d17abd246da4 diff --git a/qcsrc/server/mutators/gamemode_keepaway.qc b/qcsrc/server/mutators/gamemode_keepaway.qc index 27fb396ad2..8acb81fb8b 100644 --- a/qcsrc/server/mutators/gamemode_keepaway.qc +++ b/qcsrc/server/mutators/gamemode_keepaway.qc @@ -1,54 +1,60 @@ void ka_SpawnBall(void); -void ka_TouchEvent(entity); +void ka_TouchEvent(void); void ka_RespawnBall(void); +void ka_DropEvent(entity); -void ka_Initialize() +void ka_Initialize() // run at the start of a match, initiates game mode { if(!g_keepaway) return; precache_sound("keepaway/pickedup.wav"); precache_sound("keepaway/dropped.wav"); - - entity e; - e = spawn(); - e.think = ka_SpawnBall; - e.nextthink = time; + precache_sound("keepaway/respawn.wav"); + precache_sound("keepaway/touch.wav"); + + ScoreRules_keepaway(); + ka_SpawnBall(); } -void ka_SpawnBall() // self = the ball +void ka_Reset() // used to clear the ballcarrier whenever the match switches from warmup to normal { - if(!g_keepaway) { - remove(self); - return; - } - if (!self.model) { - self.model = "models/orbs/orbblue.md3"; - self.scale = 1; - } + if(self.owner) + if(self.owner.classname == "player") + ka_DropEvent(self.owner); - precache_model(self.model); - setmodel(self, self.model); - setsize(self, BALL_MINS, BALL_MAXS); - ball_scale = self.scale; - self.classname = "keepawayball"; - self.damageforcescale = cvar("g_keepawayball_damageforcescale"); - self.effects = self.effects | EF_FULLBRIGHT; - self.movetype = MOVETYPE_BOUNCE; - self.touch = ka_TouchEvent; - self.think = ka_RespawnBall; - self.nextthink = time; - self.flags = FL_ITEM; - //self.reset = ka_Reset; - self.owner = world; + ka_RespawnBall(); +} + +void ka_SpawnBall() // loads various values for the ball +{ + if(!g_keepaway) { return; } - // todo: Waypoints and radar - WaypointSprite_AttachCarrier("nb-ball", self); - //bprint("^4ka_SpawnBall was just called!\n"); + entity e; + e = spawn(); + e.model = "models/orbs/orbblue.md3"; + e.scale = 1; + precache_model(e.model); + setmodel(e, e.model); + setsize(e, BALL_MINS, BALL_MAXS); + e.classname = "keepawayball"; + e.damageforcescale = cvar("g_keepawayball_damageforcescale"); + e.takedamage = DAMAGE_YES; + e.glow_color = cvar("g_keepawayball_trail_color"); + e.glow_trail = TRUE; + e.movetype = MOVETYPE_BOUNCE; + e.touch = ka_TouchEvent; + e.flags = FL_ITEM; + e.reset = ka_Reset; + e.owner = world; + + InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So. } -void ka_RespawnBall() +void ka_RespawnBall() // runs whenever the ball needs to be relocated { + vector oldballorigin = self.origin; + if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256)) { makevectors(self.angles); @@ -56,222 +62,208 @@ void ka_RespawnBall() self.velocity = '0 0 200'; self.angles = '0 0 0'; self.solid = SOLID_TRIGGER; - //self.touch = ka_TouchEvent; self.think = ka_RespawnBall; self.nextthink = time + cvar("g_keepawayball_respawntime"); + + pointparticles(particleeffectnum("electro_combo"), oldballorigin, '0 0 0', 1); + pointparticles(particleeffectnum("electro_combo"), self.origin, '0 0 0', 1); + + WaypointSprite_Spawn("ka-ball", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attachedforcarrier, FALSE); + WaypointSprite_UpdateTeamRadar(self.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1'); + WaypointSprite_Ping(self.waypointsprite_attachedforcarrier); + + sound(self, CHAN_AUTO, "keepaway/respawn.wav", VOL_BASE, ATTN_NONE); } else { - // sorry, can't spawn, better luck next frame - self.think = ka_RespawnBall; - self.nextthink = time; + ka_RespawnBall(); // finding a location failed, retry } - //bprint("^4ka_RespawnBall was just called!\n"); } -void ka_TouchEvent(entity plyr) +void ka_TouchEvent() // runs any time that the ball comes in contact with something { + if(!self) { return; } if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) - { - self.think = ka_SpawnBall; - self.nextthink = time; + { // The ball fell off the map, respawn it since players can't get to it + ka_RespawnBall(); return; } - if(!plyr) - return; - if(!self) - return; - if(other.classname != "player" || other.health < 1) - return; - if(self.wait > time) - return; - //if(time > self.ctf_droptime + cvar("g_keepawayball_respawntime")) - // return; + if(other.deadflag != DEAD_NO) { return; } + if(other.classname != "player") + { // The ball 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; + } + if(self.wait > time) { return; } + // attach the ball to the player self.owner = other; - other.kaballcarried = self; + other.ballcarried = self; setattachment(self, other, ""); setorigin(self, BALL_ATTACHORG); + // make the ball invisible/unable to do anything self.velocity = '0 0 0'; self.movetype = MOVETYPE_NONE; self.touch = SUB_Null; - self.alpha = 0.01; - + self.effects |= EF_NODRAW; self.think = SUB_Null; self.nextthink = 0; + self.takedamage = DAMAGE_NO; - self.glow_color = cvar("g_keepawayball_trail_color"); - self.glow_trail = TRUE; - plyr.effects |= 8; - plyr.alpha = 0.6; + // apply effects to player + other.glow_color = cvar("g_keepawayball_trail_color"); + other.glow_trail = TRUE; + other.effects |= 8; + other.alpha = 0.6; + // messages and prints bprint(other.netname, "^7 has picked up the ball!\n"); WriteByte(MSG_BROADCAST, SVC_CENTERPRINT); WriteString(MSG_BROADCAST, strcat("\n\n", other.netname, "^7 has picked up the ball!\n")); - sound(self.owner, CHAN_AUTO, "keepaway/pickedup.wav", VOL_BASE, ATTN_NORM); + sound(self.owner, CHAN_AUTO, "keepaway/pickedup.wav", VOL_BASE, ATTN_NONE); + // scoring PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1); - // todo: Waypoints and radar + // waypoints + WaypointSprite_AttachCarrier("ka-ballcarrier", other); + WaypointSprite_UpdateRule(other.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT); + WaypointSprite_UpdateTeamRadar(other.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 0 0'); + WaypointSprite_Ping(other.waypointsprite_attachedforcarrier); + WaypointSprite_Kill(self.waypointsprite_attachedforcarrier); } -MUTATOR_HOOKFUNCTION(ka_RemovePlayer) +void ka_DropEvent(entity plyr) // runs any time that a player is supposed to lose the ball { - if(self.kaballcarried) { - entity ball; - ball = self.kaballcarried; + entity ball; + ball = plyr.ballcarried; - setattachment(ball, world, ""); - ball.movetype = MOVETYPE_BOUNCE; - ball.solid = SOLID_TRIGGER; - ball.wait = time + 1; - ball.ctf_droptime = time; - ball.think = ka_SpawnBall; - ball.nextthink = time + cvar("g_keepawayball_respawntime"); - ball.touch = ka_TouchEvent; - self.effects = EF_LOWPRECISION; - self.alpha = 1.0; - ball.alpha = 1.0; - setorigin(ball, self.origin + '0 0 10'); // FIX ME: If a player becomes spectator, the hook function is given AFTER this happens, which means the origin given is after they already moved to another position, not where they died! - ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom(); + if(!ball) { return; } - bprint(self.netname, "^7 has dropped the ball!\n"); - WriteByte(MSG_BROADCAST, SVC_CENTERPRINT); - WriteString(MSG_BROADCAST, strcat("\n\n", self.netname, "^7 has dropped the ball!\n")); - sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM); - - PlayerScore_Add(self, SP_KEEPAWAY_DROPS, 1); - - // todo - WaypointSprite_AttachCarrier("nb-ball", ball); - WaypointSprite_Kill(self.waypointsprite_attachedforcarrier); - - ball.owner.kaballcarried = world; - ball.owner = world; - } - return 1; -} - -/* -void ka_DropEvent(entity plyr, entity ball) -{ + // reset the ball setattachment(ball, world, ""); ball.movetype = MOVETYPE_BOUNCE; ball.solid = SOLID_TRIGGER; - ball.wait = time + 1; - ball.ctf_droptime = time; - ball.think = ka_SpawnBall; + ball.wait = time + 1; + ball.think = ka_RespawnBall; ball.nextthink = time + cvar("g_keepawayball_respawntime"); ball.touch = ka_TouchEvent; - plyr.effects = EF_LOWPRECISION; - plyr.alpha = 1.0; - ball.alpha = 1.0; + ball.takedamage = DAMAGE_YES; + ball.effects &~= EF_NODRAW; setorigin(ball, plyr.origin + '0 0 10'); ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom(); + ball.owner.ballcarried = world; + ball.owner = world; + + // reset the player effects + plyr.effects &~= 8; + plyr.alpha = 1.0; + plyr.glow_trail = FALSE; + // messages and prints bprint(plyr.netname, "^7 has dropped the ball!\n"); WriteByte(MSG_BROADCAST, SVC_CENTERPRINT); WriteString(MSG_BROADCAST, strcat("\n\n", plyr.netname, "^7 has dropped the ball!\n")); - sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM); + sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE); + // scoring PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1); - // todo - //WaypointSprite_AttachCarrier("ka-ball", ball); - //WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier); - - ball.owner.kaballcarried = world; - ball.owner = world; + // waypoints + WaypointSprite_Spawn("ka-ball", 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, FALSE); + WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT); + WaypointSprite_UpdateTeamRadar(ball.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1'); + WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier); + WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier); } - -void ka_CheckWinner() +MUTATOR_HOOKFUNCTION(ka_RemovePlayer) { - + if(self.ballcarried) { ka_DropEvent(self); } // a player with the ball has left the match, drop it + return 0; } -MUTATOR_HOOKFUNCTION(ka_PlayerDies) +MUTATOR_HOOKFUNCTION(ka_Scoring) { - float i; - entity e; - - float temp_tag_players_count; - temp_tag_players_count = tag_players_count; - - if(frag_target.tagcolor == frag_target.tagcolor_original) // if this is the first time we die... (our tagcolor remained unchanged) + if((frag_attacker != frag_target) && (frag_attacker.classname == "player")) { - for(i = 0; i < temp_tag_players_count; ++i) // check other players... - { - e = tag_players[i]; - if(e == world) // empty slot, skip to next - { - if(temp_tag_players_count < TAGCOLOR_MAX - 1) // just in case - ++temp_tag_players_count; - continue; - } - - if(e.tagcolor == frag_target.tagcolor_original) // and see if they have our original tag color - { - tag_GetFragAttackers_ColorOwner(); - centerprint(e, strcat("^1Your master ^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n")); - e.tagcolor = frag_attacker.tagcolor; // if so, remove it, our tag color has now "died out" from this round and we can not win anymore. The attacker will "summon" all of our previously fragged targets, and also us. - setcolor(e, 16 * e.tagcolor + e.tagcolor); - } + if(frag_target.ballcarried) { // add to amount of times killing carrier + PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1); + if(cvar("g_keepaway_bckillscore")) // add bckills to the score + PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1); } - } - else - { - frag_target.tagcolor = frag_attacker.tagcolor; - setcolor(frag_target, 16 * frag_target.tagcolor + frag_target.tagcolor); - } - - tag_GetFragAttackers_ColorOwner(); - - if(color_owner_self) - color_owner_green = "^2your own"; - centerprint(frag_attacker, strcat("^2You tagged ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n")); - - if(color_owner_self) - color_owner_red = "^1their own"; - centerprint(frag_target, strcat("^1You were tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n")); - bprint("^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"); - - frag_target.health = cvar("g_balance_health_start"); // "respawn" the player :P + else if(!frag_attacker.ballcarried) + if(cvar("g_keepaway_noncarrier_warn")) + centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!"); - tag_CheckWinner(); + if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier + PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1); + } - return 1; + if(self.ballcarried) { ka_DropEvent(self); } // a player with the ball has died, drop it + return 0; } -MUTATOR_HOOKFUNCTION(tag_RemovePlayer) +MUTATOR_HOOKFUNCTION(ka_GiveFragsForKill) { - - return 1; + frag_score = 0; // no frags counted in keepaway + return 0; } -MUTATOR_HOOKFUNCTION(tag_GiveFragsForKill) +MUTATOR_HOOKFUNCTION(ka_PlayerPreThink) { - frag_score = 0; // no frags counted in Tag, maybe later (TODO) - return 1; + self.items &~= IT_KEY1; + + if(self.ballcarried) + self.items |= IT_KEY1; + + if(self.BUTTON_USE) + if(self.ballcarried) { ka_DropEvent(self); } // drop the ball if the player presses the use button + + return 0; } -MUTATOR_HOOKFUNCTION(tag_PlayerPreThink) +MUTATOR_HOOKFUNCTION(ka_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc { - setcolor(self, 16 * self.tagcolor + self.tagcolor); // prevent cheating by changing player colors - return 1; + if(frag_attacker.items & IT_KEY1) // if the attacker is a ballcarrier + { + if(frag_target == frag_attacker) // damage done to yourself + { + frag_damage *= cvar("g_keepaway_ballcarrier_selfdamage"); + frag_force *= cvar("g_keepaway_ballcarrier_selfforce"); + } + else // damage done to noncarriers + { + frag_damage *= cvar("g_keepaway_ballcarrier_damage"); + frag_force *= cvar("g_keepaway_ballcarrier_force"); + } + } + else if not(frag_target.items & IT_KEY1) // if the target is a noncarrier + { + if(frag_target == frag_attacker) // damage done to yourself + { + frag_damage *= cvar("g_keepaway_noncarrier_selfdamage"); + frag_force *= cvar("g_keepaway_noncarrier_selfforce"); + } + else // damage done to other noncarriers + { + frag_damage *= cvar("g_keepaway_noncarrier_damage"); + frag_force *= cvar("g_keepaway_noncarrier_force"); + } + } + return 0; } -*/ - MUTATOR_DEFINITION(gamemode_keepaway) { MUTATOR_HOOK(MakePlayerObserver, ka_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, ka_RemovePlayer, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerDies, ka_RemovePlayer, CBC_ORDER_ANY); - //MUTATOR_HOOK(PlayerSpawn, ka_PlayerSpawn, CBC_ORDER_ANY); - //MUTATOR_HOOK(GiveFragsForKill, ka_GiveFragsForKill, CBC_ORDER_FIRST); - //MUTATOR_HOOK(PlayerPreThink, ka_PlayerPreThink, CBC_ORDER_FIRST); + MUTATOR_HOOK(PlayerDies, ka_Scoring, CBC_ORDER_ANY); + MUTATOR_HOOK(GiveFragsForKill, ka_GiveFragsForKill, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerPreThink, ka_PlayerPreThink, CBC_ORDER_FIRST); + MUTATOR_HOOK(PlayerDamage_Calculate, ka_PlayerDamage, CBC_ORDER_ANY); MUTATOR_ONADD { @@ -288,5 +280,4 @@ MUTATOR_DEFINITION(gamemode_keepaway) } return 0; -} - +} \ No newline at end of file