35 #ifdef KH_PLAYER_USE_ATTACHMENT 36 const vector KH_PLAYER_ATTACHMENT_DIST_ROTATED =
'0 -4 0';
37 const vector KH_PLAYER_ATTACHMENT_DIST =
'4 0 0';
38 const vector KH_PLAYER_ATTACHMENT =
'0 0 0';
39 const vector KH_PLAYER_ATTACHMENT_ANGLES =
'0 0 0';
40 const string KH_PLAYER_ATTACHMENT_BONE =
"";
92 field(SP_KH_PUSHES,
"pushes", 0);
94 field(SP_KH_PICKUPS,
"pickups", 0);
95 field(SP_KH_KCKILLS,
"kckills", 0);
115 if(!this.
owner.owner)
131 s |= (32 ** key.count) * f;
139 STAT(OBJECTIVE_STATUS, key.owner) |= (32 ** key.count) * 31;
165 else if(this.
cnt == 0)
184 if(key && key.owner && frags_owner)
190 s =
strcat(
":keyhunt:", what,
":",
ftos(player.playerid),
":",
ftos(frags_player));
200 s =
strcat(s, key.netname);
218 #ifdef KH_PLAYER_USE_ATTACHMENT 219 entity first = key.owner.kh_next;
222 setattachment(key, key.owner, KH_PLAYER_ATTACHMENT_BONE);
225 setattachment(key.kh_next, key,
"");
226 setorigin(key, key.kh_next.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
227 setorigin(key.kh_next, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
228 key.kh_next.angles =
'0 0 0';
232 key.angles = KH_PLAYER_ATTACHMENT_ANGLES;
236 setattachment(key, key.kh_prev,
"");
238 setattachment(key.kh_next, key,
"");
239 setorigin(key, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
240 setorigin(first, first.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
241 key.angles =
'0 0 0';
244 setattachment(key, key.owner,
"");
246 key.angles_y -= key.owner.angles.y;
253 key.team = key.owner.team;
254 key.nextthink =
time;
255 key.damageforcescale = 0;
263 #ifdef KH_PLAYER_USE_ATTACHMENT 264 entity first = key.owner.kh_next;
269 setattachment(key.kh_next, key.owner, KH_PLAYER_ATTACHMENT_BONE);
270 setorigin(key.kh_next, key.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
271 key.kh_next.angles = KH_PLAYER_ATTACHMENT_ANGLES;
277 setattachment(key.kh_next, key.kh_prev,
"");
278 setorigin(first, first.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
281 setattachment(key,
NULL,
"");
282 setorigin(key, key.owner.origin +
'0 0 1' * (STAT(PL_MIN, key.owner).z - KH_KEY_MIN_z));
283 key.angles = key.owner.angles;
285 setorigin(key, key.owner.origin + key.origin.z *
'0 0 1');
286 setattachment(key,
NULL,
"");
287 key.angles_y += key.owner.angles.y;
300 key.kh_previous_owner = key.owner;
301 key.kh_previous_owner_playerid = key.owner.playerid;
306 if(key.owner == player)
317 key.kh_next.kh_prev = key.kh_prev;
318 key.kh_prev.kh_next = key.kh_next;
322 if(key.owner.kh_next ==
NULL)
326 WaypointSprite_Ping(key.owner.waypointsprite_attachedforcarrier);
327 WaypointSprite_DetachCarrier(key.owner);
336 key.kh_next = player.kh_next;
337 key.kh_prev = player;
338 player.kh_next = key;
340 key.kh_next.kh_prev = key;
344 if(key.kh_next ==
NULL)
347 entity wp = WaypointSprite_AttachCarrier(WP_Null, player, RADARICON_FLAGCARRIER);
350 WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team,
SPRITERULE_TEAMPLAY);
352 WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierRed, WP_KeyCarrierFriend, WP_KeyCarrierRed);
354 WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierBlue, WP_KeyCarrierFriend, WP_KeyCarrierBlue);
356 WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierYellow, WP_KeyCarrierFriend, WP_KeyCarrierYellow);
358 WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierPink, WP_KeyCarrierFriend, WP_KeyCarrierPink);
360 WaypointSprite_Ping(player.waypointsprite_attachedforcarrier);
370 if(ownerteam != ownerteam0)
381 if (!k.owner)
continue;
383 FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
385 FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
386 WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFinish, third);
396 if (!k.owner)
continue;
398 FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
400 FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
401 WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFriend, third);
420 this.
team = attacker.team;
427 if(key.kh_dropperteam != player.team)
432 key.kh_dropperteam = 0;
434 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(realteam, INFO_KEYHUNT_PICKUP), player.netname);
457 if(toucher == this.
enemy)
468 WaypointSprite_Kill(key.waypointsprite_attachedforcarrier);
470 WaypointSprite_DetachCarrier(key);
480 if (o.kh_worldkeynext == key)
482 o.kh_worldkeynext = o.kh_worldkeynext.kh_worldkeynext;
485 o = o.kh_worldkeynext;
528 string keyowner =
"";
530 if(key.owner.kh_next == key)
533 keyowner =
strcat(keyowner,
", ");
534 keyowner = key.owner.netname;
538 Send_Notification(NOTIF_ALL,
NULL, MSG_CENTER,
APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
539 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(winner_team, INFO_KEYHUNT_CAPTURE), keyowner);
542 vector firstorigin =
'0 0 0', lastorigin =
'0 0 0', midpoint =
'0 0 0';
547 midpoint += thisorigin;
554 Send_Effect(EFFECT_TR_NEXUIZPLASMA, lastorigin, thisorigin, 1);
556 lastorigin = thisorigin;
558 firstorigin = thisorigin;
564 Send_Effect(EFFECT_TR_NEXUIZPLASMA, lastorigin, firstorigin, 1);
567 te_customflash(midpoint, 1000, 1,
Team_ColorRGB(winner_team) * 0.5 +
'0.5 0.5 0.5');
569 play2all(
SND(KH_CAPTURE));
578 if(lostkey.pusher.team != loser_team)
580 attacker = lostkey.pusher;
584 if(lostkey.kh_previous_owner)
601 if(key.owner && key.team != loser_team)
604 if(lostkey.kh_previous_owner)
608 if(lostkey.kh_previous_owner.playerid == lostkey.kh_previous_owner_playerid)
614 if(key.owner && key.team != loser_team)
627 if(thisteam == loser_team)
638 f = DistributeEvenly_Get(1);
639 kh_Scores_Event(it, NULL,
"destroyed", f, 0);
647 Send_Notification(NOTIF_ALL,
NULL, MSG_CENTER,
APP_TEAM_NUM(loser_team, CENTER_ROUND_TEAM_LOSS));
649 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(realteam, INFO_KEYHUNT_PUSHED), attacker.netname, lostkey.kh_previous_owner.netname);
651 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(realteam, INFO_KEYHUNT_DESTROYED), lostkey.kh_previous_owner.netname);
653 play2all(
SND(KH_DESTROY));
654 te_tarexplosion(lostkey.origin);
666 #ifndef KH_PLAYER_USE_ATTACHMENT 702 Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_MEET);
704 Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_HELP);
722 entity key =
new(item_kh_key);
726 key.nextthink =
time;
728 key.angles =
'0 360 0' *
random();
735 key.kh_dropperteam = 0;
742 switch(initial_owner.team)
745 key.netname =
"^1red key";
748 key.netname =
"^4blue key";
751 key.netname =
"^3yellow key";
754 key.netname =
"^6pink key";
757 key.netname =
"NETGIER key";
765 Send_Notification(NOTIF_ONE, initial_owner, MSG_CENTER,
APP_TEAM_NUM(initial_owner.team, CENTER_KEYHUNT_START));
767 WaypointSprite_Spawn(WP_KeyDropped, 0, 0, key,
'0 0 1' *
KH_KEY_WP_ZSHIFT,
NULL, key.team, key, waypointsprite_attachedforcarrier,
false, RADARICON_FLAG);
785 else if(teem != key.team)
797 entity player = key.owner;
799 key.kh_droptime =
time;
805 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(realteam, INFO_KEYHUNT_DROP), player.netname);
812 key.kh_dropperteam = key.team;
823 if(
time < player.pushltime)
824 mypusher = player.pusher;
827 while((key = player.kh_next))
832 Send_Notification(NOTIF_ALL,
NULL, MSG_INFO,
APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), player.netname);
836 key.pusher = mypusher;
839 key.kh_dropperteam = player.team;
847 int missing_teams = 0;
857 missing_teams |=
BIT(i);
859 return missing_teams;
864 static int prev_missing_teams_mask;
865 if(
time < game_starttime)
867 if (prev_missing_teams_mask > 0)
868 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_MISSING_TEAMS);
869 prev_missing_teams_mask = -1;
875 if(!missing_teams_mask)
877 if(prev_missing_teams_mask > 0)
878 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_MISSING_TEAMS);
879 prev_missing_teams_mask = -1;
887 if(prev_missing_teams_mask > 0)
888 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_MISSING_TEAMS);
889 prev_missing_teams_mask = -1;
893 if(prev_missing_teams_mask != missing_teams_mask)
895 Send_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
896 prev_missing_teams_mask = missing_teams_mask;
905 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_KEYHUNT);
906 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
913 if(
time < game_starttime)
925 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_KEYHUNT);
926 Kill_Notification(NOTIF_ALL,
NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
937 if(random() * players <= 1)
956 if(attacker.team == targ.team)
959 for(
entity k = targ.kh_next; k !=
NULL; k = k.kh_next)
994 #ifdef KH_PLAYER_USE_CARRIEDMODEL 1028 if(head.owner ==
this)
1034 if(!head.owner || head.team !=
this.team)
1043 else if(head.team ==
this.team)
1059 LOG_TRACE(
"changing role to freelancer");
1097 LOG_TRACE(
"changing role to freelancer");
1105 float key_owner_team;
1109 if(key_owner_team == this.
team)
1111 else if(key_owner_team == -1)
1139 LOG_TRACE(
"changing role to freelancer");
1147 float key_owner_team;
1152 if(key_owner_team == this.
team)
1154 else if(key_owner_team == -1)
1201 if(key_owner_team == this.
team)
1203 else if(key_owner_team == -1)
1236 if(frag_target == frag_attacker)
1248 float frag_score =
M_ARGV(2,
float);
1269 entity k = player.kh_next;
void havocbot_goalrating_kh(entity this, float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
ERASEABLE void IL_REMOVE(IntrusiveList this, entity it)
Remove any element, anywhere in the list.
#define APP_TEAM_NUM(num, prefix)
int autocvar_g_keyhunt_teams_override
#define GameRules_scoring(teams, spprio, stprio, fields)
const float KH_KEY_XYDIST
float havocbot_role_timeout
#define PHYS_INPUT_BUTTON_CHAT(s)
void kh_Key_Spawn(entity initial_owner, float _angle, float i)
void navigation_goalrating_start(entity this)
const int CBC_ORDER_EXCLUSIVE
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
void kh_Key_Touch(entity this, entity toucher)
void havocbot_role_kh_carrier(entity this)
float autocvar_g_balance_keyhunt_delay_collect
void kh_Key_Attach(entity key)
void navigation_goalrating_end(entity this)
void kh_WinnerTeam(int winner_team)
void kh_Controller_Think(entity this)
vector Team_ColorRGB(int teamid)
float autocvar_g_balance_keyhunt_delay_round
void kh_Key_DropOne(entity key)
const float KH_KEY_WP_ZSHIFT
const int SFL_SORT_PRIO_SECONDARY
Scoring priority (NOTE: PRIMARY is used for fraglimit)
void navigation_dynamicgoal_init(entity this, bool initially_static)
#define FOREACH_CLIENT(cond, body)
#define GameRules_scoring_add(client, fld, value)
int autocvar_g_balance_keyhunt_score_carrierfrag
const int SFL_SORT_PRIO_PRIMARY
int kh_previous_owner_playerid
float autocvar_g_balance_keyhunt_return_when_unreachable
void navigation_dynamicgoal_set(entity this, entity dropper)
bool kh_KeyCarrier_waypointsprite_visible_for_player(entity this, entity player, entity view)
float DPCONTENTS_PLAYERCLIP
float kh_HandleFrags(entity attacker, entity targ, float f)
void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner)
int autocvar_g_balance_keyhunt_score_capture
const float KH_KEY_ZSHIFT
float autocvar_g_balance_keyhunt_throwvelocity
MUTATOR_HOOKFUNCTION(kh, ClientDisconnect)
vector kh_AttachedOrigin(entity e)
ERASEABLE bool IL_CONTAINS(IntrusiveList this, entity it)
const int SFL_LOWER_IS_BETTER
Lower scores are better (e.g.
void navigation_routerating(entity this, entity e, float f, float rangebias)
void kh_Controller_SetThink(float t, kh_Think_t func)
ERASEABLE float DistributeEvenly_Get(float weight)
#define setmodel(this, m)
const int SPRITERULE_TEAMPLAY
float autocvar_g_balance_keyhunt_delay_damage_return
float autocvar_g_balance_keyhunt_delay_tracking
void nades_GiveBonus(entity player, float score)
float autocvar_g_balance_keyhunt_maxdist
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
float autocvar_g_balance_keyhunt_dropvelocity
const float MOVE_NOMONSTERS
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void kh_Key_Think(entity this)
int autocvar_g_balance_keyhunt_score_destroyed
bool navigation_goalrating_timeout(entity this)
void kh_ScoreRules(int teams)
float autocvar_g_balance_keyhunt_protecttime
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
#define GameRules_scoring_add_team(client, fld, value)
void kh_Key_Collect(entity key, entity player)
void PlayerUseKey(entity this)
void UpdateFrags(entity player, int f)
bool kh_Key_waypointsprite_visible_for_player(entity this, entity player, entity view)
float autocvar_g_balance_keyhunt_damageforcescale
void key_reset(entity this)
int kh_Key_AllOwnedByWhichTeam()
const int CBC_ORDER_FIRST
void havocbot_role_kh_offense(entity this)
const float KH_KEY_XYSPEED
const float KH_KEY_BRIGHTNESS
void kh_Key_AssignTo(entity key, entity player)
void GameLogEcho(string s)
#define MUTATOR_RETURNVALUE
var kh_Think_t kh_Controller_Thinkfunc
void navigation_goalrating_timeout_set(entity this)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define ITEM_DAMAGE_NEEDKILL(dt)
float kh_interferemsg_time
int autocvar_g_balance_keyhunt_score_push
void navigation_dynamicgoal_unset(entity this)
float autocvar_g_balance_keyhunt_delay_return
int autocvar_g_balance_keyhunt_score_collect
#define ITEM_TOUCH_NEEDKILL()
void havocbot_role_kh_defense(entity this)
void(entity this) havocbot_role_kh_carrier
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
ERASEABLE void DistributeEvenly_Init(float amount, float totalweight)
void kh_Key_DropAll(entity player, float suicide)
#define FOR_EACH_KH_KEY(v)
const float SOLID_TRIGGER
#define new_pure(class)
purely logical entities (.origin doesn't work)
void kh_Key_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings...
vector W_CalculateProjectileVelocity(entity actor, vector pvelocity, vector mvelocity, float forceAbsolute)
#define sound(e, c, s, v, a)
void havocbot_role_kh_freelancer(entity this)
bool autocvar_sv_eventlog
void kh_Key_Detach(entity key)
#define FOREACH(list, cond, body)
void kh_Key_Remove(entity key)
void set_movetype(entity this, int mt)
#define colormapPaletteColor(c, isPants)
void kh_EnableTrackingDevice()
int autocvar_g_balance_keyhunt_score_destroyed_ownfactor
void kh_LoserTeam(int loser_team, entity lostkey)