X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fcommon%2Fgamemodes%2Fgamemode%2Flms%2Fsv_lms.qc;h=1d47326929b7851dcd8e24b3676a0d22d71cb6b0;hp=bd6401d172931ea66eb07776258bc26258e8c1ca;hb=4e21f418ad9e6287efb942c1fa2861a51981110a;hpb=91bd86fc694af8c3555cc465d4d75250a8528b5e diff --git a/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc b/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc index bd6401d172..1d47326929 100644 --- a/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc +++ b/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc @@ -3,18 +3,33 @@ #include #include #include +#include +#include int autocvar_g_lms_extra_lives; bool autocvar_g_lms_join_anytime; int autocvar_g_lms_last_join; bool autocvar_g_lms_regenerate; +int autocvar_g_lms_leader_wp_lives; +float autocvar_g_lms_leader_wp_max_relative; +float autocvar_g_lms_leader_wp_time; +float autocvar_g_lms_leader_wp_time_repeat; +float autocvar_g_lms_dynamic_respawn_delay; +float autocvar_g_lms_dynamic_respawn_delay_base; +float autocvar_g_lms_dynamic_respawn_delay_increase; +bool autocvar_g_lms_dynamic_vampire; +float autocvar_g_lms_dynamic_vampire_factor_base; +float autocvar_g_lms_dynamic_vampire_factor_increase; +float autocvar_g_lms_dynamic_vampire_factor_max; +int autocvar_g_lms_dynamic_vampire_min_lives_diff; + +.float lms_wp_time; // main functions -float LMS_NewPlayerLives() +int LMS_NewPlayerLives() { - float fl; - fl = autocvar_fraglimit; - if(fl == 0) + int fl = floor(autocvar_fraglimit); + if(fl == 0 || fl > 999) fl = 999; // first player has left the game for dying too much? Nobody else can get in. @@ -22,7 +37,7 @@ float LMS_NewPlayerLives() return 0; if(!autocvar_g_lms_join_anytime) - if(lms_lowest_lives < fl - autocvar_g_lms_last_join) + if(lms_lowest_lives < fl - max(0, floor(autocvar_g_lms_last_join))) return 0; return bound(1, lms_lowest_lives, fl); @@ -126,6 +141,8 @@ MUTATOR_HOOKFUNCTION(lms, reset_map_players) it.frags = FRAGS_PLAYER; GameRules_scoring_add(it, LMS_LIVES, LMS_NewPlayerLives()); PutClientInServer(it); + if (it.waypointsprite_attachedforcarrier) + WaypointSprite_Kill(it.waypointsprite_attachedforcarrier); }); } @@ -155,15 +172,40 @@ MUTATOR_HOOKFUNCTION(lms, PutClientInServer) } } +MUTATOR_HOOKFUNCTION(lms, CalculateRespawnTime) +{ + entity player = M_ARGV(0, entity); + player.respawn_flags |= RESPAWN_FORCE; + + if (autocvar_g_lms_dynamic_respawn_delay <= 0) + return false; + + int pl_lives = GameRules_scoring_add(player, LMS_LIVES, 0); + int max_lives = 0; + int pl_cnt = 0; + FOREACH_CLIENT(it != player && IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + int lives = GameRules_scoring_add(it, LMS_LIVES, 0); + if (lives > max_lives) + max_lives = lives; + pl_cnt++; + }); + + // min delay with only 2 players + if (pl_cnt == 1) // player wasn't counted + max_lives = 0; + + player.respawn_time = time + autocvar_g_lms_dynamic_respawn_delay_base + + autocvar_g_lms_dynamic_respawn_delay_increase * max(0, max_lives - pl_lives); + return true; +} + MUTATOR_HOOKFUNCTION(lms, ForbidSpawn) { entity player = M_ARGV(0, entity); if(warmup_stage) return false; - if(player.frags == FRAGS_SPECTATOR) - return true; - if(GameRules_scoring_add(player, LMS_LIVES, 0) <= 0) + if(player.frags == FRAGS_SPECTATOR || GameRules_scoring_add(player, LMS_LIVES, 0) <= 0) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_LMS_NOLIVES); return true; @@ -171,40 +213,29 @@ MUTATOR_HOOKFUNCTION(lms, ForbidSpawn) return false; } -MUTATOR_HOOKFUNCTION(lms, PlayerDies) -{ - entity frag_target = M_ARGV(2, entity); - - frag_target.respawn_flags |= RESPAWN_FORCE; -} - void lms_RemovePlayer(entity player) { static int quitters = 0; float player_rank = GameRules_scoring_add(player, LMS_RANK, 0); if (!player_rank) { - int pl_cnt = 0; - FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { - pl_cnt++; - }); if (player.lms_spectate_warning < 2) { - if(IS_BOT_CLIENT(player)) - bot_clear(player); player.frags = FRAGS_PLAYER_OUT_OF_GAME; + int pl_cnt = 0; + FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + pl_cnt++; + }); GameRules_scoring_add(player, LMS_RANK, pl_cnt + 1); } else { - lms_lowest_lives = 999; FOREACH_CLIENT(true, { if (it.frags == FRAGS_PLAYER_OUT_OF_GAME) { float it_rank = GameRules_scoring_add(it, LMS_RANK, 0); if (it_rank > player_rank && it_rank <= 256) GameRules_scoring_add(it, LMS_RANK, -1); - lms_lowest_lives = 0; } else if (it.frags != FRAGS_SPECTATOR) { @@ -294,6 +325,109 @@ MUTATOR_HOOKFUNCTION(lms, ForbidThrowCurrentWeapon) return true; } +MUTATOR_HOOKFUNCTION(lms, Damage_Calculate) +{ + if (!autocvar_g_lms_dynamic_vampire) + return; + + entity frag_attacker = M_ARGV(1, entity); + entity frag_target = M_ARGV(2, entity); + float frag_damage = M_ARGV(4, float); + + if (IS_PLAYER(frag_attacker) && !IS_DEAD(frag_target) && frag_attacker != frag_target) + { + float vampire_factor = 0; + + int frag_attacker_lives = GameRules_scoring_add(frag_attacker, LMS_LIVES, 0); + int frag_target_lives = GameRules_scoring_add(frag_target, LMS_LIVES, 0); + int diff = frag_target_lives - frag_attacker_lives - autocvar_g_lms_dynamic_vampire_min_lives_diff; + + if (diff >= 0) + vampire_factor = autocvar_g_lms_dynamic_vampire_factor_base + diff * autocvar_g_lms_dynamic_vampire_factor_increase; + if (vampire_factor > 0) + { + vampire_factor = min(vampire_factor, autocvar_g_lms_dynamic_vampire_factor_max); + SetResourceExplicit(frag_attacker, RES_HEALTH, + min(GetResource(frag_attacker, RES_HEALTH) + frag_damage * vampire_factor, start_health)); + } + } +} + +bool lms_waypointsprite_visible_for_player(entity this, entity player, entity view) // runs on waypoints which are attached to ballcarriers, updates once per frame +{ + if(view.lms_wp_time) + if(IS_SPEC(player)) + return false; // we don't want spectators of leaders to see the attached waypoint on the top of their screen + + float leader_time = autocvar_g_lms_leader_wp_time; + float leader_repeat_time = leader_time + autocvar_g_lms_leader_wp_time_repeat; + float wp_time = this.owner.lms_wp_time; + if (wp_time && (time - wp_time) % leader_repeat_time > leader_time) + return false; + + return true; +} + +void lms_UpdateWaypoints() +{ + int max_lives = 0; + int pl_cnt = 0; + FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + int lives = GameRules_scoring_add(it, LMS_LIVES, 0); + if (lives > max_lives) + max_lives = lives; + pl_cnt++; + }); + + int second_max_lives = 0; + int pl_cnt_with_max_lives = 0; + FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + int lives = GameRules_scoring_add(it, LMS_LIVES, 0); + if (lives == max_lives) + pl_cnt_with_max_lives++; + else if (lives > second_max_lives) + second_max_lives = lives; + }); + + int lives_diff = autocvar_g_lms_leader_wp_lives; + if (max_lives - second_max_lives >= lives_diff && pl_cnt_with_max_lives <= pl_cnt * autocvar_g_lms_leader_wp_max_relative) + FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + int lives = GameRules_scoring_add(it, LMS_LIVES, 0); + if (lives == max_lives) + { + if (!it.waypointsprite_attachedforcarrier) + { + WaypointSprite_AttachCarrier(WP_LmsLeader, it, RADARICON_FLAGCARRIER); + it.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = lms_waypointsprite_visible_for_player; + WaypointSprite_UpdateRule(it.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT); + vector pl_color = colormapPaletteColor(it.clientcolors & 0x0F, false); + WaypointSprite_UpdateTeamRadar(it.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, pl_color); + WaypointSprite_Ping(it.waypointsprite_attachedforcarrier); + } + if (!it.lms_wp_time) + it.lms_wp_time = time; + } + else + { + if (it.waypointsprite_attachedforcarrier) + WaypointSprite_Kill(it.waypointsprite_attachedforcarrier); + it.lms_wp_time = 0; + } + }); + else + FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { + if (it.waypointsprite_attachedforcarrier) + WaypointSprite_Kill(it.waypointsprite_attachedforcarrier); + it.lms_wp_time = 0; + }); +} + +MUTATOR_HOOKFUNCTION(lms, PlayerDied) +{ + if (!warmup_stage && autocvar_g_lms_leader_wp_lives > 0) + lms_UpdateWaypoints(); +} + MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill) { entity frag_target = M_ARGV(1, entity); @@ -310,8 +444,6 @@ MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill) FOREACH_CLIENT(IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME, { pl_cnt++; }); - if(IS_BOT_CLIENT(frag_target)) - bot_clear(frag_target); frag_target.frags = FRAGS_PLAYER_OUT_OF_GAME; GameRules_scoring_add(frag_target, LMS_RANK, pl_cnt); } @@ -323,7 +455,7 @@ MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill) MUTATOR_HOOKFUNCTION(lms, SetStartItems) { - start_items &= ~IT_UNLIMITED_AMMO; + start_items &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS); start_health = warmup_start_health = cvar("g_lms_start_health"); start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor"); start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells"); @@ -358,6 +490,7 @@ void lms_extralife(entity this) MUTATOR_HOOKFUNCTION(lms, OnEntityPreSpawn) { + if (MUTATOR_RETURNVALUE) return false; if (!autocvar_g_powerups) return false; if (!autocvar_g_lms_extra_lives) return false; @@ -379,12 +512,14 @@ MUTATOR_HOOKFUNCTION(lms, OnEntityPreSpawn) MUTATOR_HOOKFUNCTION(lms, ItemTouch) { + if(MUTATOR_RETURNVALUE) return false; + entity item = M_ARGV(0, entity); entity toucher = M_ARGV(1, entity); if(item.itemdef == ITEM_ExtraLife) { - Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES); + Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES, autocvar_g_lms_extra_lives); GameRules_scoring_add(toucher, LMS_LIVES, autocvar_g_lms_extra_lives); return MUT_ITEMTOUCH_PICKUP; } @@ -449,5 +584,5 @@ MUTATOR_HOOKFUNCTION(lms, AddPlayerScore) void lms_Initialize() { - lms_lowest_lives = 9999; + lms_lowest_lives = 999; }