.float next_take_time; // the next time a player can pick up a flag (time + blah) /// I used this, in part, to fix the looping score bug. - avirox //float FLAGSCORE_PICKUP = 1; //float FLAGSCORE_RETURN = 5; // returned by owner team //float FLAGSCORE_RETURNROGUE = 10; // returned by rogue team //float FLAGSCORE_CAPTURE = 5; //float FLAGSCORE_CAPTURE_TEAM = 20; void() FlagThink; void() FlagTouch; void() place_flag = { if(!self.t_width) self.t_width = 0.1; // frame animation rate if(!self.t_length) self.t_length = 119; // maximum frame self.mdl = self.model; self.flags = FL_ITEM; self.solid = SOLID_TRIGGER; self.movetype = MOVETYPE_TOSS; self.velocity = '0 0 0'; self.origin_z = self.origin_z + 6; self.think = FlagThink; self.touch = FlagTouch; self.nextthink = time + 0.1; self.cnt = FLAG_BASE; self.mangle = self.angles; //self.effects = self.effects | EF_DIMLIGHT; if (!droptofloor(0, 0)) { dprint("Flag fell out of level at ", vtos(self.origin), "\n"); remove(self); return; } self.oldorigin = self.origin; }; void LogCTF(string mode, float flagteam, entity actor) { string s; if(!cvar("sv_eventlog")) return; s = strcat(":ctf:", mode); s = strcat(s, ":", ftos(flagteam)); if(actor != world) s = strcat(s, ":", ftos(actor.playerid)); GameLogEcho(s, FALSE); } void(entity e) RegenFlag = { e.movetype = MOVETYPE_TOSS; e.solid = SOLID_TRIGGER; // TODO: play a sound here setorigin(e, e.oldorigin); e.angles = e.mangle; e.cnt = FLAG_BASE; e.owner = world; e.flags = FL_ITEM; // clear FL_ONGROUND and any other junk }; void(entity e) ReturnFlag = { if (e.owner) if (e.owner.flagcarried == e) e.owner.flagcarried = world; e.owner = world; RegenFlag(e); }; void(entity e) DropFlag = { local entity p; if (!e.owner) { dprint("FLAG: drop - no owner?!?!\n"); return; } p = e.owner; if (p.flagcarried != e) { dprint("FLAG: drop - owner is not carrying this flag??\n"); return; } bprint(strcat(p.netname, "^7 lost the ", e.netname, "\n")); if (p.flagcarried == e) p.flagcarried = world; e.owner = world; e.flags = FL_ITEM; // clear FL_ONGROUND and any other junk e.solid = SOLID_TRIGGER; e.movetype = MOVETYPE_TOSS; // setsize(e, '-16 -16 0', '16 16 74'); setorigin(e, p.origin - '0 0 24'); e.cnt = FLAG_DROPPED; e.velocity = '0 0 300'; e.pain_finished = time + cvar("g_ctf_flag_returntime");//30; }; void AnimateFlag() { if(self.delay > time) return; self.delay = time + self.t_width; if(self.nextthink > self.delay) self.nextthink = self.delay; self.frame = self.frame + 1; if(self.frame > self.t_length) self.frame = 0; } void() FlagThink = { local entity e; local vector v; local float f; self.nextthink = time + 0.1; AnimateFlag(); if (self.cnt == FLAG_BASE) return; if (self.cnt == FLAG_DROPPED) { if (time > self.pain_finished) { bprint(strcat("The ", self.netname, " has returned to base\n")); sound (e, CHAN_AUTO, self.noise3, 1, ATTN_NONE); LogCTF("returned", self.team, world); ReturnFlag(self); } return; } e = self.owner; if (e.classname != "player" || (e.deadflag) || (e.flagcarried != self)) { DropFlag(self); LogCTF("dropped", self.team, e); return; } // borrowed from threewave CTF, because it would be way too much work makevectors (e.angles); v = v_forward; v_z = 0 - v_z; // reverse z f = 14; /* if (e.frame >= 29 && e.frame <= 40) { if (e.frame >= 29 && e.frame <= 34) { //axpain if (e.frame == 29) f = f + 2; else if (e.frame == 30) f = f + 8; else if (e.frame == 31) f = f + 12; else if (e.frame == 32) f = f + 11; else if (e.frame == 33) f = f + 10; else if (e.frame == 34) f = f + 4; } else if (e.frame >= 35 && e.frame <= 40) { // pain if (e.frame == 35) f = f + 2; else if (e.frame == 36) f = f + 10; else if (e.frame == 37) f = f + 10; else if (e.frame == 38) f = f + 8; else if (e.frame == 39) f = f + 4; else if (e.frame == 40) f = f + 2; } } else if (e.frame >= 103 && e.frame <= 118) { if (e.frame >= 103 && e.frame <= 104) f = f + 6; //nailattack else if (e.frame >= 105 && e.frame <= 106) f = f + 6; //light else if (e.frame >= 107 && e.frame <= 112) f = f + 7; //rocketattack else if (e.frame >= 112 && e.frame <= 118) f = f + 7; //shotattack } */ self.angles = e.angles + '0 0 -45'; setorigin (self, e.origin + '0 0 0' - f*v + v_right * 22); self.nextthink = time + 0.01; }; float flagcaptimerecord; .float flagpickuptime; void() FlagTouch = { if(gameover) return; local float t; local entity head; local entity player; if (other.classname != "player") return; if (other.health < 1) // ignore dead players return; if (self.cnt == FLAG_CARRY) return; if (self.cnt == FLAG_BASE) if (other.team == self.team) if (other.flagcarried) // he's got a flag if (other.flagcarried.team != self.team) // capture { if (other.flagcarried == world) { return; } t = time - other.flagcarried.flagpickuptime; if (flagcaptimerecord == 0) { bprint(other.netname, "^7 captured the ", other.flagcarried.netname, " in ", ftos(t), " seconds\n"); flagcaptimerecord = t; } else if (t < flagcaptimerecord) { bprint(other.netname, "^7 captured the ", other.flagcarried.netname, " in ", ftos(t), ", breaking the previous record of ", ftos(flagcaptimerecord), " seconds\n"); flagcaptimerecord = t; } else { bprint(other.netname, "^7 captured the ", other.flagcarried.netname, " in ", ftos(t), ", failing to break the previous record of ", ftos(flagcaptimerecord), " seconds\n"); } LogCTF("capture", other.flagcarried.team, other); other.frags = other.frags + cvar("g_ctf_flagscore_capture");//FLAGSCORE_CAPTURE; head = find(head, classname, "player"); while (head) { if (head.team == self.team) head.frags = head.frags + cvar("g_ctf_flagscore_capture_team");//FLAGSCORE_CAPTURE_TEAM; head = find(head, classname, "player"); } sound (self, CHAN_AUTO, self.noise2, 1, ATTN_NONE); RegenFlag (other.flagcarried); other.flagcarried = world; other.next_take_time = time + 1; } if (self.cnt == FLAG_BASE) if (other.team == 5 || other.team == 14) // only red and blue team can steal flags if (other.team != self.team) if (!other.flagcarried) { if (other.next_take_time > time) return; // pick up self.flagpickuptime = time; // used for timing runs self.solid = SOLID_NOT; setorigin(self, self.origin); // relink self.owner = other; other.flagcarried = self; self.cnt = FLAG_CARRY; bprint(other.netname, "^7 got the ", self.netname, "\n"); other.frags = other.frags + cvar("g_ctf_flagscore_pickup");//FLAGSCORE_PICKUP; LogCTF("steal", self.team, other); sound (self, CHAN_AUTO, self.noise, 1, ATTN_NONE); player = find(world, classname, "player"); while(player) { if(player.team == self.team) centerprint(player, "The enemy got your flag! Retrieve it!"); player = find(player, classname, "player"); } return; } if (self.cnt == FLAG_DROPPED) { self.flags = FL_ITEM; // clear FL_ONGROUND and any other junk if (other.team == self.team || (other.team != 5 && other.team != 14)) { // return flag bprint(other.netname, "^7 returned the ", self.netname, "\n"); if (other.team == 5 || other.team == 14) other.frags = other.frags + cvar("g_ctf_flagscore_return");//FLAGSCORE_RETURN; else other.frags = other.frags + cvar("g_ctf_flagscore_return_rogue");//FLAGSCORE_RETURNROGUE; LogCTF("return", self.team, other); sound (self, CHAN_AUTO, self.noise1, 1, ATTN_NONE); ReturnFlag(self); } else if (!other.flagcarried) { // pick up self.solid = SOLID_NOT; setorigin(self, self.origin); // relink self.owner = other; other.flagcarried = self; self.cnt = FLAG_CARRY; bprint(other.netname, "^7 picked up the ", self.netname, "\n"); other.frags = other.frags + cvar("g_ctf_flagscore_pickup");//FLAGSCORE_PICKUP; LogCTF("pickup", self.team, other); sound (self, CHAN_AUTO, self.noise, 1, ATTN_NONE); player = find(world, classname, "player"); while(player) { if(player.team == self.team) centerprint(player, "The enemy got your flag! Retrieve it!"); player = find(player, classname, "player"); } } } }; /*QUAKED info_player_team1 (1 0 0) (-16 -16 -24) (16 16 24) CTF Starting point for a player in team one (Red). Keys: "angle" viewing angle when spawning */ void() info_player_team1 = { self.classname = "info_player_deathmatch"; self.team = 5; // red relocate_spawnpoint(); }; //self.team = 4;self.classname = "info_player_start";info_player_start();}; /*QUAKED info_player_team2 (1 0 0) (-16 -16 -24) (16 16 24) CTF Starting point for a player in team two (Blue). Keys: "angle" viewing angle when spawning */ void() info_player_team2 = { self.classname = "info_player_deathmatch"; self.team = 14; // blue relocate_spawnpoint(); }; //self.team = 13;self.classname = "info_player_start";info_player_start();}; /*QUAKED info_player_team3 (1 0 0) (-16 -16 -24) (16 16 24) CTF Starting point for a player in team three (Magenta). Keys: "angle" viewing angle when spawning */ void() info_player_team3 = { self.classname = "info_player_deathmatch"; self.team = 10; // purple relocate_spawnpoint(); }; /*QUAKED info_player_team4 (1 0 0) (-16 -16 -24) (16 16 24) CTF Starting point for a player in team four (Yellow). Keys: "angle" viewing angle when spawning */ void() info_player_team4 = { self.classname = "info_player_deathmatch"; self.team = 13; // yellow relocate_spawnpoint(); }; /*QUAKED item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37) CTF flag for team one (Red). Multiple are allowed. Keys: "angle" Angle the flag will point (minus 90 degrees) "model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3) "noise" sound played when flag is picked up (default ctf/take.wav) "noise1" sound played when flag is returned by a teammate (default ctf/return.wav) "noise2" sound played when flag is captured (default ctf/capture.wav) "noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav) */ void() item_flag_team1 = { if (!cvar("g_ctf")) return; //if(!cvar("teamplay")) // cvar_set("teamplay", "3"); self.team = 5; // color 4 team (red) self.items = IT_KEY2; // gold key (redish enough) self.netname = "^1RED^7 flag"; self.target = "###item###"; self.skin = 0; if (!self.model) self.model = "models/ctf/flag_red.md3"; if (!self.noise) self.noise = "ctf/take.wav"; if (!self.noise1) self.noise1 = "ctf/return.wav"; if (!self.noise2) self.noise2 = "ctf/capture.wav"; if (!self.noise3) self.noise3 = "ctf/respawn.wav"; precache_model (self.model); setmodel (self, self.model); precache_sound (self.noise); precache_sound (self.noise1); precache_sound (self.noise2); precache_sound (self.noise3); setsize(self, '-16 -16 -37', '16 16 37'); setorigin(self, self.origin + '0 0 37'); self.nextthink = time + 0.2; // start after doors etc self.think = place_flag; if(!self.scale) self.scale = 0.6; //if(!self.glow_size) // self.glow_size = 50; self.effects = self.effects | EF_FULLBRIGHT | EF_LOWPRECISION; }; /*QUAKED item_flag_team2 (0 0.5 0.8) (-48 -48 -24) (48 48 64) CTF flag for team two (Blue). Multiple are allowed. Keys: "angle" Angle the flag will point (minus 90 degrees) */ void() item_flag_team2 = { if (!cvar("g_ctf")) return; //if(!cvar("teamplay")) // cvar_set("teamplay", "3"); self.team = 14; // color 13 team (blue) self.items = IT_KEY1; // silver key (bluish enough) self.netname = "^4BLUE^7 flag"; self.target = "###item###"; self.skin = 0; if (!self.model) self.model = "models/ctf/flag_blue.md3"; if (!self.noise) self.noise = "ctf/take.wav"; if (!self.noise1) self.noise1 = "ctf/return.wav"; if (!self.noise2) self.noise2 = "ctf/capture.wav"; if (!self.noise3) self.noise3 = "ctf/respawn.wav"; precache_model (self.model); setmodel (self, self.model); precache_sound (self.noise); precache_sound (self.noise1); precache_sound (self.noise2); precache_sound (self.noise3); setsize(self, '-16 -16 -37', '16 16 37'); setorigin(self, self.origin + '0 0 37'); self.nextthink = time + 0.2; // start after doors etc self.think = place_flag; if(!self.scale) self.scale = 0.6; //if(!self.glow_size) // self.glow_size = 50; self.effects = self.effects | EF_FULLBRIGHT | EF_LOWPRECISION; }; /*QUAKED ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32) Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map. Note: If you use ctf_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too. Keys: "netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc) "cnt" Scoreboard color of the team (for example 4 is red and 13 is blue) */ void() ctf_team = { self.classname = "ctf_team"; self.team = self.cnt + 1; }; // code from here on is just to support maps that don't have control point and team entities void ctf_spawnteam (string teamname, float teamcolor) { local entity oldself; oldself = self; self = spawn(); self.classname = "ctf_team"; self.netname = teamname; self.cnt = teamcolor; ctf_team(); self = oldself; }; // spawn some default teams if the map is not set up for ctf void() ctf_spawnteams = { float numteams; numteams = 2;//cvar("g_ctf_default_teams"); ctf_spawnteam("Red", 4); ctf_spawnteam("Blue", 13); }; void() ctf_delayedinit = { self.think = SUB_Remove; self.nextthink = time; // if no teams are found, spawn defaults if (find(world, classname, "ctf_team") == world) ctf_spawnteams(); }; void() ctf_init = { local entity e; e = spawn(); e.think = ctf_delayedinit; e.nextthink = time + 0.1; };