+++ /dev/null
-void spawnfunc_func_breakable();
-void target_objective_decrease_activate();
-.entity assault_decreaser;
-.entity assault_sprite;
-
-void spawnfunc_info_player_attacker() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_1; // red, gets swapped every round
- spawnfunc_info_player_deathmatch();
-}
-
-void spawnfunc_info_player_defender() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_2; // blue, gets swapped every round
- spawnfunc_info_player_deathmatch();
-}
-
-// reset this objective. Used when spawning an objective
-// and when a new round starts
-void assault_objective_reset() {
- self.health = ASSAULT_VALUE_INACTIVE;
-}
-
-void assault_objective_use() {
- // activate objective
- self.health = 100;
- //print("^2Activated objective ", self.targetname, "=", etos(self), "\n");
- //print("Activator is ", activator.classname, "\n");
-
- entity oldself;
- oldself = self;
-
- for(self = world; (self = find(self, target, oldself.targetname)); )
- {
- if(self.classname == "target_objective_decrease")
- target_objective_decrease_activate();
- }
-
- self = oldself;
-}
-
-vector target_objective_spawn_evalfunc(entity player, entity spot, vector current)
-{
- if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE)
- return '-1 0 0';
- return current;
-}
-
-void spawnfunc_target_objective() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.classname = "target_objective";
- self.use = assault_objective_use;
- assault_objective_reset();
- self.reset = assault_objective_reset;
- self.spawn_evalfunc = target_objective_spawn_evalfunc;
-}
-
-
-// decrease the health of targeted objectives
-void assault_objective_decrease_use() {
- if(activator.team != assault_attacker_team) {
- // wrong team triggered decrease
- return;
- }
-
- if(other.assault_sprite)
- {
- WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime);
- if(other.classname == "func_assault_destructible")
- other.sprite = world;
- }
- else
- return; // already activated! cannot activate again!
-
- if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
- {
- if(self.enemy.health - self.dmg > 0.5)
- {
- PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
- self.enemy.health = self.enemy.health - self.dmg;
- }
- else
- {
- PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
- PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
- self.enemy.health = -1;
-
- entity oldself, oldactivator;
-
- oldself = self;
- self = oldself.enemy;
- if(self.message)
- {
- entity player;
- string s;
- FOR_EACH_PLAYER(player)
- {
- s = strcat(self.message, "\n");
- centerprint(player, s);
- }
- }
-
- oldactivator = activator;
- activator = oldself;
- SUB_UseTargets();
- activator = oldactivator;
- self = oldself;
- }
- }
-}
-
-void assault_setenemytoobjective()
-{
- entity objective;
- for(objective = world; (objective = find(objective, targetname, self.target)); ) {
- if(objective.classname == "target_objective") {
- if(self.enemy == world)
- self.enemy = objective;
- else
- objerror("more than one objective as target - fix the map!");
- break;
- }
- }
-
- if(self.enemy == world)
- objerror("no objective as target - fix the map!");
-}
-
-float assault_decreaser_sprite_visible(entity e)
-{
- entity decreaser;
-
- decreaser = self.assault_decreaser;
-
- if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
- return FALSE;
-
- return TRUE;
-}
-
-void target_objective_decrease_activate()
-{
- entity ent, spr;
- self.owner = world;
- for(ent = world; (ent = find(ent, target, self.targetname)); )
- {
- if(ent.assault_sprite != world)
- {
- WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
- if(ent.classname == "func_assault_destructible")
- ent.sprite = world;
- }
-
- spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE, '1 0.5 0');
- spr.assault_decreaser = self;
- spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
- spr.classname = "sprite_waypoint";
- WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
- if(ent.classname == "func_assault_destructible")
- {
- WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
- WaypointSprite_UpdateMaxHealth(spr, ent.max_health);
- WaypointSprite_UpdateHealth(spr, ent.health);
- ent.sprite = spr;
- }
- else
- WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
- }
-}
-
-void target_objective_decrease_findtarget()
-{
- assault_setenemytoobjective();
-}
-
-//=============================================================================
-
-void spawnfunc_target_objective_decrease() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
-
- self.classname = "target_objective_decrease";
-
- if(!self.dmg) {
- self.dmg = 101;
- }
- self.use = assault_objective_decrease_use;
- self.health = ASSAULT_VALUE_INACTIVE;
- self.max_health = ASSAULT_VALUE_INACTIVE;
- self.enemy = world;
-
- InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-void spawnfunc_func_assault_destructible() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.spawnflags = 3;
- self.classname = "func_assault_destructible";
- if(assault_attacker_team == NUM_TEAM_1) {
- self.team = NUM_TEAM_2;
- } else {
- self.team = NUM_TEAM_1;
- }
- spawnfunc_func_breakable();
-}
-
-void assault_wall_think() {
- if(self.enemy.health < 0) {
- self.model = "";
- self.solid = SOLID_NOT;
- } else {
- self.model = self.mdl;
- self.solid = SOLID_BSP;
- }
-
- self.nextthink = time + 0.2;
-}
-
-void spawnfunc_func_assault_wall() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.classname = "func_assault_wall";
- self.mdl = self.model;
- setmodel(self, self.mdl);
- self.solid = SOLID_BSP;
- self.think = assault_wall_think;
- self.nextthink = time;
- InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
-}
-
-
-void target_assault_roundend_reset() {
- //print("round end reset\n");
- self.cnt = self.cnt + 1; // up round counter
- self.winning = 0; // up round
-}
-
-void target_assault_roundend_use() {
- self.winning = 1; // round has been won by attackers
-}
-
-void spawnfunc_target_assault_roundend() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.winning = 0; // round not yet won by attackers
- self.classname = "target_assault_roundend";
- self.use = target_assault_roundend_use;
- self.cnt = 0; // first round
- self.reset = target_assault_roundend_reset;
-}
-
-void assault_roundstart_use() {
-
- activator = self;
- SUB_UseTargets();
-
-
-#ifdef TTURRETS_ENABLED
- entity ent, oldself;
-
- //(Re)spawn all turrets
- oldself = self;
- ent = find(world, classname, "turret_main");
- while(ent) {
- // Swap turret teams
- if(ent.team == NUM_TEAM_1)
- ent.team = NUM_TEAM_2;
- else
- ent.team = NUM_TEAM_1;
-
- self = ent;
-
- // Dubbles as teamchange
- turret_stdproc_respawn();
-
- ent = find(ent, classname, "turret_main");
- }
- self = oldself;
-#endif
-
-
-}
-
-void spawnfunc_target_assault_roundstart() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- assault_attacker_team = NUM_TEAM_1;
- self.classname = "target_assault_roundstart";
- self.use = assault_roundstart_use;
- self.reset2 = assault_roundstart_use;
- InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
-}
-
-// trigger new round
-// reset objectives, toggle spawnpoints, reset triggers, ...
-void vehicles_clearrturn();
-void vehicles_spawn();
-void assault_new_round()
-{
- entity oldself;
- //bprint("ASSAULT: new round\n");
-
- oldself = self;
- // Eject players from vehicles
- FOR_EACH_PLAYER(self)
- {
- if(self.vehicle)
- vehicles_exit(VHEF_RELESE);
- }
-
- self = findchainflags(vehicle_flags, VHF_ISVEHICLE);
- while(self)
- {
- vehicles_clearrturn();
- vehicles_spawn();
- self = self.chain;
- }
-
- self = oldself;
-
- // up round counter
- self.winning = self.winning + 1;
-
- // swap attacker/defender roles
- if(assault_attacker_team == NUM_TEAM_1) {
- assault_attacker_team = NUM_TEAM_2;
- } else {
- assault_attacker_team = NUM_TEAM_1;
- }
-
-
- entity ent;
- for(ent = world; (ent = nextent(ent)); )
- {
- if(IS_NOT_A_CLIENT(ent))
- {
- if(ent.team_saved == NUM_TEAM_1)
- ent.team_saved = NUM_TEAM_2;
- else if(ent.team_saved == NUM_TEAM_2)
- ent.team_saved = NUM_TEAM_1;
- }
- }
-
- // reset the level with a countdown
- cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
- ReadyRestart_force(); // sets game_starttime
-}
+++ /dev/null
-#define HAVOCBOT_AST_ROLE_NONE 0
-#define HAVOCBOT_AST_ROLE_DEFENSE 2
-#define HAVOCBOT_AST_ROLE_OFFENSE 4
-
-.float havocbot_role_flags;
-.float havocbot_attack_time;
-
-.void() havocbot_role;
-.void() havocbot_previous_role;
-
-void() havocbot_role_ast_defense;
-void() havocbot_role_ast_offense;
-.entity havocbot_ast_target;
-
-void(entity bot) havocbot_ast_reset_role;
-
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-void havocbot_goalrating_ast_targets(float ratingscale)
-{
- entity ad, best, wp, tod;
- float radius, found, bestvalue;
- vector p;
-
- ad = findchain(classname, "func_assault_destructible");
-
- for (; ad; ad = ad.chain)
- {
- if (ad.target == "")
- continue;
-
- if not(ad.bot_attack)
- continue;
-
- found = FALSE;
- for(tod = world; (tod = find(tod, targetname, ad.target)); )
- {
- if(tod.classname == "target_objective_decrease")
- {
- if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
- {
- // dprint(etos(ad),"\n");
- found = TRUE;
- break;
- }
- }
- }
-
- if(!found)
- {
- /// dprint("target not found\n");
- continue;
- }
- /// dprint("target #", etos(ad), " found\n");
-
-
- p = 0.5 * (ad.absmin + ad.absmax);
- // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
- // te_knightspike(p);
- // te_lightning2(world, '0 0 0', p);
-
- // Find and rate waypoints around it
- found = FALSE;
- best = world;
- bestvalue = 99999999999;
- for(radius=0; radius<1500 && !found; radius+=500)
- {
- for(wp=findradius(p, radius); wp; wp=wp.chain)
- {
- if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
- if(wp.classname=="waypoint")
- if(checkpvs(wp.origin, ad))
- {
- found = TRUE;
- if(wp.cnt<bestvalue)
- {
- best = wp;
- bestvalue = wp.cnt;
- }
- }
- }
- }
-
- if(best)
- {
- /// dprint("waypoints around target were found\n");
- // te_lightning2(world, '0 0 0', best.origin);
- // te_knightspike(best.origin);
-
- navigation_routerating(best, ratingscale, 4000);
- best.cnt += 1;
-
- self.havocbot_attack_time = 0;
-
- if(checkpvs(self.view_ofs,ad))
- if(checkpvs(self.view_ofs,best))
- {
- // dprint("increasing attack time for this target\n");
- self.havocbot_attack_time = time + 2;
- }
- }
- }
-}
-
-void havocbot_role_ast_offense()
-{
- if(self.deadflag != DEAD_NO)
- {
- self.havocbot_attack_time = 0;
- havocbot_ast_reset_role(self);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ast_reset_role(self);
- return;
- }
-
- if(self.havocbot_attack_time>time)
- return;
-
- if (self.bot_strategytime < time)
- {
- navigation_goalrating_start();
- havocbot_goalrating_enemyplayers(20000, self.origin, 650);
- havocbot_goalrating_ast_targets(20000);
- havocbot_goalrating_items(15000, self.origin, 10000);
- navigation_goalrating_end();
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- }
-}
-
-void havocbot_role_ast_defense()
-{
- if(self.deadflag != DEAD_NO)
- {
- self.havocbot_attack_time = 0;
- havocbot_ast_reset_role(self);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ast_reset_role(self);
- return;
- }
-
- if(self.havocbot_attack_time>time)
- return;
-
- if (self.bot_strategytime < time)
- {
- navigation_goalrating_start();
- havocbot_goalrating_enemyplayers(20000, self.origin, 3000);
- havocbot_goalrating_ast_targets(20000);
- havocbot_goalrating_items(15000, self.origin, 10000);
- navigation_goalrating_end();
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- }
-}
-
-void havocbot_role_ast_setrole(entity bot, float role)
-{
- switch(role)
- {
- case HAVOCBOT_AST_ROLE_DEFENSE:
- bot.havocbot_role = havocbot_role_ast_defense;
- bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_AST_ROLE_OFFENSE:
- bot.havocbot_role = havocbot_role_ast_offense;
- bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- }
-}
-
-void havocbot_ast_reset_role(entity bot)
-{
- if(self.deadflag != DEAD_NO)
- return;
-
- if(bot.team==assault_attacker_team)
- havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE);
- else
- havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE);
-}
-
-void havocbot_chooserole_ast()
-{
- havocbot_ast_reset_role(self);
-}
+++ /dev/null
-#define HAVOCBOT_CTF_ROLE_NONE 0
-#define HAVOCBOT_CTF_ROLE_DEFENSE 2
-#define HAVOCBOT_CTF_ROLE_MIDDLE 4
-#define HAVOCBOT_CTF_ROLE_OFFENSE 8
-#define HAVOCBOT_CTF_ROLE_CARRIER 16
-#define HAVOCBOT_CTF_ROLE_RETRIEVER 32
-#define HAVOCBOT_CTF_ROLE_ESCORT 64
-
-.void() havocbot_role;
-.void() havocbot_previous_role;
-
-void() havocbot_role_ctf_middle;
-void() havocbot_role_ctf_defense;
-void() havocbot_role_ctf_offense;
-void() havocbot_role_ctf_carrier;
-void() havocbot_role_ctf_retriever;
-void() havocbot_role_ctf_escort;
-
-void(entity bot) havocbot_ctf_reset_role;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-.float havocbot_cantfindflag;
-.float havocbot_role_timeout;
-.entity ctf_worldflagnext;
-.entity bot_basewaypoint;
-
-entity ctf_worldflaglist;
-vector havocbot_ctf_middlepoint;
-float havocbot_ctf_middlepoint_radius;
-
-entity havocbot_ctf_find_flag(entity bot)
-{
- entity f;
- f = ctf_worldflaglist;
- while (f)
- {
- if (bot.team == f.team)
- return f;
- f = f.ctf_worldflagnext;
- }
- return world;
-}
-
-entity havocbot_ctf_find_enemy_flag(entity bot)
-{
- entity f;
- f = ctf_worldflaglist;
- while (f)
- {
- if (bot.team != f.team)
- return f;
- f = f.ctf_worldflagnext;
- }
- return world;
-}
-
-float havocbot_ctf_teamcount(entity bot, vector org, float radius)
-{
- if not(teamplay)
- return 0;
-
- float c = 0;
- entity head;
-
- FOR_EACH_PLAYER(head)
- {
- if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
- continue;
-
- if(vlen(head.origin - org) < radius)
- ++c;
- }
-
- return c;
-}
-
-void havocbot_goalrating_ctf_ourflag(float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if (self.team == head.team)
- break;
- head = head.ctf_worldflagnext;
- }
- if (head)
- navigation_routerating(head, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_ourbase(float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if (self.team == head.team)
- break;
- head = head.ctf_worldflagnext;
- }
- if not(head)
- return;
-
- navigation_routerating(head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemyflag(float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if (self.team != head.team)
- break;
- head = head.ctf_worldflagnext;
- }
- if (head)
- navigation_routerating(head, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemybase(float ratingscale)
-{
- if not(bot_waypoints_for_items)
- {
- havocbot_goalrating_ctf_enemyflag(ratingscale);
- return;
- }
-
- entity head;
-
- head = havocbot_ctf_find_enemy_flag(self);
-
- if not(head)
- return;
-
- navigation_routerating(head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
-{
- entity mf;
-
- mf = havocbot_ctf_find_flag(self);
-
- if(mf.ctf_status == FLAG_BASE)
- return;
-
- if(mf.tag_entity)
- navigation_routerating(mf.tag_entity, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- // flag is out in the field
- if(head.ctf_status != FLAG_BASE)
- if(head.tag_entity==world) // dropped
- {
- if(radius)
- {
- if(vlen(org-head.origin)<radius)
- navigation_routerating(head, ratingscale, 10000);
- }
- else
- navigation_routerating(head, ratingscale, 10000);
- }
-
- head = head.ctf_worldflagnext;
- }
-}
-
-void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
-{
- entity head;
- float t;
- head = findchainfloat(bot_pickup, TRUE);
- while (head)
- {
- // gather health and armor only
- if (head.solid)
- if (head.health || head.armorvalue)
- if (vlen(head.origin - org) < sradius)
- {
- // get the value of the item
- t = head.bot_pickupevalfunc(self, head) * 0.0001;
- if (t > 0)
- navigation_routerating(head, t * ratingscale, 500);
- }
- head = head.chain;
- }
-}
-
-void havocbot_role_ctf_setrole(entity bot, float role)
-{
- dprint(strcat(bot.netname," switched to "));
- switch(role)
- {
- case HAVOCBOT_CTF_ROLE_CARRIER:
- dprint("carrier");
- bot.havocbot_role = havocbot_role_ctf_carrier;
- bot.havocbot_role_timeout = 0;
- bot.havocbot_cantfindflag = time + 10;
- bot.bot_strategytime = 0;
- break;
- case HAVOCBOT_CTF_ROLE_DEFENSE:
- dprint("defense");
- bot.havocbot_role = havocbot_role_ctf_defense;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_MIDDLE:
- dprint("middle");
- bot.havocbot_role = havocbot_role_ctf_middle;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_OFFENSE:
- dprint("offense");
- bot.havocbot_role = havocbot_role_ctf_offense;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_RETRIEVER:
- dprint("retriever");
- bot.havocbot_previous_role = bot.havocbot_role;
- bot.havocbot_role = havocbot_role_ctf_retriever;
- bot.havocbot_role_timeout = time + 10;
- bot.bot_strategytime = 0;
- break;
- case HAVOCBOT_CTF_ROLE_ESCORT:
- dprint("escort");
- bot.havocbot_previous_role = bot.havocbot_role;
- bot.havocbot_role = havocbot_role_ctf_escort;
- bot.havocbot_role_timeout = time + 30;
- bot.bot_strategytime = 0;
- break;
- }
- dprint("\n");
-}
-
-void havocbot_role_ctf_carrier()
-{
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried == world)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.bot_strategytime < time)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
- navigation_goalrating_start();
- havocbot_goalrating_ctf_ourbase(50000);
-
- if(self.health<100)
- havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
-
- navigation_goalrating_end();
-
- if (self.navigation_hasgoals)
- self.havocbot_cantfindflag = time + 10;
- else if (time > self.havocbot_cantfindflag)
- {
- // Can't navigate to my own base, suicide!
- // TODO: drop it and wander around
- Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
- return;
- }
- }
-}
-
-void havocbot_role_ctf_escort()
-{
- entity mf, ef;
-
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If enemy flag is back on the base switch to previous role
- ef = havocbot_ctf_find_enemy_flag(self);
- if(ef.ctf_status==FLAG_BASE)
- {
- self.havocbot_role = self.havocbot_previous_role;
- self.havocbot_role_timeout = 0;
- return;
- }
-
- // If the flag carrier reached the base switch to defense
- mf = havocbot_ctf_find_flag(self);
- if(mf.ctf_status!=FLAG_BASE)
- if(vlen(ef.origin - mf.dropped_origin) < 300)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- {
- self.havocbot_role_timeout = time + random() * 30 + 60;
- }
-
- // If nothing happened just switch to previous role
- if (time > self.havocbot_role_timeout)
- {
- self.havocbot_role = self.havocbot_previous_role;
- self.havocbot_role_timeout = 0;
- return;
- }
-
- // Chase the flag carrier
- if (self.bot_strategytime < time)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
- havocbot_goalrating_ctf_enemyflag(30000);
- havocbot_goalrating_ctf_ourstolenflag(40000);
- havocbot_goalrating_items(10000, self.origin, 10000);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_role_ctf_offense()
-{
- entity mf, ef;
- vector pos;
-
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // Check flags
- mf = havocbot_ctf_find_flag(self);
- ef = havocbot_ctf_find_enemy_flag(self);
-
- // Own flag stolen
- if(mf.ctf_status!=FLAG_BASE)
- {
- if(mf.tag_entity)
- pos = mf.tag_entity.origin;
- else
- pos = mf.origin;
-
- // Try to get it if closer than the enemy base
- if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
- }
-
- // Escort flag carrier
- if(ef.ctf_status!=FLAG_BASE)
- {
- if(ef.tag_entity)
- pos = ef.tag_entity.origin;
- else
- pos = ef.origin;
-
- if(vlen(pos-mf.dropped_origin)>700)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
- return;
- }
- }
-
- // About to fail, switch to middlefield
- if(self.health<50)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.bot_strategytime < time)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
- havocbot_goalrating_ctf_ourstolenflag(50000);
- havocbot_goalrating_ctf_enemybase(20000);
- havocbot_goalrating_items(5000, self.origin, 1000);
- havocbot_goalrating_items(1000, self.origin, 10000);
- navigation_goalrating_end();
- }
-}
-
-// Retriever (temporary role):
-void havocbot_role_ctf_retriever()
-{
- entity mf;
-
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If flag is back on the base switch to previous role
- mf = havocbot_ctf_find_flag(self);
- if(mf.ctf_status==FLAG_BASE)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 20;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.bot_strategytime < time)
- {
- float radius;
- radius = 10000;
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
- havocbot_goalrating_ctf_ourstolenflag(50000);
- havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
- havocbot_goalrating_ctf_enemybase(30000);
- havocbot_goalrating_items(500, self.origin, radius);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_role_ctf_middle()
-{
- entity mf;
-
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- mf = havocbot_ctf_find_flag(self);
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 10;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.bot_strategytime < time)
- {
- vector org;
-
- org = havocbot_ctf_middlepoint;
- org_z = self.origin_z;
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
- havocbot_goalrating_ctf_ourstolenflag(50000);
- havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(10000, org, havocbot_ctf_middlepoint_radius * 0.5);
- havocbot_goalrating_items(5000, org, havocbot_ctf_middlepoint_radius * 0.5);
- havocbot_goalrating_items(2500, self.origin, 10000);
- havocbot_goalrating_ctf_enemybase(2500);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_role_ctf_defense()
-{
- entity mf;
-
- if(self.deadflag != DEAD_NO)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
-
- if (self.flagcarried)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If own flag was captured
- mf = havocbot_ctf_find_flag(self);
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 30;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(self);
- return;
- }
- if (self.bot_strategytime < time)
- {
- float radius;
- vector org;
-
- org = mf.dropped_origin;
- radius = havocbot_ctf_middlepoint_radius;
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
-
- // if enemies are closer to our base, go there
- entity head, closestplayer = world;
- float distance, bestdistance = 10000;
- FOR_EACH_PLAYER(head)
- {
- if(head.deadflag!=DEAD_NO)
- continue;
-
- distance = vlen(org - head.origin);
- if(distance<bestdistance)
- {
- closestplayer = head;
- bestdistance = distance;
- }
- }
-
- if(closestplayer)
- if(closestplayer.team!=self.team)
- if(vlen(org - self.origin)>1000)
- if(checkpvs(self.origin,closestplayer)||random()<0.5)
- havocbot_goalrating_ctf_ourbase(30000);
-
- havocbot_goalrating_ctf_ourstolenflag(20000);
- havocbot_goalrating_ctf_droppedflags(20000, org, radius);
- havocbot_goalrating_enemyplayers(15000, org, radius);
- havocbot_goalrating_items(10000, org, radius);
- havocbot_goalrating_items(5000, self.origin, 10000);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_calculate_middlepoint()
-{
- entity f;
- vector s = '0 0 0';
- vector fo = '0 0 0';
- float n = 0;
-
- f = ctf_worldflaglist;
- while (f)
- {
- fo = f.origin;
- s = s + fo;
- f = f.ctf_worldflagnext;
- }
- if(!n)
- return;
- havocbot_ctf_middlepoint = s * (1.0 / n);
- havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint);
-}
-
-void havocbot_ctf_reset_role(entity bot)
-{
- float cdefense, cmiddle, coffense;
- entity mf, ef, head;
- float c;
-
- if(bot.deadflag != DEAD_NO)
- return;
-
- if(vlen(havocbot_ctf_middlepoint)==0)
- havocbot_calculate_middlepoint();
-
- // Check ctf flags
- if (bot.flagcarried)
- {
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- mf = havocbot_ctf_find_flag(bot);
- ef = havocbot_ctf_find_enemy_flag(bot);
-
- // Retrieve stolen flag
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- // If enemy flag is taken go to the middle to intercept pursuers
- if(ef.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
- return;
- }
-
- // if there is only me on the team switch to offense
- c = 0;
- FOR_EACH_PLAYER(head)
- if(head.team==bot.team)
- ++c;
-
- if(c==1)
- {
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
- return;
- }
-
- // Evaluate best position to take
- // Count mates on middle position
- cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
-
- // Count mates on defense position
- cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
-
- // Count mates on offense position
- coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
-
- if(cdefense<=coffense)
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
- else if(coffense<=cmiddle)
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
- else
- havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
-}
-
-void havocbot_chooserole_ctf()
-{
- havocbot_ctf_reset_role(self);
-}
+++ /dev/null
-void() havocbot_role_ft_freeing;
-void() havocbot_role_ft_offense;
-
-void havocbot_goalrating_freeplayers(float ratingscale, vector org, float sradius)
-{
- entity head;
- float distance;
-
- FOR_EACH_PLAYER(head)
- {
- if ((head != self) && (head.team == self.team))
- {
- if (head.freezetag_frozen)
- {
- distance = vlen(head.origin - org);
- if (distance > sradius)
- continue;
- navigation_routerating(head, ratingscale, 2000);
- }
- else
- {
- // If teamate is not frozen still seek them out as fight better
- // in a group.
- navigation_routerating(head, ratingscale/3, 2000);
- }
- }
- }
-}
-
-void havocbot_role_ft_offense()
-{
- entity head;
- float unfrozen;
-
- if(self.deadflag != DEAD_NO)
- return;
-
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + random() * 10 + 20;
-
- // Count how many players on team are unfrozen.
- unfrozen = 0;
- FOR_EACH_PLAYER(head)
- {
- if ((head.team == self.team) && (!head.freezetag_frozen))
- unfrozen++;
- }
-
- // If only one left on team or if role has timed out then start trying to free players.
- if (((unfrozen == 0) && (!self.freezetag_frozen)) || (time > self.havocbot_role_timeout))
- {
- dprint("changing role to freeing\n");
- self.havocbot_role = havocbot_role_ft_freeing;
- self.havocbot_role_timeout = 0;
- return;
- }
-
- if (time > self.bot_strategytime)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
- navigation_goalrating_start();
- havocbot_goalrating_items(10000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
- havocbot_goalrating_freeplayers(9000, self.origin, 10000);
- //havocbot_goalrating_waypoints(1, self.origin, 1000);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_role_ft_freeing()
-{
- if(self.deadflag != DEAD_NO)
- return;
-
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + random() * 10 + 20;
-
- if (time > self.havocbot_role_timeout)
- {
- dprint("changing role to offense\n");
- self.havocbot_role = havocbot_role_ft_offense;
- self.havocbot_role_timeout = 0;
- return;
- }
-
- if (time > self.bot_strategytime)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
- navigation_goalrating_start();
- havocbot_goalrating_items(8000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(10000, self.origin, 10000);
- havocbot_goalrating_freeplayers(20000, self.origin, 10000);
- //havocbot_goalrating_waypoints(1, self.origin, 1000);
- navigation_goalrating_end();
- }
-}
-
-void havocbot_chooserole_ft()
-{
- if(self.deadflag != DEAD_NO)
- return;
-
- if (random() < 0.5)
- self.havocbot_role = havocbot_role_ft_freeing;
- else
- self.havocbot_role = havocbot_role_ft_offense;
-}
+++ /dev/null
-void() havocbot_role_ka_carrier;
-void() havocbot_role_ka_collector;
-void() havocbot_chooserole_ka;
-
-entity ka_ball;
-
-// Keepaway
-// If you don't have the ball, get it; if you do, kill people.
-
-void havocbot_goalrating_ball(float ratingscale, vector org)
-{
- float t;
- entity ball_owner;
- ball_owner = ka_ball.owner;
-
- if (ball_owner == self)
- return;
-
- // If ball is carried by player then hunt them down.
- if (ball_owner)
- {
- t = (self.health + self.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
- navigation_routerating(ball_owner, t * ratingscale, 2000);
- }
-
- // Ball has been dropped so collect.
- navigation_routerating(ka_ball, ratingscale, 2000);
-}
-
-void havocbot_role_ka_carrier()
-{
- if (self.deadflag != DEAD_NO)
- return;
-
- if (time > self.bot_strategytime)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
- navigation_goalrating_start();
- havocbot_goalrating_items(10000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
- //havocbot_goalrating_waypoints(1, self.origin, 1000);
- navigation_goalrating_end();
- }
-
- if (!self.ballcarried)
- {
- self.havocbot_role = havocbot_role_ka_collector;
- self.bot_strategytime = 0;
- }
-}
-
-void havocbot_role_ka_collector()
-{
- if (self.deadflag != DEAD_NO)
- return;
-
- if (time > self.bot_strategytime)
- {
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
- navigation_goalrating_start();
- havocbot_goalrating_items(10000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(1000, self.origin, 10000);
- havocbot_goalrating_ball(20000, self.origin);
- navigation_goalrating_end();
- }
-
- if (self.ballcarried)
- {
- self.havocbot_role = havocbot_role_ka_carrier;
- self.bot_strategytime = 0;
- }
-}
-
-void havocbot_chooserole_ka()
-{
- if (self.ballcarried)
- self.havocbot_role = havocbot_role_ka_carrier;
- else
- self.havocbot_role = havocbot_role_ka_collector;
-}
+++ /dev/null
-#define FLAG_MIN (PL_MIN + '0 0 -13')
-#define FLAG_MAX (PL_MAX + '0 0 -13')
-
-.entity basewaypoint;
-.entity sprite;
-entity ctf_worldflaglist; // CTF flags in the map
-.entity ctf_worldflagnext;
-.float dropperid;
-.float ctf_droptime;
-
-.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;
-
-#define FLAG_CARRY_POS '-15 0 7'
-
-.float ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
-
-float captureshield_min_negscore; // punish at -20 points
-float captureshield_max_ratio; // punish at most 30% of each team
-float captureshield_force; // push force of the shield
-
-float ctf_captureshield_shielded(entity p)
-{
- float s, se;
- entity e;
- float players_worseeq, players_total;
-
- if(captureshield_max_ratio <= 0)
- return FALSE;
-
- s = PlayerScore_Add(p, SP_SCORE, 0);
- if(s >= -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 * captureshield_max_ratio)
- return FALSE;
-
- return TRUE;
-}
-
-void ctf_captureshield_update(entity p, float dir)
-{
- float should;
- if(dir == p.ctf_captureshielded) // 0: shield only, 1: unshield only
- {
- should = ctf_captureshield_shielded(p);
- if(should != dir)
- {
- if(should)
- {
- Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^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.", 5, 0);
- // TODO csqc notifier for this
- }
- else
- {
- Send_CSQC_Centerprint_Generic(p, CPID_CTF_CAPTURESHIELD, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.", 5, 0);
- // TODO csqc notifier for this
- }
- p.ctf_captureshielded = should;
- }
- }
-}
-
-float ctf_captureshield_customize()
-{
- if not(other.ctf_captureshielded)
- return FALSE;
- if(self.team == other.team)
- return FALSE;
- return TRUE;
-}
-
-.float ctf_captureshield_touch_msgtime;
-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) * captureshield_force);
- if (time - other.ctf_captureshield_touch_msgtime > 2)
- Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^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.", 5, 0);
- other.ctf_captureshield_touch_msgtime = time;
-}
-
-void ctf_flag_spawnstuff()
-{
- 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);
-
- waypoint_spawnforitem_force(self, self.origin);
- self.nearestwaypointtimeout = 0; // activate waypointing again
- self.basewaypoint = self.nearestwaypoint;
-
- if(self.team == NUM_TEAM_1)
- WaypointSprite_SpawnFixed("redbase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(NUM_TEAM_1 - 1, FALSE));
- else
- WaypointSprite_SpawnFixed("bluebase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(NUM_TEAM_2 - 1, FALSE));
-}
-
-float ctf_score_value(string parameter)
-{
- return cvar(strcat("g_ctf_personal", parameter));
-}
-
-void FakeTimeLimit(entity e, float t)
-{
- msg_entity = e;
- WriteByte(MSG_ONE, 3); // svc_updatestat
- WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
- if(t < 0)
- WriteCoord(MSG_ONE, autocvar_timelimit);
- else
- WriteCoord(MSG_ONE, (t + 1) / 60);
-}
-
-float flagcaptimerecord;
-.float flagpickuptime;
-//.float iscommander;
-//.float ctf_state;
-
-void() FlagThink;
-void() FlagTouch;
-
-void place_flag()
-{
- if(self.classname != "item_flag_team")
- {
- backtrace("PlaceFlag a non-flag");
- return;
- }
-
- setattachment(self, world, "");
- self.mdl = self.model;
- self.flags = FL_ITEM | FL_NOTARGET;
- self.solid = SOLID_TRIGGER;
- self.movetype = MOVETYPE_NONE;
- 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.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
- //self.effects = self.effects | EF_DIMLIGHT;
- if(self.noalign)
- {
- self.dropped_origin = self.origin;
- }
- else
- {
- droptofloor();
- self.movetype = MOVETYPE_TOSS;
- }
-
- InitializeEntity(self, ctf_flag_spawnstuff, INITPRIO_SETLOCATION);
-}
-
-void LogCTF(string mode, float flagteam, entity actor)
-{
- string s;
- if(!autocvar_sv_eventlog)
- return;
- s = strcat(":ctf:", mode);
- s = strcat(s, ":", ftos(flagteam));
- if(actor != world)
- s = strcat(s, ":", ftos(actor.playerid));
- GameLogEcho(s);
-}
-
-void RegenFlag(entity e)
-{
- if(e.classname != "item_flag_team")
- {
- backtrace("RegenFlag a non-flag");
- return;
- }
-
- if(e.waypointsprite_attachedforcarrier)
- WaypointSprite_DetachCarrier(e);
-
- setattachment(e, world, "");
- e.damageforcescale = 0;
- e.takedamage = DAMAGE_NO;
- e.movetype = MOVETYPE_NONE;
- if(!e.noalign)
- e.movetype = MOVETYPE_TOSS;
- e.velocity = '0 0 0';
- e.solid = SOLID_TRIGGER;
- // TODO: play a sound here
- setorigin(e, e.dropped_origin);
- e.angles = e.mangle;
- e.cnt = FLAG_BASE;
- e.owner = world;
- e.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND and any other junk
-}
-
-void ReturnFlag(entity e)
-{
- if(e.classname != "item_flag_team")
- {
- backtrace("ReturnFlag a non-flag");
- return;
- }
-
- if (e.owner)
- if (e.owner.flagcarried == e)
- {
- WaypointSprite_DetachCarrier(e.owner);
- e.owner.flagcarried = world;
-
- if(e.speedrunning)
- FakeTimeLimit(e.owner, -1);
- }
- e.owner = world;
- RegenFlag(e);
-}
-
-void DropFlag(entity e, entity penalty_receiver, entity attacker)
-{
- entity p;
-
- if(e.classname != "item_flag_team")
- {
- backtrace("DropFlag a non-flag");
- return;
- }
-
- if(e.speedrunning)
- {
- ReturnFlag(e);
- return;
- }
-
- 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(p.netname, "^7 lost the ", e.netname, "\n");
- Send_KillNotification (p.netname, e.netname, "", INFO_LOSTFLAG, MSG_INFO);
-
- if(penalty_receiver)
- UpdateFrags(penalty_receiver, -ctf_score_value("penalty_suicidedrop"));
- else
- UpdateFrags(p, -ctf_score_value("penalty_drop"));
- PlayerScore_Add(p, SP_CTF_DROPS, +1);
- ctf_captureshield_update(p, 0); // shield only
- e.playerid = attacker.playerid;
- e.ctf_droptime = time;
- WaypointSprite_Spawn("flagdropped", 0, 0, e, '0 0 1' * 61, world, NUM_TEAM_1 + NUM_TEAM_2 - e.team, e, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1');
- WaypointSprite_Ping(e.waypointsprite_attachedforcarrier);
-
- if(p.waypointsprite_attachedforcarrier)
- {
- WaypointSprite_DetachCarrier(p);
- }
- else
- {
- bprint("\{1}^1Flag carrier had no flag sprite?!?\n");
- backtrace("Flag carrier had no flag sprite?!?");
- }
- LogCTF("dropped", p.team, p);
- sound (p, CH_TRIGGER, self.noise4, VOL_BASE, ATTN_NONE);
-
- setattachment(e, world, "");
- e.damageforcescale = autocvar_g_balance_ctf_damageforcescale;
- e.takedamage = DAMAGE_YES;
-
- if (p.flagcarried == e)
- p.flagcarried = world;
- e.owner = world;
-
- e.flags = FL_ITEM | FL_NOTARGET; // 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' + '0 0 37');
- e.cnt = FLAG_DROPPED;
- e.velocity = '0 0 300';
- e.pain_finished = time + autocvar_g_ctf_flag_returntime;//30;
-
- trace_startsolid = FALSE;
- tracebox(e.origin, e.mins, e.maxs, e.origin, TRUE, e);
- if(trace_startsolid)
- dprint("FLAG FALLTHROUGH will happen SOON\n");
-}
-
-void FlagThink()
-{
- 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.cnt == FLAG_CARRY)
- {
- if(self.owner)
- if(flagcaptimerecord)
- if(time >= self.flagpickuptime + flagcaptimerecord)
- {
- bprint("The ", self.netname, " became impatient after ", ftos_decimals(flagcaptimerecord, 2), " seconds and returned itself\n");
-
- sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
- self.owner.impulse = 141; // returning!
-
- e = self;
- self = self.owner;
- ReturnFlag(e);
- ImpulseCommands();
- self = e;
- return;
- }
- }
-
- if (self.cnt == FLAG_BASE)
- return;
-
- if (self.cnt == 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, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
- LogCTF("returned", self.team, world);
- ReturnFlag(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");
- DropFlag(self, world, world);
- return;
- }
-}
-
-float ctf_usekey()
-{
- if(self.flagcarried)
- {
- DropFlag(self.flagcarried, self, world);
- return TRUE;
- }
- return FALSE;
-}
-
-void flag_cap_ring_spawn(vector org)
-{
- shockwave_spawn("models/ctf/shockwavetransring.md3", org - '0 0 15', -0.8, 0, 1);
-}
-
-// TODO add FlagDamage, replace weird hurttrigger handling inside trigger_hurt code by it
-void FlagTouch()
-{
- if(gameover) return;
-
- float t;
- entity player;
- string s, s0, h0, h1;
-
- if (self.cnt == FLAG_CARRY)
- return;
-
- if (self.cnt == FLAG_DROPPED)
- {
- if(ITEM_TOUCH_NEEDKILL())
- {
- self.pain_finished = 0; // return immediately
- return;
- }
- }
-
- if (other.classname != "player")
- return;
- if (other.health < 1) // ignore dead players
- 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;
- }
- if(autocvar_g_ctf_captimerecord_always || player_count - currentbots <= 1) // at most one human
- {
- t = time - other.flagcarried.flagpickuptime;
- s = ftos_decimals(t, 2);
- s0 = ftos_decimals(flagcaptimerecord, 2);
- h0 = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
- h1 = other.netname;
- if(h0 == h1)
- h0 = "their";
- else
- h0 = strcat(h0, "^7's"); // h0: display text for previous netname
- if (flagcaptimerecord == 0)
- {
- s = strcat(" in ", s, " seconds");
- flagcaptimerecord = t;
- db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(t));
- db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), h1);
- write_recordmarker(other, time - t, t);
- }
- else if (t < flagcaptimerecord)
- {
- s = strcat(" in ", s, " seconds, breaking ", h0, " previous record of ", s0, " seconds");
- flagcaptimerecord = t;
- db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(t));
- db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), h1);
- write_recordmarker(other, time - t, t);
- }
- else
- {
- s = strcat(" in ", s, " seconds, failing to break ", h0, " record of ", s0, " seconds");
- }
- }
- else
- s = "";
-
- Send_KillNotification (other.netname, other.flagcarried.netname, s, INFO_CAPTUREFLAG, MSG_INFO);
-
- PlayerTeamScore_Add(other, SP_CTF_CAPS, ST_CTF_CAPS, 1);
- LogCTF("capture", other.flagcarried.team, other);
- // give credit to the individual player
- UpdateFrags(other, ctf_score_value("score_capture"));
-
- if (autocvar_g_ctf_flag_capture_effects) {
- if (other.team == NUM_TEAM_1) { // red team scores effect
- pointparticles(particleeffectnum("red_ground_quake"), self.origin, '0 0 0', 1);
- flag_cap_ring_spawn(self.origin);
- }
- if (other.team == NUM_TEAM_2) { // blue team scores effect
- pointparticles(particleeffectnum("blue_ground_quake"), self.origin, '0 0 0', 1);
- flag_cap_ring_spawn(self.origin);
- }
- }
-
- sound (other, CH_TRIGGER, self.noise2, VOL_BASE, ATTN_NONE);
- WaypointSprite_DetachCarrier(other);
- if(self.speedrunning)
- FakeTimeLimit(other, -1);
- RegenFlag (other.flagcarried);
- other.flagcarried = world;
- other.next_take_time = time + 1;
- }
- if (self.cnt == FLAG_BASE)
- if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2) // only red and blue team can steal flags
- if (other.team != self.team)
- if (!other.flagcarried)
- if (!other.ctf_captureshielded)
- {
- if(MUTATOR_CALLHOOK(ItemTouch))
- return;
-
- if (other.next_take_time > time)
- return;
-
- if (autocvar_g_ctf_flag_pickup_effects) // pickup effect
- pointparticles(particleeffectnum("smoke_ring"), 0.5 * (self.absmin + self.absmax), '0 0 0', 1);
-
- // pick up
- self.flagpickuptime = time; // used for timing runs
- self.speedrunning = other.speedrunning; // if speedrunning, flag will self-return and teleport the owner back after the record
- if(other.speedrunning)
- if(flagcaptimerecord)
- FakeTimeLimit(other, time + flagcaptimerecord);
- self.solid = SOLID_NOT;
- setorigin(self, self.origin); // relink
- self.owner = other;
- other.flagcarried = self;
- self.cnt = FLAG_CARRY;
- self.angles = '0 0 0';
- //bprint(other.netname, "^7 got the ", self.netname, "\n");
- Send_KillNotification (other.netname, self.netname, "", INFO_GOTFLAG, MSG_INFO);
- UpdateFrags(other, ctf_score_value("score_pickup_base"));
- self.dropperid = other.playerid;
- PlayerScore_Add(other, SP_CTF_PICKUPS, 1);
- LogCTF("steal", self.team, other);
- sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NONE);
-
- FOR_EACH_PLAYER(player)
- if(player.team == self.team)
- centerprint(player, "The enemy got your flag! Retrieve it!");
-
- self.movetype = MOVETYPE_NONE;
- setorigin(self, FLAG_CARRY_POS);
- setattachment(self, other, "");
- WaypointSprite_AttachCarrier("flagcarrier", other, RADARICON_FLAGCARRIER, '1 1 0');
- WaypointSprite_Ping(self.sprite);
-
- return;
- }
-
- if (self.cnt == FLAG_DROPPED)
- {
- self.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND and any other junk
- if (other.team == self.team || (other.team != NUM_TEAM_1 && other.team != NUM_TEAM_2))
- {
- // return flag
- Send_KillNotification (other.netname, self.netname, "", INFO_RETURNFLAG, MSG_INFO);
- //bprint(other.netname, "^7 returned the ", self.netname, "\n");
-
- // punish the player who last had it
- FOR_EACH_PLAYER(player)
- if(player.playerid == self.dropperid)
- {
- PlayerScore_Add(player, SP_SCORE, -ctf_score_value("penalty_returned"));
- ctf_captureshield_update(player, 0); // shield only
- }
-
- // punish the team who was last carrying it
- if(self.team == NUM_TEAM_1)
- TeamScore_AddToTeam(NUM_TEAM_2, ST_SCORE, -ctf_score_value("penalty_returned"));
- else
- TeamScore_AddToTeam(NUM_TEAM_1, ST_SCORE, -ctf_score_value("penalty_returned"));
-
- // reward the player who returned it
- if(other.playerid == self.playerid) // is this the guy who killed the FC last?
- {
- if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2)
- UpdateFrags(other, ctf_score_value("score_return_by_killer"));
- else
- UpdateFrags(other, ctf_score_value("score_return_rogue_by_killer"));
- }
- else
- {
- if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2)
- UpdateFrags(other, ctf_score_value("score_return"));
- else
- UpdateFrags(other, ctf_score_value("score_return_rogue"));
- }
- PlayerScore_Add(other, SP_CTF_RETURNS, 1);
- LogCTF("return", self.team, other);
- sound (other, CH_TRIGGER, self.noise1, VOL_BASE, ATTN_NONE);
- ReturnFlag(self);
- }
- else if (!other.flagcarried && (other.playerid != self.dropperid || time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect))
- {
- if(self.waypointsprite_attachedforcarrier)
- WaypointSprite_DetachCarrier(self);
-
- if (autocvar_g_ctf_flag_pickup_effects) // field pickup effect
- pointparticles(particleeffectnum("smoke_ring"), 0.5 * (self.absmin + self.absmax), '0 0 0', 1);
-
- // pick up
- self.solid = SOLID_NOT;
- setorigin(self, self.origin); // relink
- self.owner = other;
- other.flagcarried = self;
- self.cnt = FLAG_CARRY;
- Send_KillNotification (other.netname, self.netname, "", INFO_PICKUPFLAG, MSG_INFO);
- //bprint(other.netname, "^7 picked up the ", self.netname, "\n");
-
- float f;
- f = bound(0, (self.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1);
- //print("factor is ", ftos(f), "\n");
- f = ctf_score_value("score_pickup_dropped_late") * (1-f)
- + ctf_score_value("score_pickup_dropped_early") * f;
- f = floor(f + 0.5);
- self.dropperid = other.playerid;
- //print("score is ", ftos(f), "\n");
-
- UpdateFrags(other, f);
- PlayerScore_Add(other, SP_CTF_PICKUPS, 1);
- LogCTF("pickup", self.team, other);
- sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NONE);
-
- FOR_EACH_PLAYER(player)
- if(player.team == self.team)
- centerprint(player, "The enemy got your flag! Retrieve it!");
-
- self.movetype = MOVETYPE_NONE; // flag must have MOVETYPE_NONE here, otherwise it will drop through the floor...
- setorigin(self, FLAG_CARRY_POS);
- setattachment(self, other, "");
- self.damageforcescale = 0;
- self.takedamage = DAMAGE_NO;
- WaypointSprite_AttachCarrier("flagcarrier", other, RADARICON_FLAGCARRIER, '1 1 0');
- }
- }
-}
-
-/*QUAKED spawnfunc_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 spawnfunc_info_player_team1()
-{
- if(g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_1; // red
- spawnfunc_info_player_deathmatch();
-}
-//self.team = 4;self.classname = "info_player_start";spawnfunc_info_player_start();}
-
-/*QUAKED spawnfunc_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 spawnfunc_info_player_team2()
-{
- if(g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_2; // blue
- spawnfunc_info_player_deathmatch();
-}
-//self.team = 13;self.classname = "info_player_start";spawnfunc_info_player_start();}
-
-/*QUAKED spawnfunc_info_player_team3 (1 0 0) (-16 -16 -24) (16 16 24)
-CTF Starting point for a player in
-team three (Yellow).
-
-Keys:
-"angle"
- viewing angle when spawning
-*/
-void spawnfunc_info_player_team3()
-{
- if(g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_3; // yellow
- spawnfunc_info_player_deathmatch();
-}
-
-
-/*QUAKED spawnfunc_info_player_team4 (1 0 0) (-16 -16 -24) (16 16 24)
-CTF Starting point for a player in
-team four (Magenta).
-
-Keys:
-"angle"
- viewing angle when spawning
-*/
-void spawnfunc_info_player_team4()
-{
- if(g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_4; // purple
- spawnfunc_info_player_deathmatch();
-}
-
-void item_flag_reset()
-{
- DropFlag(self, world, world);
- if(self.waypointsprite_attachedforcarrier)
- WaypointSprite_DetachCarrier(self);
- ReturnFlag(self);
-}
-
-void item_flag_postspawn()
-{ // Check CTF Item Flag Post Spawn
-
- // Flag Glow Trail Support
- if(autocvar_g_ctf_flag_glowtrails)
- { // Provide Flag Glow Trail
- if(self.team == NUM_TEAM_1)
- // Red
- self.glow_color = 251;
- else
- if(self.team == NUM_TEAM_2)
- // Blue
- self.glow_color = 210;
-
- self.glow_size = 25;
- self.glow_trail = 1;
- }
-}
-
-/*QUAKED spawnfunc_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/redcapture.wav)
-"noise3"
- sound played when flag is lost in the field and respawns itself
- (default ctf/respawn.wav)
-*/
-
-void spawnfunc_item_flag_team2();
-void spawnfunc_item_flag_team1()
-{
- if (!g_ctf)
- {
- remove(self);
- return;
- }
-
- if (g_ctf_reverse)
- {
- float old_g_ctf_reverse = g_ctf_reverse;
- g_ctf_reverse = 0; // avoid an endless loop
- spawnfunc_item_flag_team2();
- g_ctf_reverse = old_g_ctf_reverse;
- return;
- }
-
- // link flag into ctf_worldflaglist
- self.ctf_worldflagnext = ctf_worldflaglist;
- ctf_worldflaglist = self;
-
- self.classname = "item_flag_team";
- self.team = NUM_TEAM_1; // color 4 team (red)
- self.items = IT_KEY2; // gold key (redish enough)
- self.netname = "^1RED^7 flag";
- self.target = "###item###";
- self.skin = autocvar_g_ctf_flag_red_skin;
- if(self.spawnflags & 1)
- self.noalign = 1;
- if (!self.model)
- self.model = autocvar_g_ctf_flag_red_model;
- if (!self.noise)
- self.noise = "ctf/red_taken.wav";
- if (!self.noise1)
- self.noise1 = "ctf/red_returned.wav";
- if (!self.noise2)
- self.noise2 = "ctf/red_capture.wav"; // blue team scores by capturing the red flag
- if (!self.noise3)
- self.noise3 = "ctf/flag_respawn.wav";
- if (!self.noise4)
- self.noise4 = "ctf/red_dropped.wav";
- precache_model (self.model);
- setmodel (self, self.model); // precision set below
- precache_sound (self.noise);
- precache_sound (self.noise1);
- precache_sound (self.noise2);
- precache_sound (self.noise3);
- precache_sound (self.noise4);
- //setsize(self, '-16 -16 -37', '16 16 37');
- setsize(self, FLAG_MIN, FLAG_MAX);
- 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_LOWPRECISION;
- if(autocvar_g_ctf_fullbrightflags)
- self.effects |= EF_FULLBRIGHT;
- if(autocvar_g_ctf_dynamiclights)
- self.effects |= EF_RED;
-
- // From Spidflisk
- item_flag_postspawn();
-
- precache_model("models/ctf/shield.md3");
- precache_model("models/ctf/shockwavetransring.md3");
-
- self.reset = item_flag_reset;
-}
-
-/*QUAKED spawnfunc_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)
-"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/bluecapture.wav)
-"noise3"
- sound played when flag is lost in the field and respawns itself
- (default ctf/respawn.wav)
-*/
-
-void spawnfunc_item_flag_team2()
-{
- if (!g_ctf)
- {
- remove(self);
- return;
- }
-
- if (g_ctf_reverse)
- {
- float old_g_ctf_reverse = g_ctf_reverse;
- g_ctf_reverse = 0; // avoid an endless loop
- spawnfunc_item_flag_team1();
- g_ctf_reverse = old_g_ctf_reverse;
- return;
- }
-
- // link flag into ctf_worldflaglist
- self.ctf_worldflagnext = ctf_worldflaglist;
- ctf_worldflaglist = self;
-
- self.classname = "item_flag_team";
- self.team = NUM_TEAM_2; // color 13 team (blue)
- self.items = IT_KEY1; // silver key (bluish enough)
- self.netname = "^4BLUE^7 flag";
- self.target = "###item###";
- self.skin = autocvar_g_ctf_flag_blue_skin;
- if(self.spawnflags & 1)
- self.noalign = 1;
- if (!self.model)
- self.model = autocvar_g_ctf_flag_blue_model;
- if (!self.noise)
- self.noise = "ctf/blue_taken.wav";
- if (!self.noise1)
- self.noise1 = "ctf/blue_returned.wav";
- if (!self.noise2)
- self.noise2 = "ctf/blue_capture.wav"; // blue team scores by capturing the red flag
- if (!self.noise3)
- self.noise3 = "ctf/flag_respawn.wav";
- if (!self.noise4)
- self.noise4 = "ctf/blue_dropped.wav";
- precache_model (self.model);
- setmodel (self, self.model); // precision set below
- precache_sound (self.noise);
- precache_sound (self.noise1);
- precache_sound (self.noise2);
- precache_sound (self.noise3);
- precache_sound (self.noise4);
- //setsize(self, '-16 -16 -37', '16 16 37');
- setsize(self, FLAG_MIN, FLAG_MAX);
- 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_LOWPRECISION;
- if(autocvar_g_ctf_fullbrightflags)
- self.effects |= EF_FULLBRIGHT;
- if(autocvar_g_ctf_dynamiclights)
- self.effects |= EF_BLUE;
-
- // From Spidflisk
- item_flag_postspawn();
-
- precache_model("models/ctf/shield.md3");
- precache_model("models/ctf/shockwavetransring.md3");
-
- self.reset = item_flag_reset;
-}
-
-
-/*QUAKED spawnfunc_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 spawnfunc_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 spawnfunc_ctf_team()
-{
- if (!g_ctf)
- {
- remove(self);
- return;
- }
- 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)
-{
- entity oldself;
- oldself = self;
- self = spawn();
- self.classname = "ctf_team";
- self.netname = teamname;
- self.cnt = teamcolor;
-
- spawnfunc_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", NUM_TEAM_1 - 1);
- ctf_spawnteam("Blue", NUM_TEAM_2 - 1);
-}
-
-void ctf_delayedinit()
-{
- // if no teams are found, spawn defaults
- if (find(world, classname, "ctf_team") == world)
- ctf_spawnteams();
-
- ScoreRules_ctf();
-}
-
-void ctf_init()
-{
- InitializeEntity(world, ctf_delayedinit, INITPRIO_GAMETYPE);
- flagcaptimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
-
- captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
- captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
- captureshield_force = autocvar_g_ctf_shield_force;
-}
-
-void ctf_setstatus2(entity flag, float shift)
-{
- if (flag.cnt == FLAG_CARRY)
- if (flag.owner == self)
- self.items |= shift * 3;
- else
- self.items |= shift * 1;
- else if (flag.cnt == FLAG_DROPPED)
- self.items |= shift * 2;
- else
- {
- // no status bits
- }
-}
-
-void ctf_setstatus()
-{
- self.items &~= IT_RED_FLAG_TAKEN;
- self.items &~= IT_RED_FLAG_LOST;
- self.items &~= IT_BLUE_FLAG_TAKEN;
- self.items &~= IT_BLUE_FLAG_LOST;
- self.items &~= IT_CTF_SHIELDED;
-
- entity flag;
- float redflags, blueflags;
-
- if(self.ctf_captureshielded)
- self.items |= IT_CTF_SHIELDED;
-
- redflags = 0;
- blueflags = 0;
-
- for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
- {
- if(flag.items & IT_KEY2) // blue
- ++redflags;
- else if(flag.items & IT_KEY1) // red
- ++blueflags;
- }
-
- // blinking magic: if there is more than one flag, show one of these in a clever way
- if(redflags)
- redflags = mod(floor(time * redflags * 0.75), redflags);
- if(blueflags)
- blueflags = mod(floor(time * blueflags * 0.75), blueflags);
-
- for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
- {
- if(flag.items & IT_KEY2) // blue
- {
- if(--redflags == -1) // happens exactly once (redflags is in 0..count-1, and will --'ed count times)
- ctf_setstatus2(flag, IT_RED_FLAG_TAKEN);
- }
- else if(flag.items & IT_KEY1) // red
- {
- if(--blueflags == -1) // happens exactly once
- ctf_setstatus2(flag, IT_BLUE_FLAG_TAKEN);
- }
- }
-}
-/*
-entity ctf_team_has_commander(float cteam)
-{
- entity pl;
- if(cteam != NUM_TEAM_1 || cteam != NUM_TEAM_2)
- return world;
-
- FOR_EACH_REALPLAYER(pl) {
- if(pl.team == cteam && pl.iscommander) {
- return pl;
- }
- }
- return world;
-}
-
-void ctf_setstate(entity e, float st)
-{
- e.ctf_state = st;
- ++e.version;
-}
-
-void ctf_new_commander(float cteam)
-{
- entity pl, plmax;
-
- plmax = world;
- FOR_EACH_REALPLAYER(pl) {
- if(pl.team == cteam) {
- if(pl.iscommander) { // don't reassign if alreay there
- return;
- }
- if(plmax == world || plmax.frags < pl.frags) <<<<<<<<<<<<<<<<< BROKEN in new scoring system
- plmax = pl;
- }
- }
- if(plmax == world) {
- bprint(strcat(ColoredTeamName(cteam), " Team has no Commander!\n"));
- return;
- }
-
- plmax.iscommander = TRUE;
- ctf_setstate(plmax, 3);
- sprint(plmax, "^3You're the commander now!\n");
- centerprint(plmax, "^3You're the commander now!\n");
-}
-
-void ctf_clientconnect()
-{
- self.iscommander = FALSE;
-
- if(!self.team || self.classname != "player") {
- ctf_setstate(self, -1);
- } else
- ctf_setstate(self, 0);
-
- self.team_saved = self.team;
-
- if(self.team != 0 && self.classname == "player" && !ctf_team_has_commander(self.team)) {
- ctf_new_commander(self.team);
- }
-}
-
-void ctf_playerchanged()
-{
- if(!self.team || self.classname != "player") {
- ctf_setstate(self, -1);
- } else if(self.ctf_state < 0 && self.classname == "player") {
- ctf_setstate(self, 0);
- }
-
- if(self.iscommander &&
- (self.classname != "player" || self.team != self.team_saved)
- )
- {
- self.iscommander = FALSE;
- if(self.classname == "player")
- ctf_setstate(self, 0);
- else
- ctf_setstate(self, -1);
- ctf_new_commander(self.team_saved);
- }
-
- self.team_saved = self.team;
-
- ctf_new_commander(self.team);
-}
-
-void ctf_clientdisconnect()
-{
- if(self.iscommander)
- {
- ctf_new_commander(self.team);
- }
-}
-
-entity GetPlayer(string);
-float ctf_clientcommand()
-{
- entity e;
- if(argv(0) == "order") {
- if(!g_ctf) {
- sprint(self, "This command is not supported in this gamemode.\n");
- return TRUE;
- }
- if(!self.iscommander) {
- sprint(self, "^1You are not the commander!\n");
- return TRUE;
- }
- if(argv(2) == "") {
- sprint(self, "Usage: order #player status - (playernumber as in status)\n");
- return TRUE;
- }
- e = GetPlayer(argv(1));
- if(e == world) {
- sprint(self, "Invalid player.\nUsage: order #player status - (playernumber as in status)\n");
- return TRUE;
- }
- if(e.team != self.team) {
- sprint(self, "^3You can only give orders to your own team!\n");
- return TRUE;
- }
- if(argv(2) == "attack") {
- sprint(self, strcat("Ordering ", e.netname, " to attack!\n"));
- sprint(e, "^1Attack!\n");
- centerprint(e, "^7You've been ordered to^9\n^1Attack!\n");
- ctf_setstate(e, 1);
- } else if(argv(2) == "defend") {
- sprint(self, strcat("Ordering ", e.netname, " to defend!\n"));
- sprint(e, "^Defend!\n");
- centerprint(e, "^7You've been ordered to^9\n^2Defend!\n");
- ctf_setstate(e, 2);
- } else {
- sprint(self, "^7Invalid command, use ^3attack^7, or ^3defend^7.\n");
- }
- return TRUE;
- }
- return FALSE;
-}
-*/
+++ /dev/null
-
-/*
-Domination as a plugin for netquake mods
-by LordHavoc (lordhavoc@ghdigital.com)
-
-How to add domination points to a mod:
-1. Add this line to progs.src above world.qc:
-domination.qc
-2. Comment out all lines in ClientObituary in client.qc that begin with targ.frags or attacker.frags.
-3. Add this above spawnfunc_worldspawn in world.qc:
-void() dom_init;
-4. Add this line to the end of spawnfunc_worldspawn in world.qc:
-dom_init();
-
-Note: The only teams who can use dom control points are identified by spawnfunc_dom_team entities (if none exist these default to red and blue and use only quake models/sounds).
-*/
-
-#define DOMPOINTFRAGS frags
-
-.float enemy_playerid;
-.entity sprite;
-.float captime;
-
-// pps: points per second
-.float dom_total_pps;
-.float dom_pps_red;
-.float dom_pps_blue;
-.float dom_pps_yellow;
-.float dom_pps_pink;
-float total_pps;
-float pps_red;
-float pps_blue;
-float pps_yellow;
-float pps_pink;
-void set_dom_state(entity e)
-{
- e.dom_total_pps = total_pps;
- e.dom_pps_red = pps_red;
- e.dom_pps_blue = pps_blue;
- if(c3 >= 0)
- e.dom_pps_yellow = pps_yellow;
- if(c4 >= 0)
- e.dom_pps_pink = pps_pink;
-}
-
-void() dom_controlpoint_setup;
-
-void LogDom(string mode, float team_before, entity actor)
-{
- string s;
- if(!autocvar_sv_eventlog)
- return;
- s = strcat(":dom:", mode);
- s = strcat(s, ":", ftos(team_before));
- s = strcat(s, ":", ftos(actor.playerid));
- GameLogEcho(s);
-}
-
-void() dom_spawnteams;
-
-void dompoint_captured ()
-{
- entity head;
- float old_delay, old_team, real_team;
-
- // now that the delay has expired, switch to the latest team to lay claim to this point
- head = self.owner;
-
- real_team = self.cnt;
- self.cnt = -1;
-
- LogDom("taken", self.team, self.dmg_inflictor);
- self.dmg_inflictor = world;
-
- self.goalentity = head;
- self.model = head.mdl;
- self.modelindex = head.dmg;
- self.skin = head.skin;
-
- //bprint(head.message);
- //bprint("\n");
-
- //bprint(^3head.netname);
- //bprint(head.netname);
- //bprint(self.message);
- //bprint("\n");
-
- float points, wait_time;
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = self.frags;
- if (autocvar_g_domination_point_rate)
- wait_time = autocvar_g_domination_point_rate;
- else
- wait_time = self.wait;
-
- bprint("^3", head.netname, "^3", self.message);
- if (points != 1)
- bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
- else
- bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
-
- if(self.enemy.playerid == self.enemy_playerid)
- PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
- else
- self.enemy = world;
-
- if (head.noise != "")
- if(self.enemy)
- sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
- else
- sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
- if (head.noise1 != "")
- play2all(head.noise1);
-
- //self.nextthink = time + autocvar_g_domination_point_rate;
- //self.think = dompointthink;
-
- self.delay = time + wait_time;
-
- // do trigger work
- old_delay = self.delay;
- old_team = self.team;
- self.team = real_team;
- self.delay = 0;
- activator = self;
- SUB_UseTargets ();
- self.delay = old_delay;
- self.team = old_team;
-
- switch(self.goalentity.team)
- {
- case NUM_TEAM_1:
- WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
- break;
- case NUM_TEAM_2:
- WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
- break;
- case NUM_TEAM_3:
- WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
- break;
- case NUM_TEAM_4:
- WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
- }
-
- total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
- for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
- {
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = head.frags;
- if (autocvar_g_domination_point_rate)
- wait_time = autocvar_g_domination_point_rate;
- else
- wait_time = head.wait;
- switch(head.goalentity.team)
- {
- case NUM_TEAM_1:
- pps_red += points/wait_time;
- break;
- case NUM_TEAM_2:
- pps_blue += points/wait_time;
- break;
- case NUM_TEAM_3:
- pps_yellow += points/wait_time;
- break;
- case NUM_TEAM_4:
- pps_pink += points/wait_time;
- }
- total_pps += points/wait_time;
- }
-
- WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
- WaypointSprite_Ping(self.sprite);
-
- self.captime = time;
-
- FOR_EACH_REALCLIENT(head)
- set_dom_state(head);
-}
-
-void AnimateDomPoint()
-{
- if(self.pain_finished > time)
- return;
- self.pain_finished = time + self.t_width;
- if(self.nextthink > self.pain_finished)
- self.nextthink = self.pain_finished;
-
- self.frame = self.frame + 1;
- if(self.frame > self.t_length)
- self.frame = 0;
-}
-
-void dompointthink()
-{
- float fragamt;
-
- self.nextthink = time + 0.1;
-
- //self.frame = self.frame + 1;
- //if(self.frame > 119)
- // self.frame = 0;
- AnimateDomPoint();
-
- // give points
-
- if (gameover || self.delay > time || time < game_starttime) // game has ended, don't keep giving points
- return;
-
- if(autocvar_g_domination_point_rate)
- self.delay = time + autocvar_g_domination_point_rate;
- else
- self.delay = time + self.wait;
-
- // give credit to the team
- // NOTE: this defaults to 0
- if (self.goalentity.netname != "")
- {
- if(autocvar_g_domination_point_amt)
- fragamt = autocvar_g_domination_point_amt;
- else
- fragamt = self.DOMPOINTFRAGS;
- TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
- TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
-
- // give credit to the individual player, if he is still there
- if (self.enemy.playerid == self.enemy_playerid)
- {
- PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
- PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
- }
- else
- self.enemy = world;
- }
-}
-
-void dompointtouch()
-{
- entity head;
- if (other.classname != "player")
- return;
- if (other.health < 1)
- return;
-
- if(time < self.captime + 0.3)
- return;
-
- // only valid teams can claim it
- head = find(world, classname, "dom_team");
- while (head && head.team != other.team)
- head = find(head, classname, "dom_team");
- if (!head || head.netname == "" || head == self.goalentity)
- return;
-
- // delay capture
-
- self.team = self.goalentity.team; // this stores the PREVIOUS team!
-
- self.cnt = other.team;
- self.owner = head; // team to switch to after the delay
- self.dmg_inflictor = other;
-
- // self.state = 1;
- // self.delay = time + cvar("g_domination_point_capturetime");
- //self.nextthink = time + cvar("g_domination_point_capturetime");
- //self.think = dompoint_captured;
-
- // go to neutral team in the mean time
- head = find(world, classname, "dom_team");
- while (head && head.netname != "")
- head = find(head, classname, "dom_team");
- if(head == world)
- return;
-
- WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
- WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
- WaypointSprite_Ping(self.sprite);
-
- self.goalentity = head;
- self.model = head.mdl;
- self.modelindex = head.dmg;
- self.skin = head.skin;
-
- self.enemy = other; // individual player scoring
- self.enemy_playerid = other.playerid;
- dompoint_captured();
-}
-
-/*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
-Team declaration for Domination gameplay, this allows you to decide what team
-names and control point models are used in your map.
-
-Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
-can have netname set! The nameless team owns all control points at start.
-
-Keys:
-"netname"
- Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
-"cnt"
- Scoreboard color of the team (for example 4 is red and 13 is blue)
-"model"
- Model to use for control points owned by this team (for example
- "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
- keycard)
-"skin"
- Skin of the model to use (for team skins on a single model)
-"noise"
- Sound to play when this team captures a point.
- (this is a localized sound, like a small alarm or other effect)
-"noise1"
- Narrator speech to play when this team captures a point.
- (this is a global sound, like "Red team has captured a control point")
-*/
-
-void spawnfunc_dom_team()
-{
- if(!g_domination || autocvar_g_domination_teams_override >= 2)
- {
- remove(self);
- return;
- }
- precache_model(self.model);
- if (self.noise != "")
- precache_sound(self.noise);
- if (self.noise1 != "")
- precache_sound(self.noise1);
- self.classname = "dom_team";
- setmodel(self, self.model); // precision not needed
- self.mdl = self.model;
- self.dmg = self.modelindex;
- self.model = "";
- self.modelindex = 0;
- // this would have to be changed if used in quakeworld
- if(self.cnt)
- self.team = self.cnt + 1; // WHY are these different anyway?
-}
-
-void dom_controlpoint_setup()
-{
- entity head;
- // find the spawnfunc_dom_team representing unclaimed points
- head = find(world, classname, "dom_team");
- while(head && head.netname != "")
- head = find(head, classname, "dom_team");
- if (!head)
- objerror("no spawnfunc_dom_team with netname \"\" found\n");
-
- // copy important properties from spawnfunc_dom_team entity
- self.goalentity = head;
- setmodel(self, head.mdl); // precision already set
- self.skin = head.skin;
-
- self.cnt = -1;
-
- if(self.message == "")
- self.message = " has captured a control point";
-
- if(self.DOMPOINTFRAGS <= 0)
- self.DOMPOINTFRAGS = 1;
- if(self.wait <= 0)
- self.wait = 5;
-
- float points, waittime;
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = self.frags;
- if (autocvar_g_domination_point_rate)
- waittime = autocvar_g_domination_point_rate;
- else
- waittime = self.wait;
-
- total_pps += points/waittime;
-
- if(!self.t_width)
- self.t_width = 0.02; // frame animation rate
- if(!self.t_length)
- self.t_length = 239; // maximum frame
-
- self.think = dompointthink;
- self.nextthink = time;
- self.touch = dompointtouch;
- self.solid = SOLID_TRIGGER;
- self.flags = FL_ITEM;
- setsize(self, '-32 -32 -32', '32 32 32');
- setorigin(self, self.origin + '0 0 20');
- droptofloor();
-
- waypoint_spawnforitem(self);
- WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
-}
-
-
-
-/*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
-Control point for Domination gameplay.
-*/
-void spawnfunc_dom_controlpoint()
-{
- if(!g_domination)
- {
- remove(self);
- return;
- }
- self.think = dom_controlpoint_setup;
- self.nextthink = time + 0.1;
- self.reset = dom_controlpoint_setup;
-
- if(!self.scale)
- self.scale = 0.6;
-
- //if(!self.glow_size)
- // self.glow_size = cvar("g_domination_point_glow");
- self.effects = self.effects | EF_LOWPRECISION;
- if (autocvar_g_domination_point_fullbright)
- self.effects |= EF_FULLBRIGHT;
-}
-
-// code from here on is just to support maps that don't have control point and team entities
-void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
-{
- entity oldself;
- oldself = self;
- self = spawn();
- self.classname = "dom_team";
- self.netname = teamname;
- self.cnt = teamcolor;
- self.model = pointmodel;
- self.skin = pointskin;
- self.noise = capsound;
- self.noise1 = capnarration;
- self.message = capmessage;
-
- // this code is identical to spawnfunc_dom_team
- setmodel(self, self.model); // precision not needed
- self.mdl = self.model;
- self.dmg = self.modelindex;
- self.model = "";
- self.modelindex = 0;
- // this would have to be changed if used in quakeworld
- self.team = self.cnt + 1;
-
- //eprint(self);
- self = oldself;
-}
-
-void dom_spawnpoint(vector org)
-{
- entity oldself;
- oldself = self;
- self = spawn();
- self.classname = "dom_controlpoint";
- self.think = spawnfunc_dom_controlpoint;
- self.nextthink = time;
- setorigin(self, org);
- spawnfunc_dom_controlpoint();
- self = oldself;
-}
-
-// spawn some default teams if the map is not set up for domination
-void dom_spawnteams()
-{
- float numteams;
- if(autocvar_g_domination_teams_override < 2)
- numteams = autocvar_g_domination_default_teams;
- else
- numteams = autocvar_g_domination_teams_override;
- // LordHavoc: edit this if you want to change defaults
- dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
- dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
- if(numteams > 2)
- dom_spawnteam("Yellow", NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
- if(numteams > 3)
- dom_spawnteam("Pink", NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
- dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
-}
-
-void dom_delayedinit()
-{
- entity head;
-
- // if no teams are found, spawn defaults, if custom teams are set, use them
- if (find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
- dom_spawnteams();
- // if no control points are found, spawn defaults
- if (find(world, classname, "dom_controlpoint") == world)
- {
- // TODO in a few months (maybe 2011/08): change this into error() and remove this very poor dom point selection
- backtrace("This map contains no dom_controlpoint entities. A very poor dom point placement will be chosen. Please fix the map.");
-
- // if no supported map was found, make every deathmatch spawn a point
- head = find(world, classname, "info_player_deathmatch");
- while (head)
- {
- dom_spawnpoint(head.origin);
- head = find(head, classname, "info_player_deathmatch");
- }
- }
-
- ScoreRules_dom();
-}
-
-void dom_init()
-{
- // we have to precache default models/sounds even if they might not be
- // used because spawnfunc_worldspawn is executed before any other entities are read,
- // so we don't even know yet if this map is set up for domination...
- precache_model("models/domination/dom_red.md3");
- precache_model("models/domination/dom_blue.md3");
- precache_model("models/domination/dom_yellow.md3");
- precache_model("models/domination/dom_pink.md3");
- precache_model("models/domination/dom_unclaimed.md3");
- precache_sound("domination/claim.wav");
- InitializeEntity(world, dom_delayedinit, INITPRIO_GAMETYPE);
-
- addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
- addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
- addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
- if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
- if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
-}
-
+++ /dev/null
-void() movetarget_f;
-void() t_movetarget;
-void() FoundTarget;
-
-float MONSTER_WANDER = 64; // disable wandering around
-float MONSTER_APPEAR = 128; // spawn invisible, and appear when triggered
-
-.float ismonster;
-.float monsterawaitingteleport; // avoid awaking monsters in teleport rooms
-
-// when a monster becomes angry at a player, that monster will be used
-// as the sight target the next frame so that monsters near that one
-// will wake up even if they wouldn't have noticed the player
-//
-entity sight_entity;
-float sight_entity_time;
-
-/*
-
-.enemy
-Will be world if not currently angry at anyone.
-
-.movetarget
-The next path spot to walk toward. If .enemy, ignore .movetarget.
-When an enemy is killed, the monster will try to return to it's path.
-
-.huntt_ime
-Set to time + something when the player is in sight, but movement straight for
-him is blocked. This causes the monster to use wall following code for
-movement direction instead of sighting on the player.
-
-.ideal_yaw
-A yaw angle of the intended direction, which will be turned towards at up
-to 45 deg / state. If the enemy is in view and hunt_time is not active,
-this will be the exact line towards the enemy.
-
-.pausetime
-A monster will leave it's stand state and head towards it's .movetarget when
-time > .pausetime.
-
-walkmove(angle, speed) primitive is all or nothing
-*/
-
-
-//
-// globals
-//
-//float current_yaw;
-
-float(float v) anglemod =
-{
- v = v - 360 * floor(v / 360);
- return v;
-}
-
-/*
-==============================================================================
-
-MOVETARGET CODE
-
-The angle of the movetarget effects standing and bowing direction, but has no effect on movement, which allways heads to the next target.
-
-targetname
-must be present. The name of this movetarget.
-
-target
-the next spot to move to. If not present, stop here for good.
-
-pausetime
-The number of seconds to spend standing or bowing for path_stand or path_bow
-
-==============================================================================
-*/
-
-
-void() movetarget_f =
-{
- if (!self.targetname)
- objerror ("monster_movetarget: no targetname");
-
- self.solid = SOLID_TRIGGER;
- self.touch = t_movetarget;
- setsize (self, '-8 -8 -8', '8 8 8');
-}
-
-/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8)
-Monsters will continue walking towards the next target corner.
-*/
-void() path_corner =
-{
- movetarget_f ();
-}
-
-/*
-=============
-t_movetarget
-
-Something has bumped into a movetarget. If it is a monster
-moving towards it, change the next destination and continue.
-==============
-*/
-void() t_movetarget =
-{
- entity temp;
-
- if (other.health < 1)
- return;
- if (other.movetarget != self)
- return;
-
- if (other.enemy)
- return; // fighting, not following a path
-
- temp = self;
- self = other;
- other = temp;
-
- /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
- if (self.classname == "monster_ogre")
- sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound
- */
-
-//dprint ("t_movetarget\n");
- self.goalentity = self.movetarget = find (world, targetname, other.target);
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- if (!self.movetarget)
- {
- self.pausetime = time + 999999;
- self.th_stand ();
- return;
- }
-}
-
-void() monster_wanderpaththink =
-{
- vector v, v1;
- float b, c;
- self.nextthink = time + random() * 10 + 1;
- if (self.owner.health < 1) // dead, also handled in death code
- {
- self.owner.movetarget = world;
- remove(self);
- return;
- }
- b = -1;
- c = 10;
- while (c > 0)
- {
- c = c - 1;
- v = randomvec();
- traceline(self.owner.origin, v * 1024 + self.owner.origin, FALSE, self);
- v = trace_endpos - (normalize(v) * 16) - self.owner.origin;
- if (vlen(v) > b)
- {
- b = vlen(v);
- v1 = v;
- }
- }
- setorigin(self, v1 + self.owner.origin);
- self.owner.ideal_yaw = vectoyaw(self.origin - self.owner.origin);
-}
-
-void() monster_wanderpathtouch =
-{
- if (other.health < 1)
- return;
- if (other.movetarget != self)
- return;
-
- if (other.enemy)
- return; // fighting, not following a path
-
- /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
- if (other.classname == "monster_ogre")
- sound (other, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound
- */
- monster_wanderpaththink();
-}
-
-void() monster_spawnwanderpath =
-{
- newmis = spawn();
- newmis.classname = "monster_wanderpath";
- newmis.solid = SOLID_TRIGGER;
- newmis.touch = monster_wanderpathtouch;
- setsize (newmis, '-8 -8 -8', '8 8 8');
- newmis.think = monster_wanderpaththink;
- newmis.nextthink = time + random() * 10 + 1;
- newmis.owner = self;
- self.goalentity = self.movetarget = newmis;
-}
-
-void() monster_checkbossflag =
-{
-//#NO AUTOCVARS START
-#if 0
- float healthboost;
- float r;
-
- // monsterbosses cvar or spawnflag 64 causes a monster to be a miniboss
- if ((self.spawnflags & 64) || (random() * 100 < cvar("monsterbosspercent")))
- {
- self.radsuit_finished = time + 1000000000;
- r = random() * 4;
- if (r < 2)
- {
- self.super_damage_finished = time + 1000000000;
- healthboost = 30 + self.health * 0.5;
- self.effects = self.effects | (EF_FULLBRIGHT | EF_BLUE);
- }
- if (r >= 1)
- {
- healthboost = 30 + self.health * bound(0.5, skill * 0.5, 1.5);
- self.effects = self.effects | (EF_FULLBRIGHT | EF_RED);
- self.healthregen = max(self.healthregen, min(skill * 10, 30));
- }
- self.health = self.health + healthboost;
- self.max_health = self.health;
- self.bodyhealth = self.bodyhealth * 2 + healthboost;
- do
- {
- self.colormod_x = random();
- self.colormod_y = random();
- self.colormod_z = random();
- self.colormod = normalize(self.colormod);
- }
- while (self.colormod_x > 0.6 && self.colormod_y > 0.6 && self.colormod_z > 0.6);
- }
-#endif
-//#NO AUTOCVARS END
-}
-
-
-//============================================================================
-
-/*
-=============
-range
-
-returns the range catagorization of an entity reletive to self
-0 melee range, will become hostile even if back is turned
-1 visibility and infront, or visibility and show hostile
-2 infront and show hostile
-3 only triggered by damage
-=============
-*/
-float(entity targ) range =
-{
- float r;
- r = vlen ((self.origin + self.view_ofs) - (targ.origin + targ.view_ofs));
- if (r < 120)
- return RANGE_MELEE;
- if (r < 500)
- return RANGE_NEAR;
- if (r < 2000) // increased from 1000 for DP
- return RANGE_MID;
- return RANGE_FAR;
-}
-
-/*
-=============
-visible
-
-returns 1 if the entity is visible to self, even if not infront ()
-=============
-*/
-float (entity targ) visible =
-{
- if (vlen(targ.origin - self.origin) > 5000) // long traces are slow
- return FALSE;
-
- traceline ((self.origin + self.view_ofs), (targ.origin + targ.view_ofs), TRUE, self); // see through other monsters
-
- if (trace_inopen && trace_inwater)
- return FALSE; // sight line crossed contents
-
- if (trace_fraction == 1)
- return TRUE;
- return FALSE;
-}
-
-
-/*
-=============
-infront
-
-returns 1 if the entity is in front (in sight) of self
-=============
-*/
-float(entity targ) infront =
-{
- float dot;
-
- makevectors (self.angles);
- dot = normalize (targ.origin - self.origin) * v_forward;
-
- return (dot > 0.3);
-}
-// returns 0 if not infront, or the dotproduct if infront
-float(vector dir, entity targ) infront2 =
-{
- float dot;
-
- dir = normalize(dir);
- dot = normalize (targ.origin - self.origin) * dir;
-
- if (dot >= 0.3) return dot; // infront
- return 0;
-}
-
-
-//============================================================================
-
-/*
-===========
-ChangeYaw
-
-Turns towards self.ideal_yaw at self.yaw_speed
-Sets the global variable current_yaw
-Called every 0.1 sec by monsters
-============
-*/
-/*
-
-void() ChangeYaw =
-{
- float ideal, move;
-
-//current_yaw = self.ideal_yaw;
-// mod down the current angle
- current_yaw = anglemod( self.angles_y );
- ideal = self.ideal_yaw;
-
- if (current_yaw == ideal)
- return;
-
- move = ideal - current_yaw;
- if (ideal > current_yaw)
- {
- if (move > 180)
- move = move - 360;
- }
- else
- {
- if (move < -180)
- move = move + 360;
- }
-
- if (move > 0)
- {
- if (move > self.yaw_speed)
- move = self.yaw_speed;
- }
- else
- {
- if (move < 0-self.yaw_speed )
- move = 0-self.yaw_speed;
- }
-
- current_yaw = anglemod (current_yaw + move);
-
- self.angles_y = current_yaw;
-}
-
-*/
-
-
-//============================================================================
-
-void() HuntTarget =
-{
- self.goalentity = self.enemy;
- self.think = self.th_run;
- self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
- self.nextthink = time + 0.1;
- SUB_AttackFinished (1); // wait a while before first attack
-}
-
-.void() th_sightsound;
-
-void() SightSound =
-{
- if (self.health < 1)
- return;
- // skill 5 does not play sight sounds, instead you only hear the appear sound as they are about to attack
- if (skill >= 5)
- if (self.classname != "monster_hellfish")
- return;
-
- if (self.th_sightsound)
- self.th_sightsound();
-}
-
-void() FoundTarget =
-{
- if (self.health < 1 || !self.th_run)
- return;
- if (self.enemy.health < 1 || !self.enemy.takedamage)
- return;
- if (self.enemy.classname == "player")
- {
- // let other monsters see this monster for a while
- sight_entity = self;
- sight_entity_time = time + 0.1;
- }
-
- self.show_hostile = time + 1; // wake up other monsters
-
- SightSound ();
- HuntTarget ();
-}
-
-/*
-//float checkplayertime;
-entity lastcheckplayer;
-entity havocbot_list;
-
-
-entity() checkplayer =
-{
- entity check;
- float worldcount;
- // we can just fallback on checkclient if there are no bots
- if (!havocbot_list)
- return checkclient();
-*/
- /*
- if (time < checkplayertime)
- {
- traceline(self.origin + self.view_ofs, lastcheckplayer.origin + lastcheckplayer.view_ofs, TRUE, self);
- if (trace_fraction == 1)
- return lastcheckplayer;
- if (trace_ent == lastcheckplayer)
- return lastcheckplayer;
- }
- checkplayertime = time + 0.1;
- */
-/*
- check = lastcheckplayer;
- worldcount = 0;
- c = 0;
- do
- {
- c = c + 1;
- check = findfloat(check, havocattack, TRUE);
- if (check.classname == "player" || check.classname == "turretbase")
- {
- traceline(self.origin + self.view_ofs, check.origin + check.view_ofs, TRUE, self);
- if (trace_fraction == 1)
- return lastcheckplayer = check;
- if (trace_ent == check)
- return lastcheckplayer = check;
- }
- else if (check == world)
- {
- worldcount = worldcount + 1;
- if (worldcount >= 2)
- return lastcheckplayer = check;
- }
- }
- while(check != lastcheckplayer && c < 100);
- return world;
-}
-*/
-
-/*
-===========
-FindTarget
-
-Self is currently not attacking anything, so try to find a target
-
-Returns TRUE if an enemy was sighted
-
-When a player fires a missile, the point of impact becomes a fakeplayer so
-that monsters that see the impact will respond as if they had seen the
-player.
-
-To avoid spending too much time, only a single client (or fakeclient) is
-checked each frame. This means multi player games will have slightly
-slower noticing monsters.
-============
-*/
-.float findtarget;
-float() FindTarget =
-{
- entity client;
- float r;
-
- if (self.health < 1)
- return FALSE;
-
- // if the first or second spawnflag bit is set, the monster will only
- // wake up on really seeing the player, not another monster getting angry
-
- if (self.spawnflags & 3)
- {
- // don't wake up on seeing another monster getting angry
- client = checkclient ();
- if (!client)
- return FALSE; // current check entity isn't in PVS
- }
- else
- {
- if (sight_entity_time >= time)
- {
- client = sight_entity;
- if (client.enemy == self.enemy)
- return TRUE;
- }
- else
- {
- client = checkclient ();
- if (!client)
- return FALSE; // current check entity isn't in PVS
- }
- }
-
- if (client == self.enemy)
- return FALSE;
-
- if (client.flags & FL_NOTARGET)
- return FALSE;
-
-#if 0
- if (client.items & IT_INVISIBILITY)
- return FALSE;
-#endif
-
- // on skill 5 the monsters usually ignore the player and remain ghostlike
- if (skill >= 5)
- if (self.classname != "monster_hellfish")
- if (random() < 0.99)
- return FALSE;
-
- r = range(client);
- if (r == RANGE_FAR)
- return FALSE;
-
- if (!visible (client))
- return FALSE;
-
- if (r == RANGE_NEAR)
- {
- if (client.show_hostile < time && !infront (client))
- return FALSE;
- }
- else if (r == RANGE_MID)
- {
- // LordHavoc: was if ( /* client.show_hostile < time || */ !infront (client))
- if (client.show_hostile < time && !infront (client))
- return FALSE;
- }
-
- //
- // got one
- //
-
- if (client.model == "")
- return FALSE;
- self.enemy = client;
- if (self.enemy.classname != "player" && self.enemy.classname != "turretbase")
- {
- self.enemy = self.enemy.enemy;
- if (self.enemy.classname != "player" && self.enemy.classname != "turretbase")
- {
- self.enemy = world;
- return FALSE;
- }
- }
-
- FoundTarget ();
-
- return TRUE;
-}
-
-
-//=============================================================================
-
-void(float dist) ai_forward =
-{
- walkmove (self.angles_y, dist);
-}
-
-void(float dist) ai_back =
-{
- walkmove ( (self.angles_y+180), dist);
-}
-
-
-void(float a) monster_setalpha;
-
-/*
-=============
-ai_pain
-
-stagger back a bit
-=============
-*/
-void(float dist) ai_pain =
-{
- if (self.health < 1)
- return;
- ai_back (dist);
-}
-
-/*
-=============
-ai_painforward
-
-stagger back a bit
-=============
-*/
-void(float dist) ai_painforward =
-{
- if (self.health < 1)
- return;
- walkmove (self.ideal_yaw, dist);
-}
-
-/*
-=============
-ai_walk
-
-The monster is walking it's beat
-=============
-*/
-void(float dist) ai_walk =
-{
- if (self.health < 1)
- return;
-
- movedist = dist;
-
- // check for noticing a player
- if (self.oldenemy.takedamage)
- if (self.oldenemy.health >= 1)
- {
- self.enemy = self.oldenemy;
- self.oldenemy = world;
- FoundTarget();
- monster_setalpha(0);
- return;
- }
- if (self.enemy)
- {
- if (self.enemy.takedamage)
- {
- if (self.enemy.health >= 1)
- {
- FoundTarget();
- monster_setalpha(0);
- return;
- }
- else
- self.enemy = world;
- }
- else
- self.enemy = world;
- }
-
- self.findtarget = TRUE;
-
- movetogoal (dist);
- monster_setalpha(0);
-}
-
-
-/*
-=============
-ai_stand
-
-The monster is staying in one place for a while, with slight angle turns
-=============
-*/
-void() ai_stand =
-{
- if (self.health < 1)
- return;
- if (self.enemy)
- {
- if (self.enemy.takedamage)
- {
- if (self.enemy.health >= 1)
- {
- FoundTarget();
- monster_setalpha(0);
- return;
- }
- else
- self.enemy = world;
- }
- else
- self.enemy = world;
- }
- self.findtarget = TRUE;
-
- if (time > self.pausetime)
- {
- self.th_walk ();
- monster_setalpha(0);
- return;
- }
-
-// change angle slightly
-
- monster_setalpha(0);
-}
-
-/*
-=============
-ai_turn
-
-don't move, but turn towards ideal_yaw
-=============
-*/
-void() ai_turn =
-{
- if (self.enemy)
- {
- if (self.enemy.takedamage)
- {
- if (self.enemy.health >= 1)
- {
- FoundTarget();
- monster_setalpha(0);
- return;
- }
- else
- self.enemy = world;
- }
- else
- self.enemy = world;
- }
- self.findtarget = TRUE;
-
- ChangeYaw ();
- monster_setalpha(0);
-}
-
-//=============================================================================
-
-/*
-=============
-ChooseTurn
-=============
-*/
-void(vector pDestvec) ChooseTurn =
-{
- vector dir, newdir;
-
- dir = self.origin - pDestvec;
-
- newdir_x = trace_plane_normal_y;
- newdir_y = 0 - trace_plane_normal_x;
- newdir_z = 0;
-
- if (dir * newdir > 0)
- {
- dir_x = 0 - trace_plane_normal_y;
- dir_y = trace_plane_normal_x;
- }
- else
- {
- dir_x = trace_plane_normal_y;
- dir_y = 0 - trace_plane_normal_x;
- }
-
- dir_z = 0;
- self.ideal_yaw = vectoyaw(dir);
-}
-
-/*
-============
-FacingIdeal
-
-============
-*/
-float() FacingIdeal =
-{
- float delta;
-
- delta = anglemod(self.angles_y - self.ideal_yaw);
- if (delta > 45 && delta < 315)
- return FALSE;
- return TRUE;
-}
-
-
-//=============================================================================
-
-.float() th_checkattack;
-
-
-
-/*
-=============
-ai_run
-
-The monster has an enemy it is trying to kill
-=============
-*/
-void(float dist) ai_run =
-{
- float ofs;
- if (self.health < 1)
- return;
- movedist = dist;
- // see if the enemy is dead
- if (self.enemy.health < 1 || self.enemy.takedamage == DAMAGE_NO)
- {
- self.enemy = world;
- // FIXME: look all around for other targets
- if (self.oldenemy.health >= 1 && self.oldenemy.takedamage)
- {
- self.enemy = self.oldenemy;
- self.oldenemy = world;
- HuntTarget ();
- }
- else
- {
- if (self.movetarget)
- self.th_walk ();
- else
- self.th_stand ();
- return;
- }
- }
-
- // wake up other monsters
- self.show_hostile = time + 1;
-
- // check knowledge of enemy
- enemy_range = range(self.enemy);
-
- self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
- ChangeYaw ();
-
- if (self.attack_state == AS_MELEE)
- {
- //dprint ("ai_run_melee\n");
- //Turn and close until within an angle to launch a melee attack
- if (FacingIdeal())
- {
- self.th_melee ();
- self.attack_state = AS_STRAIGHT;
- }
- return;
- }
- else if (self.attack_state == AS_MISSILE)
- {
- //dprint ("ai_run_missile\n");
- //Turn in place until within an angle to launch a missile attack
- if (FacingIdeal())
- if (self.th_missile ())
- self.attack_state = AS_STRAIGHT;
- return;
- }
-
- if (self.th_checkattack())
- return; // beginning an attack
-
- if (visible(self.enemy))
- self.search_time = time + 5;
- else if (coop)
- {
- // look for other coop players
- if (self.search_time < time)
- self.findtarget = TRUE;
- }
-
- if (self.attack_state == AS_SLIDING)
- {
- //dprint ("ai_run_slide\n");
- //Strafe sideways, but stay at aproximately the same range
- if (self.lefty)
- ofs = 90;
- else
- ofs = -90;
-
- if (walkmove (self.ideal_yaw + ofs, movedist))
- return;
-
- self.lefty = !self.lefty;
-
- walkmove (self.ideal_yaw - ofs, movedist);
- }
-
- // head straight in
- movetogoal (dist); // done in C code...
-}
-
+++ /dev/null
-.entity movetarget;
-.float pausetime;
-
-.void() th_stand;
-.void() th_walk;
-.void() th_run;
-.float() th_missile; // LordHavoc: changed from void() to float(), returns true if attacking
-.void() th_melee;
-//.void(entity attacker, float damage, float damgtype, string dethtype) th_pain; // TODO Xonotic uses event_damage
-//.void() th_die; // TODO never called directly by Xonotic
-.entity oldenemy; // mad at this player before taking damage
-entity newmis; // launch_spike sets this after spawning it
-
-// range values
-float RANGE_MELEE = 0;
-float RANGE_NEAR = 1;
-float RANGE_MID = 2;
-float RANGE_FAR = 3;
-
-float DMG_KNIGHT_MELEE_BASE = 0;
-float DMG_KNIGHT_MELEE_RANDOM1 = 3;
-float DMG_KNIGHT_MELEE_RANDOM2 = 3;
-float DMG_KNIGHT_MELEE_RANDOM3 = 3;
-
-.float show_hostile;
- // set to time+0.2 whenever a client fires a
- // weapon or takes damage. Used to alert
- // monsters that otherwise would let the player go
-
-float movedist;
-.float lefty;
-.float search_time;
-.float attack_state;
-
-float AS_STRAIGHT = 1;
-float AS_SLIDING = 2;
-float AS_MELEE = 3;
-float AS_MISSILE = 4;
-
-float SKILL4_MINALPHA = 0.4;
-
-float monsterwander;
-//#NO AUTOCVARS START
-/*
- monsterwander = cvar("monsterwander");
- // monsterwander is always on in skill 5
- if (skill >= 5)
- monsterwander = TRUE;
-*/
-//#NO AUTOCVARS END
-
-.float candrown;
-
-.void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) bleedfunc;
-void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) genericbleedfunc;
+++ /dev/null
-
-/*
-
-A monster is in fight mode if it thinks it can effectively attack its
-enemy.
-
-When it decides it can't attack, it goes into hunt mode.
-
-*/
-
-void SUB_AttackFinished (float normal)
-{
- self.cnt = 0; // refire count for nightmare
- if (skill < 3)
- ATTACK_FINISHED(self) = time + normal;
-}
-
-float CanDamage(entity targ, entity inflictor)
-{
- if (targ.movetype == MOVETYPE_PUSH)
- {
- traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
- if (trace_ent == targ)
- return TRUE;
- return FALSE;
- }
-
- traceline(inflictor.origin, targ.origin, TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
- traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
- traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
- traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
- traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
- if (trace_fraction == 1)
- return TRUE;
-
- return FALSE;
-}
-
-float(float v) anglemod;
-
-void(vector dest) ChooseTurn;
-
-void() ai_face;
-
-
-float enemy_range;
-
-
-//=============================================================================
-
-/*
-===========
-GenericCheckAttack
-
-The player is in view, so decide to move or launch an attack
-Returns FALSE if movement should continue
-============
-*/
-float() GenericCheckAttack =
-{
- vector spot1, spot2;
- entity targ;
- float chance;
-
- if (self.health < 1)
- return FALSE;
- targ = self.enemy;
-
- if (vlen(targ.origin - self.origin) > 5000) // long traces are slow
- return FALSE;
-
-// see if any entities are in the way of the shot
- spot1 = self.origin + self.view_ofs;
- spot2 = targ.origin + targ.view_ofs;
-
- traceline (spot1, spot2, FALSE, self);
-
- if (trace_ent != targ)
- return FALSE; // don't have a clear shot
-
- if (trace_inopen && trace_inwater)
- return FALSE; // sight line crossed contents
-
- if (enemy_range == RANGE_MELEE)
- { // melee attack
- if (self.th_melee)
- {
- self.th_melee ();
- return TRUE;
- }
- }
-
-// missile attack
- if (time < ATTACK_FINISHED(self))
- return FALSE;
-
- if (!self.th_missile)
- return FALSE;
-
- if (enemy_range == RANGE_FAR)
- return FALSE;
-
- if (enemy_range == RANGE_MELEE)
- {
- chance = 0.9;
- ATTACK_FINISHED(self) = 0;
- }
- else if (enemy_range == RANGE_NEAR)
- {
- if (self.th_melee)
- chance = 0.2;
- else
- chance = 0.4;
- }
- else if (enemy_range == RANGE_MID)
- {
- if (self.th_melee)
- chance = 0.05;
- else
- chance = 0.1;
- }
- else
- chance = 0;
-
- if (random () < chance)
- if (self.th_missile ())
- {
- SUB_AttackFinished (2*random());
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-/*
-=============
-ai_face
-
-Stay facing the enemy
-=============
-*/
-void() ai_face =
-{
- self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
- ChangeYaw ();
-}
-
-/*
-=============
-ai_charge
-
-The monster is in a melee attack, so get as close as possible to .enemy
-=============
-*/
-float (entity targ) visible;
-float(entity targ) infront;
-float(entity targ) range;
-
-void(float d) ai_charge =
-{
- if (self.health < 1)
- return;
- ai_face ();
- movetogoal (d); // done in C code...
-}
-
-void() ai_charge_side =
-{
- if (self.health < 1)
- return;
- vector dtemp;
- float heading;
-
-// aim to the left of the enemy for a flyby
-
- self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
- ChangeYaw ();
-
- makevectors (self.angles);
- dtemp = self.enemy.origin - 30*v_right;
- heading = vectoyaw(dtemp - self.origin);
-
- walkmove(heading, 20);
-}
-
-
-/*
-=============
-ai_melee
-
-=============
-*/
-void() ai_melee =
-{
- vector delta;
- float ldmg;
-
- if (self.health < 1)
- return;
- if (!self.enemy)
- return; // removed before stroke
-
- delta = self.enemy.origin - self.origin;
-
- if (vlen(delta) > 60)
- return;
-
- ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
- ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
- ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
- traceline(self.origin, self.enemy.origin, FALSE, self);
-
- Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); // TODO add force to monster melee attacks?
-}
-
-
-void() ai_melee_side =
-{
- vector delta;
- float ldmg;
-
- if (self.health < 1)
- return;
- if (!self.enemy)
- return; // removed before stroke
-
- ai_charge_side();
-
- delta = self.enemy.origin - self.origin;
-
- if (vlen(delta) > 60)
- return;
- if (!CanDamage (self.enemy, self))
- return;
- ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
- ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
- ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
- traceline(self.origin, self.enemy.origin, FALSE, self);
- Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0');
-}
-
+++ /dev/null
-/* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */
-
-// name =[framenum, nexttime, nextthink] {code}
-// expands to:
-// name ()
-// {
-// self.frame=framenum;
-// self.nextthink = time + nexttime;
-// self.think = nextthink
-// <code>
-// }
-
-.float ismonster;
-
-.float modelindex2;
-
-/*
-================
-monster_use
-
-Using a monster makes it angry at the current activator
-LordHavoc: using a monster with the spawnflag 'Appear' makes it appear
-================
-*/
-void() monster_use =
-{
- if (self.enemy)
- return;
- if (self.health < 1)
- return;
- if (self.mdl)
- if (self.spawnflags & MONSTER_APPEAR)
- {
- self.nextthink = time + 0.1;
- self.spawnflags = self.spawnflags - MONSTER_APPEAR;
- self.solid = SOLID_SLIDEBOX;
- self.takedamage = DAMAGE_AIM;
- //self.movetype = MOVETYPE_STEP;
- self.model = self.mdl;
- self.mdl = "";
- self.modelindex = self.modelindex2;
- self.modelindex2 = 0;
- //setorigin(self, self.origin + '0 0 1');
- spawn_tdeath(self.origin, self, self.origin);
- return;
- }
-
-#if 0
- if (activator.items & IT_INVISIBILITY)
- return;
-#endif
- if (activator.flags & FL_NOTARGET)
- return;
- if (activator.classname != "player")
- return;
-
- // delay reaction so if the monster is teleported, its sound is still heard
- self.enemy = activator;
- self.nextthink = time + 0.1;
- self.think = FoundTarget;
-}
-
-void() monster_appearsetup =
-{
- if ((self.spawnflags & MONSTER_APPEAR) == 0)
- return;
- self.mdl = self.model;
- self.modelindex2 = self.modelindex;
- self.modelindex = 0;
- self.solid = SOLID_NOT;
- self.takedamage = DAMAGE_NO;
- //self.movetype = MOVETYPE_NONE;
- self.nextthink = -1;
- self.model = "";
-}
-
-/*
-================
-monster_setalpha
-
-Sets relative alpha of monster in skill 4 mode.
-================
-*/
-void(float a) monster_setalpha =
-{
- if (skill < 4 || self.classname == "monster_hellfish")
- {
- self.alpha = 1.0;
- return;
- }
-
- if (skill >= 5)
- {
- // randomly forget enemy, this makes monsters randomly return to their normal ghostlike state
- if (a == 0)
- if (self.enemy)
- if (random() < 0.1)
- self.enemy = world;
- // randomly blink (playing the same alarming sound as if attacking)
- if (self.enemy == world)
- {
- a = 0;
- if (time >= 0.3) // don't blink during the init process because it might become permanent
- if (random() < 0.005)
- {
- // blink for an instant, this causes the appear sound, alarming the player as if under attack
- /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
- sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM);
- */
- a = 1;
- }
- }
- // if ghosted, become non-solid and immune to damage
- if (a <= 0 || self.enemy == world)
- {
- self.solid = SOLID_NOT;
- self.takedamage = DAMAGE_NO;
- }
- else
- {
- // if unghosting, make sure we have an enemy, otherwise stay ghosted (even if blinking) so we can't be shot while blinking
- /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
- if (self.solid != SOLID_SLIDEBOX)
- sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM);
- */
- self.solid = SOLID_SLIDEBOX;
- self.takedamage = DAMAGE_AIM;
- }
- }
- self.alpha = SKILL4_MINALPHA + (1 - SKILL4_MINALPHA) * bound(0, a, 1);
-}
-
-/*
-================
-monster_death_use
-
-When a mosnter dies, it fires all of its targets with the current
-enemy as activator.
-================
-*/
-void() monster_death_use =
-{
-// fall to ground
- if (self.flags & FL_FLY)
- self.flags = self.flags - FL_FLY;
- if (self.flags & FL_SWIM)
- self.flags = self.flags - FL_SWIM;
-
- if (!self.target)
- return;
-
- activator = self.enemy;
- SUB_UseTargets ();
-}
-
-
-void() monsterinwall =
-{
- entity e;
- if (!autocvar_developer)
- return;
- // this is handy for level designers,
- // puts a spikey ball where the error is...
- e = spawn();
- setorigin(e, self.origin);
- setmodel (e, "models/ebomb.mdl");
- e.movetype = MOVETYPE_NONE;
- e.solid = SOLID_NOT;
- e.think = func_null;
- e.nextthink = -1;
- e.scale = 16;
-}
-
-//============================================================================
-
-void() walkmonster_start_go =
-{
- self.origin_z = self.origin_z + 1; // raise off floor a bit
-
- tracebox(self.origin, self.mins, self.maxs, self.origin, TRUE, self);
- if (trace_startsolid)
- {
- dprint("walkmonster in wall at: ");
- dprint(vtos(self.origin));
- dprint("\n");
- monsterinwall();
- droptofloor();
- }
- else
- {
- droptofloor();
- if (!walkmove(0,0))
- {
- dprint("walkmonster in wall at: ");
- dprint(vtos(self.origin));
- dprint("\n");
- monsterinwall();
- }
- }
-
- //self.cantrigger = TRUE;
-
- self.takedamage = DAMAGE_AIM;
-
- self.ideal_yaw = self.angles * '0 1 0';
- if (!self.yaw_speed)
- self.yaw_speed = 20;
- self.view_ofs = '0 0 25';
- self.use = monster_use;
-
- self.flags = self.flags | FL_MONSTER;
-
- if (monsterwander)
- self.spawnflags = self.spawnflags | MONSTER_WANDER;
-
- if (self.target)
- {
- self.goalentity = self.movetarget = find(world, targetname, self.target);
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- if (!self.movetarget)
- {
- dprint("Monster can't find target at ");
- dprint(vtos(self.origin));
- dprint("\n");
- }
- // this used to be an objerror
- if (self.movetarget.classname == "path_corner")
- self.th_walk ();
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
- }
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
-
-// spread think times so they don't all happen at same time
- self.nextthink = self.nextthink + random()*0.5 + 0.1;
- self.iscreature = TRUE;
- self.teleportable = TELEPORT_NORMAL;
- self.damagedbycontents = TRUE;
-
- force_retouch = 2; // mainly to detect teleports
-
- monster_appearsetup();
-}
-
-
-void() walkmonster_start =
-{
- self.candrown = 1; // this is turned off by some monsters like zombies
- // delay drop to floor to make sure all doors have been spawned
- // spread think times so they don't all happen at same time
- self.nextthink = time + random()*0.5 + 0.3;
- self.think = walkmonster_start_go;
- total_monsters = total_monsters + 1;
- self.bot_attack = TRUE;
- self.frags = 2; // actually just used to get havocbots to attack it...
- self.bleedfunc = genericbleedfunc;
- self.ismonster = TRUE;
-
- monster_setalpha (0);
-}
-
-
-
-void() flymonster_start_go =
-{
- self.takedamage = DAMAGE_AIM;
-
- self.ideal_yaw = self.angles * '0 1 0';
- if (!self.yaw_speed)
- self.yaw_speed = 10;
- self.view_ofs = '0 0 25';
- self.use = monster_use;
-
- self.flags = self.flags | FL_FLY;
- self.flags = self.flags | FL_MONSTER;
-
- if (!walkmove(0,0))
- {
- dprint("flymonster in wall at: ");
- dprint(vtos(self.origin));
- dprint("\n");
- monsterinwall();
- }
-
- //self.cantrigger = TRUE;
-
- if (monsterwander)
- self.spawnflags = self.spawnflags | MONSTER_WANDER;
-
- if (self.target)
- {
- self.goalentity = self.movetarget = find(world, targetname, self.target);
- if (!self.movetarget)
- {
- dprint("Monster can't find target at ");
- dprint(vtos(self.origin));
- dprint("\n");
- }
- // this used to be an objerror
- if (self.movetarget.classname == "path_corner")
- self.th_walk ();
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
- }
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
- self.iscreature = TRUE;
- self.teleportable = TELEPORT_NORMAL;
- self.damagedbycontents = TRUE;
-
- force_retouch = 2; // mainly to detect teleports
-
- monster_appearsetup();
-}
-
-void() flymonster_start =
-{
- self.candrown = 1;
- // spread think times so they don't all happen at same time
- self.nextthink = time + random()*0.5 + 0.1;
- self.think = flymonster_start_go;
- total_monsters = total_monsters + 1;
- self.bot_attack = TRUE;
- self.frags = 2; // actually just used to get havocbots to attack it...
- self.bleedfunc = genericbleedfunc;
- self.ismonster = TRUE;
-
- monster_setalpha (0);
-}
-
-
-void() swimmonster_start_go =
-{
- if (deathmatch)
- {
- remove(self);
- return;
- }
-
- //self.cantrigger = TRUE;
-
- self.takedamage = DAMAGE_AIM;
-
- self.ideal_yaw = self.angles * '0 1 0';
- if (!self.yaw_speed)
- self.yaw_speed = 10;
- self.view_ofs = '0 0 10';
- self.use = monster_use;
-
- self.flags = self.flags | FL_SWIM;
- self.flags = self.flags | FL_MONSTER;
-
- if (monsterwander)
- self.spawnflags = self.spawnflags | MONSTER_WANDER;
-
- if (self.target)
- {
- self.goalentity = self.movetarget = find(world, targetname, self.target);
- if (!self.movetarget)
- {
- dprint("Monster can't find target at ");
- dprint(vtos(self.origin));
- dprint("\n");
- }
- // this used to be an objerror
- if (self.movetarget.classname == "path_corner")
- self.th_walk ();
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
- }
- else
- {
- if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
- {
- monster_spawnwanderpath();
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.th_walk ();
- }
- else
- {
- self.pausetime = 99999999;
- self.th_stand ();
- }
- }
- self.iscreature = TRUE;
- self.teleportable = TELEPORT_NORMAL;
- self.damagedbycontents = TRUE;
-
- force_retouch = 2; // mainly to detect teleports
-
- monster_appearsetup();
-}
-
-void() swimmonster_start =
-{
- // spread think times so they don't all happen at same time
- self.candrown = 0;
- self.nextthink = time + random()*0.5 + 0.1;
- self.think = swimmonster_start_go;
- total_monsters = total_monsters + 1;
- self.bot_attack = TRUE;
- self.frags = 2; // actually just used to get havocbots to attack it...
- self.bleedfunc = genericbleedfunc;
- self.ismonster = TRUE;
-
- monster_setalpha(0);
-}
-
-void(vector org, float bodydamage, float armordamage, vector force, float damgtype) genericbleedfunc =
-{
- vector v;
- v = '0 0 0' - force * 0.05;
- if (armordamage > 0)
- te_spark(org, v, armordamage * 3);
- if (bodydamage > 0)
- te_blood(org, v, bodydamage);
-}
+++ /dev/null
-//#define MONSTES_ENABLED
-#ifdef MONSTES_ENABLED
-
-float autocvar_g_monster_zombie_attack_run_damage;
-float autocvar_g_monster_zombie_attack_run_delay;
-float autocvar_g_monster_zombie_attack_run_force;
-float autocvar_g_monster_zombie_attack_run_hitrange;
-float autocvar_g_monster_zombie_attack_run_range;
-float autocvar_g_monster_zombie_attack_stand_damage;
-float autocvar_g_monster_zombie_attack_stand_delay;
-float autocvar_g_monster_zombie_attack_stand_force;
-float autocvar_g_monster_zombie_attack_stand_range;
-float autocvar_g_monster_zombie_health;
-float autocvar_g_monster_zombie_idle_timer_max;
-float autocvar_g_monster_zombie_idle_timer_min;
-float autocvar_g_monster_zombie_movespeed;
-float autocvar_g_monster_zombie_respawntime;
-float autocvar_g_monster_zombie_stopspeed;
-float autocvar_g_monster_zombie_targetrange;
-float autocvar_g_monster_zombie_turnspeed;
-float autocvar_g_monsters;
-
-
-#define zombie_anim_attackleap 0
-#define zombie_anim_attackrun1 1
-#define zombie_anim_attackrun2 2
-#define zombie_anim_attackrun3 3
-#define zombie_anim_attackstanding1 4
-#define zombie_anim_attackstanding2 5
-#define zombie_anim_attackstanding3 6
-#define zombie_anim_blockend 7
-#define zombie_anim_blockstart 8
-#define zombie_anim_deathback1 9
-#define zombie_anim_deathback2 10
-#define zombie_anim_deathback3 11
-#define zombie_anim_deathfront1 12
-#define zombie_anim_deathfront2 13
-#define zombie_anim_deathfront3 14
-#define zombie_anim_deathleft1 15
-#define zombie_anim_deathleft2 16
-#define zombie_anim_deathright1 17
-#define zombie_anim_deathright2 18
-#define zombie_anim_idle 19
-#define zombie_anim_painback1 20
-#define zombie_anim_painback2 21
-#define zombie_anim_painfront1 22
-#define zombie_anim_painfront2 23
-#define zombie_anim_runbackwards 24
-#define zombie_anim_runbackwardsleft 25
-#define zombie_anim_runbackwardsright 26
-#define zombie_anim_runforward 27
-#define zombie_anim_runforwardleft 28
-#define zombie_anim_runforwardright 29
-#define zombie_anim_spawn 30
-
-#define ZOMBIE_MIN '-18 -18 -25'
-#define ZOMBIE_MAX '18 18 47'
-
-#define ZV_IDLE 10
-
-#define ZV_PATH 100
-#define ZV_HUNT 200
-
-#define ZV_ATTACK_FIND 10
-#define ZV_ATTACK_RUN 20
-#define ZV_ATTACK_STAND 30
-
-#define ZV_PATH2 10000
-
-//.entity verbs_idle;
-//.entity verbs_attack;
-//.entity verbs_move;
-
-//.float state_timeout;
-//.void() monster_state;
-#define MONSTERFLAG_NORESPAWN 2
-
-void zombie_spawn();
-
-float zombie_scoretarget(entity trg)
-{
- float tmp;
- vector ang1;
-
- if (trg.takedamage == DAMAGE_AIM)
- if not (trg.flags & FL_NOTARGET)
- if (trg.deadflag == DEAD_NO)
- if (trg.team != self.team)
- {
- if((self.origin_z - trg.origin_z) < 128)
- {
- ang1 = normalize(self.origin - trg.origin);
- tmp = vlen(ang1 - v_forward);
- if(tmp > 1.5)
- {
- traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self);
- if(trace_ent != trg)
- return 0;
-
- return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp;
- }
- else if(self.enemy == trg)
- return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp;
- }
- }
-
- return 0;
-}
-
-void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
- //dprint("zombie_corpse_damage\n");
- Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
-
- self.health -= damage;
-
- if(self.health < 0)
- {
- Violence_GibSplash(self, 1, 1, attacker);
- remove(self);
- }
-}
-
-void zombie_die(vector dir)
-{
- vector v;
- float f;
-
- entity dummy;
-
- dummy = spawn();
- setmodel(dummy,"models/monsters/zombie.dpm");
- setorigin(dummy, self.origin);
- dummy.velocity = self.velocity;
- dummy.movetype = MOVETYPE_BOUNCE;
- dummy.think = SUB_Remove;
- dummy.nextthink = time + 3;
- dummy.health = 50;
- dummy.takedamage = DAMAGE_YES;
- dummy.event_damage = zombie_corpse_damage;
- dummy.solid = SOLID_CORPSE;
- setsize(dummy,self.mins,self.maxs);
-
- SUB_SetFade(dummy,time + 5,2);
-
-
- v = normalize(self.origin - dir);
- f = vlen(v_forward - v) - 1;
- if(f > 0.5)
- dummy.frame = zombie_anim_deathfront1 + rint(random() * 2);
- else if(f < 0.5)
- dummy.frame = zombie_anim_deathback1 + rint(random() * 2);
- else
- {
- f = vlen(v_right - v) - 1;
- if(f > 0.5)
- dummy.frame = zombie_anim_deathright1 + rint(random() * 2);
- else if(f < 0.5)
- dummy.frame = zombie_anim_deathleft1 + rint(random() * 2);
- }
-
-
- if(self.spawnflags & MONSTERFLAG_NORESPAWN)
- {
- self.think = SUB_Remove;
- self.nextthink = time;
- return;
- }
-
- setmodel(self,"");
- self.solid = SOLID_NOT;
- self.takedamage = DAMAGE_NO;
- self.event_damage = func_null;
- self.enemy = world;
- self.think = zombie_spawn;
- self.nextthink = time + autocvar_g_monster_zombie_respawntime;
- self.pain_finished = self.nextthink;
-}
-
-void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
-
- vector v;
- float f;
-
- v = normalize(self.origin - hitloc);
- f = vlen(v_forward - v) - 1;
-
-
- self.health -= damage;
- self.velocity = self.velocity + force;
- if(self.health <= 0)
- {
- zombie_die(hitloc);
- return;
- }
-
- Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
-
- if (damage > 50)
- Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker);
- if (damage > 100)
- Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker);
-
- if (time > self.pain_finished)
- {
- if(f < 0.5)
- {
- if(random() < 0.5)
- self.frame = zombie_anim_painback1;
- else
- self.frame = zombie_anim_painback2;
- }
- else
- {
- if(random() < 0.5)
- self.frame = zombie_anim_painfront1;
- else
- self.frame = zombie_anim_painfront2;
- }
-
- self.pain_finished = time + 0.36;
- }
-}
-
-.vector bvec;
-.float bvec_time;
-
-void zombie_move()
-{
- vector real_angle;
- float vz, tdiff, tspeed;
-
- tdiff = time - self.zoomstate;
- tspeed = tdiff * autocvar_g_monster_zombie_turnspeed;
- vz = self.velocity_z;
- self.zoomstate = time;
-
- if(self.bvec_time < time)
- {
- self.bvec_time = time + 0.2;
- self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64);
- }
-
- if(self.enemy)
- self.moveto = self.enemy.origin;
- else
- self.moveto = self.origin + v_forward;
-
- self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec);
-
- self.angles_y = safeangle(self.angles_y);
- real_angle = vectoangles(self.steerto) - self.angles;
- self.angles_y += bound(-10, real_angle_y, 10);
-
- if(vlen(self.origin - self.moveto) > 64)
- {
- movelib_move_simple(v_forward ,autocvar_g_monster_zombie_movespeed,0.6);
- if(time > self.pain_finished)
- if(self.attack_finished_single < time)
- self.frame = zombie_anim_runforward;
- }
- else
- {
- movelib_beak_simple(autocvar_g_monster_zombie_stopspeed);
- if(time > self.pain_finished)
- if(self.attack_finished_single < time)
- self.frame = zombie_anim_idle;
- }
-
- self.velocity_z = vz;
- self.steerto = self.origin;
-}
-
-float zombie_verb_idle_roam(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
-
- if(self.enemy)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
-
- self.moveto = v_forward * 128;
- self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64);
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-float zombie_verb_idle_stand(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
-
- if(self.enemy)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
-
- self.moveto = self.origin;
- self.frame = zombie_anim_idle;
- self.velocity = '0 0 0';
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-float zombie_verb_idle(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
-
- if(self.enemy)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
- float t;
-
- t = autocvar_g_monster_zombie_idle_timer_max - autocvar_g_monster_zombie_idle_timer_min;
- t = autocvar_g_monster_zombie_idle_timer_min + (random() * t);
-
- if(random() < 0.5)
- verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self);
- else
- verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self);
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-float zombie_verb_attack_findtarget(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
- if(self.enemy)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
-
- entity trg, best_trg;
- float trg_score, best_trg_score;
-
- trg = findradius(self.origin,autocvar_g_monster_zombie_targetrange);
- while(trg)
- {
- trg_score = zombie_scoretarget(trg);
- if(trg_score > best_trg_score)
- {
- best_trg = trg;
- best_trg_score = trg_score;
- }
-
- trg = trg.chain;
- }
-
- if(best_trg)
- {
- self.enemy = best_trg;
- dprint("Selected: ",best_trg.netname, " as target.\n");
- }
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-void zombie_runattack_damage()
-{
- entity oldself;
- oldself = self;
- self = self.owner;
-
- if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_hitrange)
- return;
-
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
- return;
-
- Damage(self.enemy, self, self, autocvar_g_monster_zombie_attack_run_damage, DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * autocvar_g_monster_zombie_attack_run_force);
-
- self = oldself;
- self.think = SUB_Remove;
- self.nextthink = time;
-}
-
-float zombie_verb_attack_run(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
- if not (self.enemy)
- return VS_CALL_NO;
-
- if(self.attack_finished_single > time)
- return VS_CALL_NO;
-
- if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_range)
- return VS_CALL_NO;
-
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
- entity pain;
- pain = spawn();
- pain.owner = self;
- pain.think = zombie_runattack_damage;
- pain.nextthink = time + autocvar_g_monster_zombie_attack_run_delay;
-
- self.attack_finished_single = time + 0.7;
- self.frame = zombie_anim_attackrun1 + rint(random() * 2);
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-void zombie_standattack_damage()
-{
- //entity oldself;
- //oldself = self;
- //self = self.owner;
-
- setorigin(self,self.owner.origin + v_forward * 32);
- RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world);
- //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
-
-
- //self = oldself;
- self.think = SUB_Remove;
- self.nextthink = time;
-}
-
-float zombie_verb_attack_stand(float eval)
-{
- switch (eval)
- {
- case VCM_EVAL:
- if not (self.enemy)
- return VS_CALL_NO;
-
- if(self.attack_finished_single > time)
- return VS_CALL_NO;
-
- if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_stand_range)
- return VS_CALL_NO;
-
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8)
- return VS_CALL_NO;
-
- return verb.verb_static_value;
-
- case VCM_DO:
- entity pain;
- pain = spawn();
- pain.owner = self;
- pain.think = zombie_runattack_damage;
- pain.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay;
-
- self.attack_finished_single = time + 0.7;
- self.frame = zombie_anim_attackstanding1 + rint(random() * 1);
- dprint("frame:",ftos(self.frame),"\n");
-
- return VS_CALL_YES_DOING;
- }
-
- return VS_CALL_YES_DONE;
-}
-
-void zombie_think()
-{
- self.angles_x *= -1;
- makevectors(self.angles);
- self.angles_x *= -1;
-
- if (zombie_scoretarget(self.enemy) == 0)
- self.enemy = world;
-
- verbstack_pop(self.verbs_attack);
- //verbstack_pop(self.verbs_move);
-
- if not (self.enemy)
- verbstack_pop(self.verbs_idle);
-
- zombie_move();
-
- if(self.enemy)
- self.nextthink = time;
- else
- self.nextthink = time + 0.2;
-}
-
-void zombie_spawn()
-{
- setmodel(self,"models/monsters/zombie.dpm");
-
- self.solid = SOLID_BBOX;
- self.takedamage = DAMAGE_AIM;
- self.event_damage = zombie_damage;
- self.enemy = world;
- self.frame = zombie_anim_spawn;
- self.think = zombie_think;
- self.nextthink = time + 2.1;
- self.pain_finished = self.nextthink;
- self.movetype = MOVETYPE_WALK;
- self.health = autocvar_g_monster_zombie_health;
- self.velocity = '0 0 0';
- self.angles = self.pos2;
- self.moveto = self.origin;
- self.flags = FL_MONSTER;
-
- setorigin(self,self.pos1);
- setsize(self,ZOMBIE_MIN,ZOMBIE_MAX);
-}
-
-
-void spawnfunc_monster_zombie()
-{
- if not(autocvar_g_monsters)
- {
- remove(self);
- return;
- }
-
- precache_model("models/monsters/zombie.dpm");
-
-
- self.verbs_idle = spawn();
- self.verbs_attack = spawn();
-
- self.verbs_idle.owner = self;
- self.verbs_attack.owner = self;
-
- self.think = zombie_spawn;
- self.nextthink = time + 2;
-
- traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self);
-
- self.pos1 = trace_endpos;
- self.pos2 = self.angles;
- self.team = MAX_SHOT_DISTANCE -1;
-
- verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self);
-
- verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self);
- verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self);
- verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self);
-
-}
-
-#endif // MONSTES_ENABLED
+++ /dev/null
-//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
-#define BALL_EFFECTMASK 1229
-#define BALL_MINS '-16 -16 -16' // The model is 24*24*24
-#define BALL_MAXS '16 16 16'
-#define BALL_ATTACHORG '3 0 16'
-#define BALL_SPRITECOLOR '.91 .85 .62'
-#define BALL_FOOT 1
-#define BALL_BASKET 2
-//spawnflags
-#define GOAL_TOUCHPLAYER 1
-//goal types
-#define GOAL_FAULT -1
-#define GOAL_OUT -2
-
-#define CVTOV(s) s = cvar( #s )
-
-float g_nexball_football_boost_forward;
-float g_nexball_football_boost_up;
-float g_nexball_football_physics;
-float g_nexball_delay_idle;
-float g_nexball_basketball_delay_hold;
-float g_nexball_basketball_delay_hold_forteam;
-float g_nexball_basketball_effects_default;
-float g_nexball_basketball_teamsteal;
-float balls;
-float ball_scale;
-float nb_teams;
-
-.float teamtime;
-
-.float nb_dropperid;
-.float nb_droptime;
-
-void nb_delayedinit();
-void nb_init() // Called early (worldspawn stage)
-{
- CVTOV(g_nexball_meter_period); //sent with the client init entity
- if (g_nexball_meter_period <= 0)
- g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
- g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
- addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
-
- // General settings
- CVTOV(g_nexball_football_boost_forward); //100
- CVTOV(g_nexball_football_boost_up); //200
- CVTOV(g_nexball_delay_idle); //10
- CVTOV(g_nexball_football_physics); //0
-
- radar_showennemies = autocvar_g_nexball_radar_showallplayers;
-
- InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
-}
-
-float OtherTeam(float t) //works only if there are two teams on the map!
-{
- entity e;
- e = find(world, classname, "nexball_team");
- if (e.team == t)
- e = find(e, classname, "nexball_team");
- return e.team;
-}
-
-void ResetBall();
-
-void LogNB(string mode, entity actor)
-{
- string s;
- if(!autocvar_sv_eventlog)
- return;
- s = strcat(":nexball:", mode);
- if(actor != world)
- s = strcat(s, ":", ftos(actor.playerid));
- GameLogEcho(s);
-}
-
-void ball_restart (void)
-{
- if(self.owner)
- DropBall(self, self.owner.origin, '0 0 0');
- ResetBall();
-}
-
-void nexball_setstatus (void)
-{
- entity oldself;
- self.items &~= IT_KEY1;
- if (self.ballcarried)
- {
- if (self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
- {
- bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n");
- oldself = self;
- self = self.ballcarried;
- DropBall(self, self.owner.origin, '0 0 0');
- ResetBall();
- self = oldself;
- } else
- self.items |= IT_KEY1;
- }
-}
-
-void relocate_nexball (void)
-{
- tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, TRUE, self);
- if (trace_startsolid)
- {
- vector o;
- o = self.origin;
- if(!move_out_of_solid(self))
- objerror("could not get out of solid at all!");
- print("^1NOTE: this map needs FIXING. ", self.classname, " at ", vtos(o - '0 0 1'));
- print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
- print(" ", ftos(self.origin_y - o_y));
- print(" ", ftos(self.origin_z - o_z), "'\n");
- self.origin = o;
- }
-}
-
-void basketball_touch();
-void football_touch();
-
-void DropOwner (void)
-{
- entity ownr;
- ownr = self.owner;
- DropBall(self, ownr.origin, ownr.velocity);
- makevectors(ownr.v_angle_y * '0 1 0');
- ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
- ownr.flags &~= FL_ONGROUND;
-}
-
-void GiveBall (entity plyr, entity ball)
-{
- entity ownr;
-
- if ((ownr = ball.owner))
- {
- ownr.effects &~= g_nexball_basketball_effects_default;
- ownr.ballcarried = world;
- if (ownr.metertime)
- {
- ownr.metertime = 0;
- ownr.weaponentity.state = WS_READY;
- }
- WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
- }
- else
- {
- WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
- }
-
- setattachment(ball, plyr, "");
- setorigin(ball, BALL_ATTACHORG);
-
- if (ball.team != plyr.team)
- ball.teamtime = time + g_nexball_basketball_delay_hold_forteam;
-
- ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
- ball.team = plyr.team;
- plyr.ballcarried = ball;
- ball.nb_dropperid = plyr.playerid;
-
- plyr.effects |= g_nexball_basketball_effects_default;
- ball.effects &~= g_nexball_basketball_effects_default;
-
- ball.velocity = '0 0 0';
- ball.movetype = MOVETYPE_NONE;
- ball.touch = func_null;
- ball.effects |= EF_NOSHADOW;
- ball.scale = 1; // scale down.
-
- WaypointSprite_AttachCarrier("nb-ball", plyr, RADARICON_FLAGCARRIER, BALL_SPRITECOLOR);
- WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- if (g_nexball_basketball_delay_hold)
- {
- ball.think = DropOwner;
- ball.nextthink = time + g_nexball_basketball_delay_hold;
- }
-}
-
-void DropBall (entity ball, vector org, vector vel)
-{
- ball.effects |= g_nexball_basketball_effects_default;
- ball.effects &~= EF_NOSHADOW;
- ball.owner.effects &~= g_nexball_basketball_effects_default;
-
- setattachment(ball, world, "");
- setorigin (ball, org);
- ball.movetype = MOVETYPE_BOUNCE;
- ball.flags &~= FL_ONGROUND;
- ball.scale = ball_scale;
- ball.velocity = vel;
- ball.nb_droptime = time;
- ball.touch = basketball_touch;
- ball.think = ResetBall;
- ball.nextthink = min(time + g_nexball_delay_idle, ball.teamtime);
-
- if (ball.owner.metertime)
- {
- ball.owner.metertime = 0;
- ball.owner.weaponentity.state = WS_READY;
- }
-
- WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
- WaypointSprite_Spawn("nb-ball", 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAGCARRIER, BALL_SPRITECOLOR); // no health bar please
- WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- ball.owner.ballcarried = world;
- ball.owner = world;
-}
-
-void InitBall (void)
-{
- if (gameover) return;
- self.flags &~= FL_ONGROUND;
- self.movetype = MOVETYPE_BOUNCE;
- if (self.classname == "nexball_basketball")
- self.touch = basketball_touch;
- else if (self.classname == "nexball_football")
- self.touch = football_touch;
- self.cnt = 0;
- self.think = ResetBall;
- self.nextthink = time + g_nexball_delay_idle + 3;
- self.teamtime = 0;
- self.pusher = world;
- self.team = FALSE;
- sound (self, CH_TRIGGER, self.noise1, VOL_BASE, ATTN_NORM);
- WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);
- LogNB("init", world);
-}
-
-void ResetBall (void)
-{
- if (self.cnt < 2) { // step 1
- if (time == self.teamtime)
- bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n");
- self.touch = func_null;
- self.movetype = MOVETYPE_NOCLIP;
- self.velocity = '0 0 0'; // just in case?
- if(!self.cnt)
- LogNB("resetidle", world);
- self.cnt = 2;
- self.nextthink = time;
- } else if (self.cnt < 4) { // step 2 and 3
-// dprint("Step ", ftos(self.cnt), ": Calculated velocity: ", vtos(self.spawnorigin - self.origin), ", time: ", ftos(time), "\n");
- self.velocity = (self.spawnorigin - self.origin) * (self.cnt - 1); // 1 or 0.5 second movement
- self.nextthink = time + 0.5;
- self.cnt += 1;
- } else { // step 4
-// dprint("Step 4: time: ", ftos(time), "\n");
- if (vlen(self.origin - self.spawnorigin) > 10) // should not happen anymore
- dprint("The ball moved too far away from its spawn origin.\nOffset: ",
- vtos(self.origin - self.spawnorigin), " Velocity: ", vtos(self.velocity), "\n");
- self.velocity = '0 0 0';
- setorigin(self, self.spawnorigin); // make sure it's positioned correctly anyway
- self.movetype = MOVETYPE_NONE;
- self.think = InitBall;
- self.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
- }
-}
-
-void football_touch (void)
-{
- if (other.solid == SOLID_BSP) {
- if (time > self.lastground + 0.1)
- {
- sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
- self.lastground = time;
- }
- if (vlen(self.velocity) && !self.cnt)
- self.nextthink = time + g_nexball_delay_idle;
- return;
- }
- if (other.classname != "player")
- return;
- if (other.health < 1)
- return;
- if (!self.cnt)
- self.nextthink = time + g_nexball_delay_idle;
-
- self.pusher = other;
- self.team = other.team;
-
- if (g_nexball_football_physics == -1) { // MrBougo try 1, before decompiling Rev's original
- if (vlen(other.velocity))
- self.velocity = other.velocity * 1.5 + '0 0 1' * g_nexball_football_boost_up;
- } else if (g_nexball_football_physics == 1) { // MrBougo's modded Rev style: partially independant of the height of the aiming point
- makevectors(other.v_angle);
- self.velocity = other.velocity + v_forward * g_nexball_football_boost_forward + '0 0 1' * g_nexball_football_boost_up;
- } else if (g_nexball_football_physics == 2) { // 2nd mod try: totally independant. Really playable!
- makevectors(other.v_angle_y * '0 1 0');
- self.velocity = other.velocity + v_forward * g_nexball_football_boost_forward + v_up * g_nexball_football_boost_up;
- } else { // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
- makevectors(other.v_angle);
- self.velocity = other.velocity + v_forward * g_nexball_football_boost_forward + v_up * g_nexball_football_boost_up;
- }
- self.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
-}
-
-void basketball_touch (void)
-{
- if (other.ballcarried)
- {
- football_touch();
- return;
- }
- if (!self.cnt && other.classname == "player" && (other.playerid != self.nb_dropperid || time > self.nb_droptime + autocvar_g_nexball_delay_collect)) {
- if (other.health <= 0)
- return;
- LogNB("caught", other);
- GiveBall(other, self);
- } else if (other.solid == SOLID_BSP) {
- sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
- if (vlen(self.velocity) && !self.cnt)
- self.nextthink = min(time + g_nexball_delay_idle, self.teamtime);
- }
-}
-
-void GoalTouch (void)
-{
- entity ball;
- float isclient, pscore, otherteam;
- string pname;
-
- if (gameover) return;
- if ((self.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
- ball = other.ballcarried;
- else
- ball = other;
- if (ball.classname != "nexball_basketball")
- if (ball.classname != "nexball_football")
- return;
- if ((!ball.pusher && self.team != GOAL_OUT) || ball.cnt)
- return;
- EXACTTRIGGER_TOUCH;
-
-
- if(nb_teams == 2)
- otherteam = OtherTeam(ball.team);
-
- if((isclient = ball.pusher.flags & FL_CLIENT))
- pname = ball.pusher.netname;
- else
- pname = "Someone (?)";
-
- if (ball.team == self.team) //owngoal (regular goals)
- {
- LogNB("owngoal", ball.pusher);
- bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
- pscore = -1;
- } else if (self.team == GOAL_FAULT) {
- LogNB("fault", ball.pusher);
- if (nb_teams == 2)
- bprint(ColoredTeamName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
- else
- bprint(ColoredTeamName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
- pscore = -1;
- } else if (self.team == GOAL_OUT) {
- LogNB("out", ball.pusher);
- if ((self.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
- bprint(pname, "^7 went out of bounds.\n");
- else
- bprint("The ball was returned.\n");
- pscore = 0;
- } else { //score
- LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
- bprint("Goaaaaal! ", pname, "^7 scored a point for the ", ColoredTeamName(ball.team), ".\n");
- pscore = 1;
- }
-
- sound (ball, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NONE);
-
- if(ball.team && pscore)
- {
- if (nb_teams == 2 && pscore < 0)
- TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
- else
- TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
- }
- if (isclient)
- {
- if (pscore > 0)
- PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
- else if (pscore < 0)
- PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
- }
-
- if (ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
- DropBall(ball, ball.owner.origin, ball.owner.velocity);
-
- WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-
- ball.cnt = 1;
- ball.think = ResetBall;
- if (ball.classname == "nexball_basketball")
- ball.touch = football_touch; // better than func_null: football control until the ball gets reset
- ball.nextthink = time + autocvar_g_nexball_delay_goal * (self.team != GOAL_OUT);
-}
-
-//=======================//
-// team ents //
-//=======================//
-void spawnfunc_nexball_team (void)
-{
- if(!g_nexball) { remove(self); return; }
- self.team = self.cnt + 1;
-}
-
-void nb_spawnteam (string teamname, float teamcolor)
-{
- dprint("^2spawned team ", teamname, "\n");
- entity e;
- e = spawn();
- e.classname = "nexball_team";
- e.netname = teamname;
- e.cnt = teamcolor;
- e.team = e.cnt + 1;
- nb_teams += 1;
-}
-
-void nb_spawnteams (void)
-{
- float t_r, t_b, t_y, t_p;
- entity e;
- for(e = world; (e = find(e, classname, "nexball_goal")); )
- {
- switch(e.team)
- {
- case NUM_TEAM_1: if(!t_r) { nb_spawnteam ("Red", e.team-1) ; t_r = 1; } break;
- case NUM_TEAM_2: if(!t_b) { nb_spawnteam ("Blue", e.team-1) ; t_b = 1; } break;
- case NUM_TEAM_3: if(!t_y) { nb_spawnteam ("Yellow", e.team-1); t_y = 1; } break;
- case NUM_TEAM_4: if(!t_p) { nb_spawnteam ("Pink", e.team-1) ; t_p = 1; } break;
- }
- }
-}
-
-void nb_delayedinit (void)
-{
- if (find(world, classname, "nexball_team") == world)
- nb_spawnteams();
- ScoreRules_nexball(nb_teams);
-}
-
-
-//=======================//
-// spawnfuncs //
-//=======================//
-
-void SpawnBall (void)
-{
- if(!g_nexball) { remove(self); return; }
-
-// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
-
- if (!self.model) {
- self.model = "models/nexball/ball.md3";
- self.scale = 1.3;
- }
-
- precache_model (self.model);
- setmodel (self, self.model);
- setsize (self, BALL_MINS, BALL_MAXS);
- ball_scale = self.scale;
-
- relocate_nexball();
- self.spawnorigin = self.origin;
-
- self.effects = self.effects | EF_LOWPRECISION;
-
- if (cvar(strcat("g_", self.classname, "_trail"))) //nexball_basketball :p
- {
- self.glow_color = autocvar_g_nexball_trail_color;
- self.glow_trail = TRUE;
- }
-
- self.movetype = MOVETYPE_FLY;
-
- if (!autocvar_g_nexball_sound_bounce)
- self.noise = "";
- else if (!self.noise)
- self.noise = "sound/nexball/bounce.wav";
- //bounce sound placeholder (FIXME)
- if (!self.noise1)
- self.noise1 = "sound/nexball/drop.wav";
- //ball drop sound placeholder (FIXME)
- if (!self.noise2)
- self.noise2 = "sound/nexball/steal.wav";
- //stealing sound placeholder (FIXME)
- if (self.noise) precache_sound (self.noise);
- precache_sound (self.noise1);
- precache_sound (self.noise2);
-
- WaypointSprite_AttachCarrier("nb-ball", self, RADARICON_FLAGCARRIER, BALL_SPRITECOLOR); // the ball's team is not set yet, no rule update needed
-
- self.reset = ball_restart;
- self.think = InitBall;
- self.nextthink = game_starttime + autocvar_g_nexball_delay_start;
-}
-
-void spawnfunc_nexball_basketball (void)
-{
- self.classname = "nexball_basketball";
- if not(balls & BALL_BASKET)
- {
- CVTOV(g_nexball_basketball_effects_default);
- CVTOV(g_nexball_basketball_delay_hold);
- CVTOV(g_nexball_basketball_delay_hold_forteam);
- CVTOV(g_nexball_basketball_teamsteal);
- g_nexball_basketball_effects_default = g_nexball_basketball_effects_default & BALL_EFFECTMASK;
- }
- if (!self.effects)
- self.effects = g_nexball_basketball_effects_default;
- self.solid = SOLID_TRIGGER;
- balls |= BALL_BASKET;
- self.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
- self.bouncestop = autocvar_g_nexball_basketball_bouncestop;
- SpawnBall();
-}
-
-void spawnfunc_nexball_football (void)
-{
- self.classname = "nexball_football";
- self.solid = SOLID_TRIGGER;
- balls |= BALL_FOOT;
- self.bouncefactor = autocvar_g_nexball_football_bouncefactor;
- self.bouncestop = autocvar_g_nexball_football_bouncestop;
- SpawnBall();
-}
-
-void SpawnGoal (void)
-{
- if(!g_nexball) { remove(self); return; }
- EXACTTRIGGER_INIT;
- self.classname = "nexball_goal";
- if (!self.noise)
- self.noise = "ctf/respawn.wav";
- precache_sound(self.noise);
- self.touch = GoalTouch;
-}
-
-void spawnfunc_nexball_redgoal (void)
-{
- self.team = NUM_TEAM_1;
- SpawnGoal();
-}
-void spawnfunc_nexball_bluegoal (void)
-{
- self.team = NUM_TEAM_2;
- SpawnGoal();
-}
-void spawnfunc_nexball_yellowgoal (void)
-{
- self.team = NUM_TEAM_3;
- SpawnGoal();
-}
-void spawnfunc_nexball_pinkgoal (void)
-{
- self.team = NUM_TEAM_4;
- SpawnGoal();
-}
-
-void spawnfunc_nexball_fault (void)
-{
- self.team = GOAL_FAULT;
- if (!self.noise)
- self.noise = "misc/typehit.wav";
- SpawnGoal();
-}
-
-void spawnfunc_nexball_out (void)
-{
- self.team = GOAL_OUT;
- if (!self.noise)
- self.noise = "misc/typehit.wav";
- SpawnGoal();
-}
-
-//
-//Spawnfuncs preserved for compatibility
-//
-
-void spawnfunc_ball (void) { spawnfunc_nexball_football(); }
-void spawnfunc_ball_football (void) { spawnfunc_nexball_football(); }
-void spawnfunc_ball_basketball (void) { spawnfunc_nexball_basketball(); }
-// The "red goal" is defended by blue team. A ball in there counts as a point for red.
-void spawnfunc_ball_redgoal (void) { spawnfunc_nexball_bluegoal(); } // I blame Revenant
-void spawnfunc_ball_bluegoal (void) { spawnfunc_nexball_redgoal(); } // but he didn't mean to cause trouble :p
-void spawnfunc_ball_fault (void) { spawnfunc_nexball_fault(); }
-void spawnfunc_ball_bound (void) { spawnfunc_nexball_out(); }
-
-//=======================//
-// Weapon code //
-//=======================//
-
-void W_Nexball_Touch (void)
-{
- entity ball, attacker;
- attacker = self.owner;
-
- PROJECTILE_TOUCH;
- if(attacker.team != other.team || g_nexball_basketball_teamsteal)
- if((ball = other.ballcarried) && (attacker.classname == "player"))
- {
- other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
- other.flags &~= FL_ONGROUND;
- if(!attacker.ballcarried)
- {
- LogNB("stole", attacker);
- sound (other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTN_NORM);
-
- if(attacker.team == other.team && time > attacker.teamkill_complain)
- {
- attacker.teamkill_complain = time + 5;
- attacker.teamkill_soundtime = time + 0.4;
- attacker.teamkill_soundsource = other;
- }
-
- GiveBall(attacker, other.ballcarried);
- }
- }
- remove(self);
-}
-
-void W_Nexball_Attack (float t)
-{
- entity ball;
- float mul, mi, ma;
- if (!(ball = self.ballcarried))
- return;
-
- W_SetupShot (self, FALSE, 4, "nexball/shoot1.wav", CH_WEAPON_A, 0);
- tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, world);
- if(trace_startsolid)
- {
- if(self.metertime)
- self.metertime = 0; // Shot failed, hide the power meter
- return;
- }
-
- //Calculate multiplier
- if (t < 0)
- mul = 1;
- else
- {
- mi = autocvar_g_nexball_basketball_meter_minpower;
- ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
- //One triangle wave period with 1 as max
- mul = 2 * mod(t, g_nexball_meter_period) / g_nexball_meter_period;
- if (mul > 1)
- mul = 2 - mul;
- mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
- }
- DropBall (ball, w_shotorg, W_CalculateProjectileVelocity(self.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, FALSE));
- //TODO: use the speed_up cvar too ??
-}
-
-void W_Nexball_Attack2 (void)
-{
- entity missile;
- if (!(balls & BALL_BASKET))
- return;
- W_SetupShot (self, FALSE, 2, "nexball/shoot2.wav", CH_WEAPON_A, 0);
-// pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
- missile = spawn ();
-
- missile.owner = self;
- missile.classname = "ballstealer";
-
- missile.movetype = MOVETYPE_FLY;
- PROJECTILE_MAKETRIGGER(missile);
-
- setmodel (missile, "models/elaser.mdl"); // precision set below
- setsize (missile, '0 0 0', '0 0 0');
- setorigin (missile, w_shotorg);
-
- W_SetupProjectileVelocity(missile, autocvar_g_balance_nexball_secondary_speed, 0);
- missile.angles = vectoangles (missile.velocity);
- missile.touch = W_Nexball_Touch;
- missile.think = SUB_Remove;
- missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
-
- missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
- missile.flags = FL_PROJECTILE;
-}
-
-float w_nexball_weapon(float req)
-{
- if (req == WR_THINK)
- {
- if (self.BUTTON_ATCK)
- if (weapon_prepareattack(0, autocvar_g_balance_nexball_primary_refire))
- if (autocvar_g_nexball_basketball_meter)
- {
- if (self.ballcarried && !self.metertime)
- self.metertime = time;
- else
- weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- else
- {
- W_Nexball_Attack(-1);
- weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- if (self.BUTTON_ATCK2)
- if (weapon_prepareattack(1, autocvar_g_balance_nexball_secondary_refire))
- {
- W_Nexball_Attack2();
- weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
- }
-
- if (!self.BUTTON_ATCK && self.metertime && self.ballcarried)
- {
- W_Nexball_Attack(time - self.metertime);
- // DropBall or stealing will set metertime back to 0
- weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- }
- else if (req == WR_PRECACHE)
- {
- precache_model ("models/weapons/g_porto.md3");
- precache_model ("models/weapons/v_porto.md3");
- precache_model ("models/weapons/h_porto.iqm");
- precache_model ("models/elaser.mdl");
- precache_sound ("nexball/shoot1.wav");
- precache_sound ("nexball/shoot2.wav");
- precache_sound ("misc/typehit.wav");
- }
- else if (req == WR_SETUP)
- weapon_setup(WEP_PORTO);
- else if (req == WR_SUICIDEMESSAGE)
- {
- w_deathtypestring = "is a weirdo";
- }
- else if (req == WR_KILLMESSAGE)
- {
- w_deathtypestring = "got killed by #'s black magic";
- }
- // No need to check WR_CHECKAMMO* or WR_AIM, it should always return TRUE
- return TRUE;
-}
+++ /dev/null
-float rune_numspawns;
-
-float RUNE_FIRST = 1;
-float RUNE_STRENGTH = 1;
-float RUNE_DEFENSE = 2;
-float RUNE_REGEN = 4;
-float RUNE_SPEED = 8;
-float RUNE_VAMPIRE = 16;
-float RUNE_LAST = 16;
-
-float CURSE_FIRST = 8192;
-float CURSE_WEAK = 8192;
-float CURSE_VULNER = 16384;
-float CURSE_VENOM = 32768;
-float CURSE_SLOW = 65536;
-float CURSE_EMPATHY = 131072;
-float CURSE_LAST = 131072;
-
-float RUNE_COUNT = 5;
-
-/* rune ideas:
-
- Doom/Death
- Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health)
- Curse: When you are damaged, you have a chance of being instant-killed
-
- Vengence/Slothful
- Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100)
- Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage)
-
-*/
-
-/*QUAKED spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24)
-spawn point for runes in runematch
-*/
-
-void spawnfunc_runematch_spawn_point()
-{
- if(!g_runematch || !autocvar_g_runematch_fixedspawns)
- {
- remove(self);
- return;
- }
-
- setsize(self, '0 0 -35', '0 0 0');
- droptofloor();
- ++rune_numspawns;
-}
-
-// only used if using rune spawns at all
-entity rune_find_spawnpoint()
-{
- entity e;
-
- if(rune_numspawns < RUNE_COUNT)
- return world;
-
- RandomSelection_Init();
-
- for(e = world; (e = find(e, classname, "runematch_spawn_point")); )
- if(e.owner == world)
- RandomSelection_Add(e, 0, string_null, e.cnt, 0);
-
- return RandomSelection_chosen_ent;
-}
-
-float rune_spawn_somewhere(entity e)
-{
- entity spot;
- spot = rune_find_spawnpoint();
- if(spot)
- {
- spot.owner = e;
- setorigin(e, spot.origin);
-
- e.owner = spot;
- spot.owner = e;
-
- return TRUE;
- }
- else
- {
- if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
- {
- // great
- makevectors(self.angles),
- self.velocity = v_forward * 250;
- self.angles = '0 0 0';
- return TRUE;
- }
- else
- {
- // sorry, can't spawn, better luck next frame
- return FALSE;
- }
- }
-}
-
-void rune_unmark_spot(entity e)
-{
- if(e.owner.classname == "runematch_spawn_point")
- {
- e.owner.owner = world;
- e.owner = world;
- }
-}
-
-string RuneName(float r)
-{
- if(r == RUNE_STRENGTH)
- return "^1Strength^7";
- if(r == RUNE_DEFENSE)
- return "^4Defense^7";
- if(r == RUNE_REGEN)
- return "^2Vitality^7";
- if(r == RUNE_SPEED)
- return "^3Speed^7";
- if(r == RUNE_VAMPIRE)
- return "^6Vampire^7";
-
- if(r == CURSE_WEAK)
- return "^1Weakness^7";
- if(r == CURSE_VULNER)
- return "^4Vulnerability^7";
- if(r == CURSE_VENOM)
- return "^2Venom^7";
- if(r == CURSE_SLOW)
- return "^3Slow^7";
- if(r == CURSE_EMPATHY)
- return "^6Empathy^7";
- return strcat("^8[unnamed", ftos(r), "]^7");
-}
-
-vector RuneColormod(float r)
-{
- vector _color = '255 0 255';
-
- if(r == RUNE_STRENGTH)
- _color = '255 0 0';
- if(r == RUNE_DEFENSE)
- _color = '0 0 255';//'0 102 255';//
- if(r == RUNE_REGEN)
- _color = '0 204 0';//'0 255 0';
- if(r == RUNE_SPEED)
- _color = 0.35*'185 185 0';//255 230 0';//'255 255 0';
- if(r == RUNE_VAMPIRE)
- _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';//
-
- if(r == CURSE_WEAK)
- _color = '255 0 0';
- if(r == CURSE_VULNER)
- _color = '0 0 255';//'0 102 255';//
- if(r == CURSE_VENOM)
- _color = '0 204 0';//'0 255 0';
- if(r == CURSE_SLOW)
- _color = 0.5*'185 185 0';//'255 255 0';
- if(r == CURSE_EMPATHY)
- _color = '179 0 204';//'128 0 255';
-
- return _color * (1 / 255) * autocvar_g_runematch_rune_color_strength;
-}
-
-void rune_respawn();
-
-void RuneCarriedThink()
-{
- float rcount, rnum;
- vector ang = '0 0 0';
- entity rune;
-
- if(!IS_PLAYER(self.owner) || time < game_starttime)
- {
- rune_respawn();
- return;
- }
-
- self.nextthink = time + 0.1;
-
- // count runes my owner holds
- rcount = 0;
- rune = find(world, classname, "rune");
- rnum = -1;
- while(rune)
- {
- if(rune.owner == self.owner)
- rcount = rcount + 1;
- if(rune == self)
- rnum = rcount;
- rune = find(rune, classname, "rune");
- }
-
- ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180;
-
- makevectors(ang);
-
- setorigin(self, v_forward*32);
-}
-
-void rune_touch()
-{
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- {
- self.think = rune_respawn;
- self.nextthink = time;
- return;
- }
-
- if(!IS_PLAYER(other) || other.health < 1)
- return;
- if(self.wait > time)
- return; // "notouch" time isn't finished
-
- // detach from the spawn point you're on
- rune_unmark_spot(self);
-
- self.owner = other;
- self.enemy.owner = other;
- setattachment(self, other, "");
-
- other.runes = other.runes | self.runes | self.enemy.runes;
-
- //self.think = func_null;
- //self.nextthink = 0;
- self.think = RuneCarriedThink;
- self.nextthink = time;
- self.touch = func_null;
-
- self.solid = SOLID_NOT;
- setorigin(self, self.origin);
-
- //sprint(other, strcat("^3You have picked up ",
- // RuneName(self.runes & (RUNE_LAST*2-1)), " and "));
- //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
-
- bprint("^3", other.netname, "^7 has picked up ",
- RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and ");
- bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
-}
-
-void rune_respawn()
-{
- rune_unmark_spot(self);
- if(rune_spawn_somewhere(self))
- {
- self.solid = SOLID_TRIGGER;
- self.touch = rune_touch;
- self.think = rune_respawn;
- self.nextthink = time + autocvar_g_runematch_shuffletime;//30 + random()*5; // fixme: cvar
- }
- else
- {
- // try again later
- self.think = rune_respawn;
- self.nextthink = time;
- }
-}
-
-entity FindRune(entity own, string clname, float r)
-{
- entity rune;
- float _count, c;
-
- c = _count = 0;
- rune = world;
-
- do
- {
- rune = find(rune, classname, clname);
- if(!rune)
- rune = find(rune, classname, clname);
- if(!rune)
- break;
- if(rune.owner == own)
- {
- _count = _count + 1;
- if(_count >= r)
- return rune;
- if(r <= 1)
- return rune;
- }
- c = c + 1;
- }while(c < 30);
- return world;
-}
-
-
-void DropRune(entity pl, entity e)
-{
- //entity pl;
-
- //pl = e.owner;
- // detach from player
- setattachment(e, world, "");
- e.owner = world;
- e.enemy.owner = world;
- // don't instantly touch player again
- e.wait = time + 1; // "notouch" time
- e.movetype = MOVETYPE_TOSS;
- e.solid = SOLID_TRIGGER;
- // reposition itself if not picked up soon
- e.think = rune_respawn;
- e.nextthink = time + autocvar_g_runematch_respawntime;//15 + random()*5; // fixme: cvar
- e.touch = rune_touch;
-
- pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes));
-
- // toss from player
- setorigin(e, pl.origin + '0 0 10');
- e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
-
-
- bprint("^3", pl.netname, "^7 has lost ",
- RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and ");
- bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
-}
-
-float RuneMatchesCurse(float r, float c)
-{
- float cr;
- if(r & RUNE_STRENGTH)
- cr = CURSE_WEAK;
- else if(r & RUNE_DEFENSE)
- cr = CURSE_VULNER;
- else if(r & RUNE_REGEN)
- cr = CURSE_VENOM;
- else if(r & RUNE_SPEED)
- cr = CURSE_SLOW;
- else if(r & RUNE_VAMPIRE)
- cr = CURSE_EMPATHY;
- else return FALSE; // fixme: error?
-
- if(c & cr)
- return TRUE;
- return FALSE;
-}
-
-// player died, drop runes
-// each rune should pair up with a random curse and then be tossed from the player
-void DropAllRunes(entity pl)
-{
- entity rune, curse;
- float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries;
-
- entity curse1, rune1, curse2, rune2;
-
- rcount = ccount = r = c = 0;
- rune = find(world, classname, "rune");
- while(rune)
- {
- if(rune.owner == pl)
- rcount = rcount + 1;
- rune = find(rune, classname, "rune");
- }
- curse = find(world, classname, "curse");
- while(curse)
- {
- if(curse.owner == pl)
- ccount = ccount + 1;
- curse = find(curse, classname, "curse");
- }
-
- numtodrop = autocvar_g_runematch_drop_runes_max;
- prevent_same = !autocvar_g_runematch_allow_same;
-
- do
- {
- rune = find(rune, classname, "rune");
- if(!rune)
- break;
- if(rune.owner != pl)
- continue;
-
-
- // find a random curse
- tries = 15;
- if(ccount > 1 && prevent_same)
- {
- // avoid pairing runes and curses that match each other
- do{
- rand = floor(random()*ccount) + 1;
- curse = FindRune(pl, "curse", rand);
- tries = tries - 1;
- }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0);
- if(tries <= 0)
- {
- bprint("warning: couldn't prevent same rune\n");
- }
- }
- else
- {
- rand = floor(random()*ccount) + 1;
- curse = FindRune(pl, "curse", rand);
- }
-
- if(!curse)
- error("Couldn't fine curse to bind rune to\n");
-
- // pair rune and curse
-
- rune1 = rune;
- curse1 = curse;
- rune2 = curse1.enemy;
- curse2 = rune1.enemy;
-
- if(rune1 != rune2) // not already attached to each other
- {
- rune1.enemy = curse1;
- curse1.enemy = rune1;
- setattachment(curse1, rune1, "");
- rune2.enemy = curse2;
- curse2.enemy = rune2;
- setattachment(curse2, rune2, "");
- //DropRune(pl, rune2);
- //ccount = ccount - 1;
- //rcount = rcount - 1;
- }
- DropRune(pl, rune1);
-
- if(numtodrop <=0)
- {
- rune1.think = rune_respawn;
- rune1.nextthink = time;
- }
-
- numtodrop = numtodrop - 1;
-
- ccount = ccount - 1;
- rcount = rcount - 1;
-
- }while(rune);
-}
-
-void rune_reset()
-{
- if(self.owner)
- if(self.owner.classname != "runematch_spawn_point")
- DropAllRunes(self.owner);
- rune_respawn();
-}
-
-void spawn_runes()
-{
- float rn, cs, runes_used, curses_used, prevent_same, numrunes;
- entity e;
-
- if(self)
- remove(self);
-
- // fixme: instead of placing them all now, why not
- // simply create them all and let them call rune_respawn() as their think?
-
- runes_used = 0;
- curses_used = 0;
-
- prevent_same = !autocvar_g_runematch_allow_same;
- numrunes = RUNE_COUNT;
-
- while(numrunes > 0)
- {
- RandomSelection_Init();
- for(rn = RUNE_FIRST; rn <= RUNE_LAST; rn *= 2)
- if not(runes_used & rn)
- RandomSelection_Add(world, rn, string_null, 1, 1);
- rn = RandomSelection_chosen_float;
-
- RandomSelection_Init();
- for(cs = CURSE_FIRST; cs <= CURSE_LAST; cs *= 2)
- if not(curses_used & cs)
- if not(prevent_same && cs == RuneMatchesCurse(rn, cs))
- RandomSelection_Add(world, cs, string_null, 1, 1);
- cs = RandomSelection_chosen_float;
-
- if(!rn || !cs)
- error("No rune/curse left");
-
- runes_used |= rn;
- curses_used |= cs;
-
- e = spawn();
- e.runes = rn;
- e.classname = "rune";
- e.touch = rune_touch;
- e.think = rune_respawn;
- e.nextthink = time;
- e.movetype = MOVETYPE_TOSS;
- e.solid = SOLID_TRIGGER;
- e.flags = FL_ITEM;
- e.reset = rune_reset;
- setmodel(e, "models/runematch/rune.mdl"); // precision set below
- setsize(e, '0 0 -35', '0 0 0');
-
- e.enemy = spawn();
- e.enemy.enemy = e;
- e.enemy.classname = "curse";
- e.enemy.runes = cs;
- //e.enemy.avelocity = '300 500 200';
- setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below
- setorigin(e, '0 0 0');
- setattachment(e.enemy, e, "");
-
- e.colormod = RuneColormod(rn);
- e.enemy.colormod = RuneColormod(cs);
-
- e.alpha = e.enemy.alpha = autocvar_g_runematch_rune_alpha;//0.78;
- e.effects = e.enemy.effects = autocvar_g_runematch_rune_effects | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT;
-
- //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size");
- //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color");
-
- //rn = RUNE_FIRST;
- //cs = CURSE_FIRST;
-
- numrunes = numrunes - 1;
- }
-}
-
-void runematch_init()
-{
- if(!g_runematch)
- return;
-
- entity e;
- e = spawn();
- e.think = spawn_runes;
- e.nextthink = time + 0.1;
-}
-
-
-float runematch_point_time;
-
-// give points to players who are holding runes
-void RuneMatchGivePoints()
-{
- entity rune;
-
- if(!g_runematch || !autocvar_g_runematch_pointamt)
- return;
-
- if(gameover)
- return;
-
- if(runematch_point_time > time)
- return;
-
- runematch_point_time = time + autocvar_g_runematch_pointrate;
-
- rune = world;
- do
- {
- rune = find(rune, classname, "rune");
- if(!rune)
- return;
-
- if(IS_PLAYER(rune.owner))
- {
- UpdateFrags(rune.owner, autocvar_g_runematch_pointamt);
- }
- }while(rune);
-}
-
-float RunematchHandleFrags(entity attacker, entity targ, float f)
-{
- entity head;
- float arunes, trunes, newfrags;
-
- if(f <= 0)
- return f;
- if(attacker == targ)
- return f;
-
- arunes = trunes = 0;
-
- head = find(world, classname, "rune");
- while(head)
- {
- if(head.owner == attacker)
- {
- arunes = arunes + 1;
- }
- else if(head.owner == targ)
- {
- trunes = trunes + 1;
- }
-
- head = find(head, classname, "rune");
- }
-
- if(!arunes && !trunes)
- return f - 1 + autocvar_g_runematch_frags_norune; // don't give points to players when no runes are involved.
-
- newfrags = 0;
- if(arunes)
- { // got a kill while holding runes
- newfrags = newfrags + autocvar_g_runematch_frags_killedby_runeholder;//5;
- }
- if(trunes)
- { // killed an enemy holding runes
- newfrags = newfrags + autocvar_g_runematch_frags_killed_runeholder;//5;
- }
- if(newfrags)
- f = f - 1 + newfrags;
-
- return f;
-}
+++ /dev/null
-#ifdef SVQC
-// Auto cvars
-float autocvar_g_vehicle_bumblebee_speed_forward;
-float autocvar_g_vehicle_bumblebee_speed_strafe;
-float autocvar_g_vehicle_bumblebee_speed_up;
-float autocvar_g_vehicle_bumblebee_speed_down;
-float autocvar_g_vehicle_bumblebee_turnspeed;
-float autocvar_g_vehicle_bumblebee_pitchspeed;
-float autocvar_g_vehicle_bumblebee_pitchlimit;
-float autocvar_g_vehicle_bumblebee_friction;
-
-float autocvar_g_vehicle_bumblebee_energy;
-float autocvar_g_vehicle_bumblebee_energy_regen;
-float autocvar_g_vehicle_bumblebee_energy_regen_pause;
-
-float autocvar_g_vehicle_bumblebee_health;
-float autocvar_g_vehicle_bumblebee_health_regen;
-float autocvar_g_vehicle_bumblebee_health_regen_pause;
-
-float autocvar_g_vehicle_bumblebee_shield;
-float autocvar_g_vehicle_bumblebee_shield_regen;
-float autocvar_g_vehicle_bumblebee_shield_regen_pause;
-
-float autocvar_g_vehicle_bumblebee_cannon_cost;
-float autocvar_g_vehicle_bumblebee_cannon_damage;
-float autocvar_g_vehicle_bumblebee_cannon_radius;
-float autocvar_g_vehicle_bumblebee_cannon_refire;
-float autocvar_g_vehicle_bumblebee_cannon_speed;
-float autocvar_g_vehicle_bumblebee_cannon_spread;
-float autocvar_g_vehicle_bumblebee_cannon_force;
-
-float autocvar_g_vehicle_bumblebee_cannon_turnspeed;
-float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down;
-float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up;
-float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
-float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
-
-float autocvar_g_vehicle_bumblebee_respawntime;
-
-float autocvar_g_vehicle_bumblebee_blowup_radius;
-float autocvar_g_vehicle_bumblebee_blowup_coredamage;
-float autocvar_g_vehicle_bumblebee_blowup_edgedamage;
-float autocvar_g_vehicle_bumblebee_blowup_forceintensity;
-
-#define BUMB_MIN '-120 -120 -40'
-#define BUMB_MAX '120 120 40'
-
-.entity gunner1;
-//.entity gunner2;
-.vector lastaim;
-float bumb_gunner_frame()
-{
- entity vehic, gun, gunner;
- float ftmp, ftmp2;
- vector vtmp;
-
- vehic = self.vehicle;
- gun = self.vehicle.gun1;
- gunner = self;
-
- self = vehic;
- vehic.solid = SOLID_NOT;
- crosshair_trace(gunner);
-
- //vtmp = gettaginfo(vehic, gettagindexvehic, "tag_hardpoint01"));
- vtmp = gettaginfo(gun, gettagindex(gun, "muzzle"));
- vtmp = vectoangles(normalize(trace_endpos - vtmp)); // Find the direction & angle
- vtmp = shortangle_vxy(vtmp - (vehic.angles + gun.angles), vehic.angles + gun.angles); // Find aim offset
-
- // Bind to aimspeed
- ftmp2 = autocvar_g_vehicle_bumblebee_cannon_turnspeed * frametime; ftmp = -ftmp2;
- vtmp_x = bound(ftmp, vtmp_x, ftmp2);
- vtmp_y = bound(ftmp, vtmp_y, ftmp2);
- // Bind to limts
- gun.angles_x = bound(-autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down, vtmp_x + gun.angles_x, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up);
- gun.angles_y = bound(-autocvar_g_vehicle_bumblebee_cannon_turnlimit_in, vtmp_y + gun.angles_y, autocvar_g_vehicle_bumblebee_cannon_turnlimit_out);
-
- if(gunner.BUTTON_ATCK && gun.cnt <= time)
- {
- vtmp = gettaginfo(gun, gettagindex(gun, "muzzle"));
- v_forward = normalize(v_forward);
- vtmp += v_forward * 50;
-
- fireBullet (vtmp, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_damage,
- autocvar_g_vehicle_spiderbot_minigun_spread, DEATH_SBMINIGUN, 0);
-
- gun.cnt = time + 0.1;
- }
-
- setorigin(gunner, vehic.origin);
- gunner.velocity = vehic.velocity;
-
- vehic.solid = SOLID_BBOX;
- gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0;
- self = gunner;
- return 1;
-}
-
-void bumb_gunner_enter()
-{
- if(self.gunner1 != world)
- return;
-
- self.gunner1 = other;
- self.gunner1.vehicle = self;
-
- msg_entity = other;
- WriteByte (MSG_ONE, SVC_SETVIEWPORT);
- WriteEntity(MSG_ONE, self.gun1);
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
- if(self.tur_head)
- {
- WriteAngle(MSG_ONE, self.gun1.angles_x + self.angles_x); // tilt
- WriteAngle(MSG_ONE, self.gun1.angles_y + self.angles_y); // yaw
- WriteAngle(MSG_ONE, 0); // roll
- }
- other.PlayerPhysplug = bumb_gunner_frame;
-}
-
-float bumb_pilot_frame()
-{
- entity pilot, gunner, vehic;
- vector newvel;
-
- pilot = self;
- vehic = self.vehicle;
- self = vehic;
-
- if(pilot.BUTTON_USE && vehic.deadflag == DEAD_NO)
- {
- self = vehic;
- vehicles_exit(VHEF_NORMAL);
- self = pilot;
- return 0;
- }
-
- if(vehic.deadflag != DEAD_NO)
- {
- self = pilot;
- pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0;
- return 1;
- }
-
- crosshair_trace(pilot);
-
- vector vang;
- float ftmp;
-
- vang = vehic.angles;
- newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32'));
- vang_x *= -1;
- newvel_x *= -1;
- if(newvel_x > 180) newvel_x -= 360;
- if(newvel_x < -180) newvel_x += 360;
- if(newvel_y > 180) newvel_y -= 360;
- if(newvel_y < -180) newvel_y += 360;
-
- ftmp = shortangle_f(pilot.v_angle_y - vang_y, vang_y);
- if(ftmp > 180) ftmp -= 360; if(ftmp < -180) ftmp += 360;
- vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed);
-
- // Pitch
- ftmp = 0;
- if(pilot.movement_x > 0 && vang_x < autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = 5;
- else if(pilot.movement_x < 0 && vang_x > -autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = -20;
-
- newvel_x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x , autocvar_g_vehicle_bumblebee_pitchlimit);
- ftmp = vang_x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit);
- vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity_x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed);
-
- vehic.angles_x = anglemods(vehic.angles_x);
- vehic.angles_y = anglemods(vehic.angles_y);
- vehic.angles_z = anglemods(vehic.angles_z);
-
- makevectors('0 1 0' * vehic.angles_y);
- newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction;
-
- if(pilot.movement_x != 0)
- {
- if(pilot.movement_x > 0)
- newvel += v_forward * autocvar_g_vehicle_bumblebee_speed_forward;
- else if(pilot.movement_x < 0)
- newvel -= v_forward * autocvar_g_vehicle_bumblebee_speed_forward;
- }
-
- if(pilot.movement_y != 0)
- {
- if(pilot.movement_y < 0)
- newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
- else if(pilot.movement_y > 0)
- newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
- ftmp = newvel * v_right;
- ftmp *= frametime * 0.1;
- vehic.angles_z = bound(-15, vehic.angles_z + ftmp, 15);
- }
- else
- {
- vehic.angles_z *= 0.95;
- if(vehic.angles_z >= -1 && vehic.angles_z <= -1)
- vehic.angles_z = 0;
- }
-
- if(pilot.BUTTON_CROUCH)
- newvel -= v_up * autocvar_g_vehicle_bumblebee_speed_down;
- else if (pilot.BUTTON_JUMP)
- newvel += v_up * autocvar_g_vehicle_bumblebee_speed_up;
-
- vehic.velocity += newvel * frametime;
- pilot.velocity = pilot.movement = vehic.velocity;
- setorigin(pilot,vehic.origin + '0 0 32');
-
-
- if(vehic.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime);
-
- if(vehic.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime);
-
- if(vehic.vehicle_flags & VHF_ENERGYREGEN)
- vehicles_regen(cnt, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime);
-
- VEHICLE_UPDATE_PLAYER(health, bumblebee);
- VEHICLE_UPDATE_PLAYER(energy, bumblebee);
- if(vehic.vehicle_flags & VHF_HASSHIELD)
- VEHICLE_UPDATE_PLAYER(shield, bumblebee);
-
- pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0;
- self = pilot;
-
- return 1;
-}
-
-void bumb_think()
-{
- self.velocity = self.velocity * 0.99;
- self.nextthink = time + 0.1;
-}
-
-void bumb_enter()
-{
- self.touch = bumb_gunner_enter;
-}
-
-void bumb_exit(float eject)
-{
- self.owner = world;
- self.touch = vehicles_touch;
-}
-
-void bumb_spawn()
-{
- self.vehicle_health = autocvar_g_vehicle_bumblebee_health;
- self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
- self.movetype = MOVETYPE_TOSS;
- self.solid = SOLID_BBOX;
- //self.vehicle_energy = 1;
- self.movetype = MOVETYPE_FLY;
- setorigin(self, self.origin + '0 0 25');
-}
-
-void bumb_die()
-{
- self.health = 0;
- self.event_damage = func_null;
- self.solid = SOLID_CORPSE;
- self.takedamage = DAMAGE_NO;
- self.deadflag = DEAD_DYING;
- self.movetype = MOVETYPE_BOUNCE;
-
- pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1);
-}
-
-void bumb_dinit()
-{
- if not (vehicle_initialize(
- "Bumblebee",
- "models/vehicles/bumblebee_body.dpm",
- "",
- "models/vehicles/spiderbot_cockpit.dpm",
- "", "", "tag_viewport",
- HUD_BUMBLEBEE,
- BUMB_MIN, BUMB_MAX,
- FALSE,
- bumb_spawn, autocvar_g_vehicle_bumblebee_respawntime,
- bumb_pilot_frame,
- bumb_enter, bumb_exit,
- bumb_die, bumb_think,
- FALSE))
- {
- remove(self);
- return;
- }
- self.gun1 = spawn();
- setmodel(self.gun1, "models/vehicles/bumblebee_ray.dpm");
- setattachment(self.gun1, self, "tag_hardpoint03");
-
- self.gun1 = spawn();
- self.gun2 = spawn();
-
- self.gun1.owner = self;
- self.gun2.owner = self;
-
- setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm");
- setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm");
-
- setattachment(self.gun1, self, "tag_hardpoint01");
- setattachment(self.gun2, self, "tag_hardpoint02");
-
- vector ofs;
- ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint01"));
- ofs -= self.origin;
- setattachment(self.gun1, self, "");
- setorigin(self.gun1, ofs);
-
- ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint02"));
- ofs -= self.origin;
- setattachment(self.gun2, self, "");
- setorigin(self.gun2, ofs);
-
-
-}
-
-void spawnfunc_vehicle_bumblebee()
-{
-
- precache_model ("models/vehicles/bumblebee_body.dpm");
- precache_model ("models/vehicles/bumblebee_plasma_left.dpm");
- precache_model ("models/vehicles/bumblebee_plasma_right.dpm");
- precache_model ("models/vehicles/bumblebee_ray.dpm");
-
- //vehicles_configcheck("vehicle_bumblebee.cfg", autocvar_g_vehicle_bumblebee_health);
-
- if(autocvar_g_vehicle_bumblebee_energy)
- if(autocvar_g_vehicle_bumblebee_energy_regen)
- self.vehicle_flags |= VHF_ENERGYREGEN;
-
- if(autocvar_g_vehicle_bumblebee_shield)
- self.vehicle_flags |= VHF_HASSHIELD;
-
- if(autocvar_g_vehicle_bumblebee_shield_regen)
- self.vehicle_flags |= VHF_SHIELDREGEN;
-
- if(autocvar_g_vehicle_bumblebee_health_regen)
- self.vehicle_flags |= VHF_HEALTHREGEN;
-
- self.think = bumb_dinit;
- self.nextthink = time + 1;
-}
-#endif // SVQC
-
-#ifdef CSQC
-void bumblebee_draw()
-{
-
-}
-
-void bumblebee_draw2d()
-{
-
-}
-
-void bumblebee_read_extra()
-{
-
-}
-
-void vehicle_bumblebee_assemble()
-{
-
-}
-#endif //CSQC
+++ /dev/null
-vector collision_force;
-vector collision_angle;
-
-vector bb1[9];
-vector bb2[9];
-
-float collision_run()
-{
- vector vtmp, vmin, vmax, vrot, vforce, vtmp2, vtmp3;
- float i, fvel, bcol;
-
-
- // Extract the 8 bbox corners from mins/maxs for self
- vmax = self.maxs;
- vmin = self.mins;
- bb1[0] = vmax;
- vtmp = vmax; vtmp_x = vmin_x; bb1[1] = vtmp;
- vtmp = vmax; vtmp_y = vmin_y; bb1[2] = vtmp;
- vtmp = vmin; vtmp_z = vmax_z; bb1[3] = vtmp;
- bb1[4] = vmin;
- vtmp = vmin; vtmp_x = vmax_x; bb1[5] = vtmp;
- vtmp = vmin; vtmp_y = vmax_y; bb1[6] = vtmp;
- vtmp = vmax; vtmp_z = vmin_z; bb1[7] = vtmp;
-
- makevectors(self.angles + '-2 0 0' * self.angles_x);
- bcol = 0;
-
- // Pass1: Transform by rotation, ajust points by impact/s
- for(i = 8; i >= 0; --i)
- {
- vtmp = bb1[i];
- vtmp = self.origin + vtmp_x * v_forward - vtmp_y * v_right + vtmp_z * v_up;
- traceline(self.origin, vtmp, MOVE_WORLDONLY, self);
- te_lightning1(world,self.origin,vtmp);
- if(trace_fraction != 1.0)
- {
- vforce += (trace_endpos - vtmp);
- vtmp3 = self.origin + self.velocity * frametime;
- vtmp2 = vectoangles(normalize(vtmp - vtmp3));
- vrot += (vectoangles(normalize(trace_endpos - vtmp3)) - vtmp2);
- bcol += 1;
- }
- }
-
- if(bcol)
- {
-
- vtmp = self.origin + self.velocity * frametime;
- self.angles += vrot * frametime;
- self.velocity += vforce * frametime;
-
- }
-
-}
-
+++ /dev/null
-#ifdef VEHICLES_CSQC
-// SendFlags
-float VSF_SETUP = 1; /// Send vehicle type etc
-float VSF_ORIGIN = 2; /// Send location
-float VSF_MOVEMENT = 4; /// Send movement update (and angles)
-float VSF_AVEL = 8; /// Send Angular velocity
-float VSF_STATS = 16; /// Send ammo, health etc
-float VSF_EXTRA = 32; /// Send additional data (turret rotations etc). Handeld per vehicle type.
-float VSF_ANIMINFO = 64; /// Animation info
-float VSF_FULL_UPDATE = 16777215; /// Send everything
-
-float VSX_FAR = 1;
-float VSX_OWNER = 2;
-float VSX_GUN1 = 4;
-float VSX_GUN2 = 8;
-
-#ifdef SVQC
-#define VSX_FARDISTANCE 2000
-float send_vehile(entity to, float sf)
-{
- float dist, xf;
-
- var void WriteFunc(float, float);
-
- dist = vlen(self.origin - to.origin);
- if(to == self.owner)
- xf |= VSX_OWNER;
- else if(dist > VSX_FARDISTANCE)
- xf |= VSX_FAR;
-
- // Always send a movement and origin to owner
- if(to == self.owner)
- sf |= VSF_ORIGIN | VSF_MOVEMENT;
-
- WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE);
-
- // We need to know client-side what was sent
- WriteByte(MSG_ENTITY, sf);
- WriteByte(MSG_ENTITY, xf);
-
- if(sf & VSF_SETUP)
- {
- WriteByte(MSG_ENTITY, self.hud); //vehicle type = hud
- WriteByte(MSG_ENTITY, self.team);
- WriteShort(MSG_ENTITY, self.colormap);
- WriteShort(MSG_ENTITY, self.vehicle_flags);
- }
-
- if(sf & VSF_ORIGIN)
- {
- WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord);
- WriteFunc(MSG_ENTITY, self.origin_x);
- WriteFunc(MSG_ENTITY, self.origin_y);
- WriteFunc(MSG_ENTITY, self.origin_z);
- }
-
- if(sf & VSF_MOVEMENT)
- {
- WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord);
- WriteFunc(MSG_ENTITY, self.velocity_x);
- WriteFunc(MSG_ENTITY, self.velocity_y);
- WriteFunc(MSG_ENTITY, self.velocity_z);
-
- WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteAngle);
- WriteFunc(MSG_ENTITY, self.angles_x);
- WriteFunc(MSG_ENTITY, self.angles_y);
- WriteFunc(MSG_ENTITY, self.angles_z);
- }
-
- if(sf & VSF_AVEL)
- {
- WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord);
- WriteFunc(MSG_ENTITY, self.avelocity_x);
- WriteFunc(MSG_ENTITY, self.avelocity_y);
- WriteFunc(MSG_ENTITY, self.avelocity_z);
- }
-
- if(sf & VSF_STATS)
- {
- WriteByte(MSG_ENTITY, self.vehicle_health);
- if(xf & VSX_OWNER)
- {
- WriteByte(MSG_ENTITY, self.vehicle_shield);
- WriteByte(MSG_ENTITY, self.vehicle_energy);
-
- WriteByte(MSG_ENTITY, self.vehicle_ammo1);
- WriteByte(MSG_ENTITY, self.vehicle_reload1);
-
- WriteByte(MSG_ENTITY, self.vehicle_ammo2);
- WriteByte(MSG_ENTITY, self.vehicle_reload2);
-
- }
- }
-
- if(sf & VSF_EXTRA)
- self.vehile_send_exta(to, sf);
-
- return TRUE;
-}
-
-void net_link_vehile()
-{
- self.SendFlags = 0xFFFFFF;
- Net_LinkEntity(self, FALSE, 0, send_vehile);
-}
-#endif // SVQC
-
-#ifdef CSQC
-void vehicle_spiderbot_assemble()
-{
-
-}
-
-void vehicle_raptor_assemble()
-{
-
-}
-
-void vehicle_bumblebee_assemble()
-{
-
-}
-
-.float lastupdate;
-void read_vehicle(float bIsNew)
-{
- float sf, xf;
- var float ReadFunc();
-
- sf = ReadByte();
- xf = ReadByte();
-
- if(xf & VSX_OWNER)
- vehicle = self;
-
- if(sf & VSF_SETUP)
- {
- self.vehicle_hud = ReadByte();
- self.team = ReadByte();
- self.colormap = ReadShort();
- self.vehicle_flags = ReadShort();
-
- switch(self.vehicle_hud)
- {
- case HUD_WAKIZASHI:
- vehicle_racer_assemble();
- break;
- case HUD_SPIDERBOT:
- vehicle_spiderbot_assemble();
- break;
- case HUD_RAPTOR:
- vehicle_raptor_assemble();
- break;
- case HUD_BUMBLEBEE:
- vehicle_bumblebee_assemble();
- break;
- default:
- break;
- }
- }
-
- if(self.vehicle_hud == HUD_WAKIZASHI && xf & VSX_OWNER)
- {
-
- vehicle_hudmodel.owner = self;
- }
-
- //if(xf & VSX_FAR)
- // dprint("Client vehicle faaar set\n");
-
- if(sf & VSF_ORIGIN)
- {
- ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord);
- self.origin_x = ReadFunc();
- self.origin_y = ReadFunc();
- self.origin_z = ReadFunc();
-
- setorigin(self, self.origin);
- //self.lastupdate = time;
- }
-
- if(sf & VSF_MOVEMENT)
- {
- ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord);
- self.velocity_x = ReadFunc();
- self.velocity_y = ReadFunc();
- self.velocity_z = ReadFunc();
-
- ReadFunc = ((sf & VSX_FAR) ? ReadShort : ReadAngle);
- self.angles_x = ReadFunc();
- self.angles_y = ReadFunc();
- self.angles_z = ReadFunc();
-
- //self.lastupdate = time;
- // self.move_velocity = self.velocity;
- // self.move_angles = self.angles;
- }
-
- if(sf & VSF_AVEL)
- {
- ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord);
- self.avelocity_x = ReadFunc();
- self.avelocity_y = ReadFunc();
- self.avelocity_z = ReadFunc();
-
- // self.move_avelocity = self.avelocity;
- }
-
- if(sf & VSF_STATS)
- {
- self.vehicle_health = ReadByte();
- if(xf & VSX_OWNER)
- {
- self.vehicle_shield = ReadByte();
- self.vehicle_energy = ReadByte();
- self.vehicle_ammo1 = ReadByte();
- self.vehicle_reload1 = ReadByte();
- self.vehicle_ammo2 = ReadByte();
- self.vehicle_reload2 = ReadByte();
- }
- }
-
- if(sf & VSF_EXTRA)
- self.vehile_read_exta(sf);
-
-}
-
-#endif // CSQC
-#else
-#ifdef CSQC
-.float lastupdate;
-void read_vehicle(float bIsNew)
-{
-
-}
-#endif
-#endif // VEHICLES_CSQC
+++ /dev/null
-/// Some default stacks.
-.entity verbs_idle;
-.entity verbs_attack;
-.entity verbs_move;
-//.entity vchain;
-
-/// This global gets set to the verb in question each time the stack manager calls verb_call
-entity verb;
-//.entity current_verb;
-//.float verb_done;
-
-/// Execure this verb
-#define VCM_DO 0
-/// Return the value of this verb. Return VS_CALL_REMOVE to delete it.
-#define VCM_EVAL 1
-/// This verb is beeing removed NOW (not sent when verb_call returns VS_CALL_REMOVE)
-#define VCM_REMOVE 2
-
-/// Verb callback
-.float(float message) verb_call;
-
-/// Points to this verb's stack.
-.entity verbstack;
-
-/// Static value of this verb
-.float verb_static_value;
-
-/// verb_call returns this when a verb in not doable
-#define VS_CALL_NO 0
-/// verb_call(VCM_DO) returns this when a verb is executing
-#define VS_CALL_YES_DOING -1
-/// verb_call(VCM_DO) returns this when a verb did execure and is done
-#define VS_CALL_YES_DONE -2
-/// verb_call(VCM_DO) returns this when a verb should be deleted by the stack manager
-#define VS_CALL_REMOVE -3
-
-/*
-void verbstack_updatechain(entity stack)
-{
- entity vrb, v;
- if not (stack)
- return;
-
- dprint("verbstack_updatechain\n");
-
- vrb = findchainentity(verbstack, stack);
- if not (vrb)
- {
- stack.vchain = world;
- return;
- }
-
- stack.vchain = vrb;
- v = vrb;
-
- while(vrb)
- {
- vrb = vrb.chain;
-
-
- }
-}
-
-void verbstack_remove(entity vverb)
-{
- entity vstack;
- dprint("verbstack_remove\n");
-
- vstack = verb.verbstack;
- remove(vverb);
- vverb.verbstack = world;
- verbstack_updatechain(vstack);
-
- //vverb.think = SUB_Remove;
- //vverb.nextthink = time;
-}
-
-void verbstack_thinkremove()
-{
- dprint("verbstack_thinkremove\n");
- verbstack_remove(self);
-}
-*/
-
-/**
- Push a new verb onto the specified stack. Set vrb_life to make it time-limited.
-**/
-entity verbstack_push(entity stack, float(float eval) vrb_call, float val_static, float vrb_life,entity verb_owner)
-{
- entity vrb;
-
- if not(stack)
- return world;
-
- if not(vrb_call)
- return world;
-
- vrb = spawn();
- vrb.owner = verb_owner;
- vrb.verbstack = stack;
- vrb.verb_call = vrb_call;
- vrb.verb_static_value = val_static;
-
- vrb.classname = "verb";
- stack.classname = "verbstack";
-
- if(vrb_life)
- {
- //vrb.think = verbstack_thinkremove;
- vrb.think = SUB_Remove;
- vrb.nextthink = time + vrb_life;
- }
-
- //verbstack_updatechain(stack);
-
- return vrb;
-}
-
-/**
- Find the best verb in this stack and execurte it.
- ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL or VCM_DO
-**/
-float verbstack_pop(entity stack)
-{
- entity vrb, bestverb, oldself;
- float value, bestvalue;
-
- oldself = self;
-
- vrb = findchainentity(verbstack,stack);
- //vrb = stack.vchain;
- //dprint("owner:", stack.owner.classname, " vsn:", stack.classname,"\n");
- while(vrb)
- {
- //dprint("vn:", vrb.classname,"\n");
- verb = vrb;
- vrb = vrb.chain;
- self = verb.owner;
- value = verb.verb_call(VCM_EVAL);
-
- if(value < 0)
- {
- if(value == VS_CALL_REMOVE)
- remove(verb);
- }
- else
- {
- if(value > bestvalue)
- {
- bestverb = verb;
- bestvalue = value;
- }
- }
- }
-
- if(bestverb)
- {
- verb = bestverb;
- self = verb.owner;
- value = verb.verb_call(VCM_DO);
-
- if(value == VS_CALL_REMOVE)
- remove(bestverb);
- }
-
- self = oldself;
-
- return value;
-}
-
-float verbstack_popfifo(entity stack)
-{
- entity oldself;
- float ret;
-
- oldself = self;
- verb = findentity(stack,verbstack,stack);
- if not (verb)
- ret = 0;
- else
- {
- self = verb.owner;
- ret = verb.verb_call(VCM_DO);
-
- if(ret == VS_CALL_REMOVE)
- remove(verb);
- }
-
- self = oldself;
- return ret;
-}
-
-/**
- Find the best verb in this stack and return it.
- ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL.
-**/
-entity verbstack_pull(entity stack)
-{
- entity vrb;
- entity bestverb, oldself;
- float value, bestvalue;
-
- oldself = self;
-
- vrb = findchainentity(verbstack,stack);
- while(vrb)
- {
- self = vrb.owner;
-
- verb = vrb;
- vrb = vrb.chain;
- value = verb.verb_call(VCM_EVAL);
-
- if(value < 0)
- {
- if(value == VS_CALL_REMOVE)
- remove(verb);
- }
- else
- {
- if(value > bestvalue)
- {
- bestverb = verb;
- bestvalue = value;
- }
- }
- }
-
- self = oldself;
-
- return bestverb;
-}
-
-entity verbstack_pullfifo(entity stack)
-{
- return findentity(stack,verbstack,stack);
-}
-
-/**
- Delete every verb on this stack, signaling them with VCM_REMOVE first.
-**/
-void verbstack_flush(entity stack)
-{
- entity vrb, oldself;
-
- oldself = self;
-
- vrb = findchainentity(verbstack,stack);
- while(vrb)
- {
- self = vrb.owner;
-
- verb = vrb;
- vrb = vrb.chain;
- verb.verb_call(VCM_REMOVE);
- remove(verb);
- }
-
- self = oldself;
-
- //stack.vchain = world;
-}
-
-void verbstack_doverb(entity vrb)
-{
- float value;
-
- verb = vrb;
- self = verb.owner;
- value = verb.verb_call(VCM_DO);
-
- if(value == VS_CALL_REMOVE)
- remove(vrb);
-}