Телепортация потерявшихся монстров

Тема в разделе "Общего назначения", создана пользователем Flame, 31 окт 2012.

Метки:
  1. Flame

    Flame -Заслуженый кодер форума-

    [​IMG]
    ExEnSpooT картиночку подогнал к мутатору ))

    Обновил 8 марта 2013
    Измываемся над потерявшимися зомбиками
    3 режима - телепортация зомбика на случайную точку спавна (ZombieVolume), телепортация к случайному игроку, уничтожение
    + возможность из командной строки убить всё живое (в зависимости от настроек убивать может админ, человек из списка или любой игрок после определённого времени)

    В мутаторе зомбики обрабатываются в 3 этапа. (Если какой-нибудь из них не отключён в настройках)
    Во-первых, как только зомбик теряется в текстурах или ещё где и не может найти игроков - применяем заданное действие (2 типа телепорта или убийство)
    Во-вторых, если прошло определённое количество времени после последнего убийства зомбика (именно от рук игрока), то применяем заданное действие (этот этап похож на действие старой версии мутатора)
    В-третьих есть возможность убить особо упрямых зомби из командной строки

    Переменные:
    CfgSecondsToWait - через данное количество секунд после убийства последнего монстра к оставшимся зомбикам применяется заданное действие

    CfgSecondsToMutateKillEnabled - через данное количество секунд после убийства последнего монстра обычные игроки получают возможность убивать оставшихся зомбиков из командной строки

    CfgNumberOfTries - количество попыток применить заданное действие, если после этого количества попыток зомбики прибывают всё ещё не там где надо - они убиваются
    Тут в принципе нормальное значение - 5. В ини по умолчанию 10. Можно не трогать особо этот параметр.

    CfgDistanceCoiff - если выбран режим телепортации к случайному игроку, то этот коэф. отвечает за то, как близко от игрока появляются зомбики.
    4-5 вполне ничего как значение по-умолчанию

    CfgRegime - собственно здесь и задаётся что мы делаем с зомбиками
    если CfgRegime=0 - зомбики телепортируются на случайные точки спавна
    если CfgRegime=1 - зомбики телепортируются к случайным игрокам
    при любых других значениях - зомбики убиваются

    CfgWorksOnBossWave - работает ли заданное действие и убийство из командной строки во время волны с патриком
    Лучше бы false, чтобы нельзя было воспользоваться командной строкой

    CfgTimerInterval - как часто идут проверки - "надо ли выполнять какое-то действие?"
    15 нормальный интервал

    CfgInstantActionEnabled - включает или отключает 1 этап (см. выше).
    По-умолчанию true. Если вдруг косяк в коде и монстры сразу телепортируются или умирают и не по делу это делают, то можно поставить false

    CfgTimedActionEnabled - включает или отключает 2 этап (см. выше).
    По-умолчанию true.

    CfgVipList - массив, для игрока с данным ID есть возможность сразу вызвать убийство зомби из командной строки

    CfgMapList - массив карт для которых мутатор не работает (командная строка работает)
    Например, надо сюда включить карты на прохождение, иначе игровой процесс будет своеобразным ))

    Убийство зомби вызывать командной mutate killzeds
    Ссылка 1 или Ссылка 2
    Добавлять в виде LostZombiesMut.LostZombiesMut

    p.s. Не очень то проверял насколько всё идеально работает - написал по сути за ночь)
    Так что пишите косяки. Потихоньку поправлю
    Код:
    Код:
    class LostZombiesMut extends Mutator config(LostZombiesMut);
    
    
    
    var config int CfgSecondsToWait;
    
    var config int CfgSecondsToMutateKillEnabled;
    
    var config int CfgNumberOfTries;
    
    var config float CfgDistanceCoiff;
    
    var config int CfgRegime;
    
    var config array<string> CfgVipList;
    
    var config array<string> CfgMapList;
    
    var config bool CfgWorksOnBossWave;
    
    var config int CfgTimerInterval;
    
    var config bool CfgInstantActionEnabled;
    
    var config bool CfgTimedActionEnabled;
    
    
    
    var int lastMonsterKilledTime;
    
    var int monsterCount;
    
    var array<Monster> LostZombieList;
    
    var LZGameRules RulesMod;
    
    var float LastActionTime;
    
    
    
    function PostBeginPlay()
    
    {
    
    SaveConfig();
    
    if( RulesMod==None )
    
    RulesMod = Spawn(Class'LZGameRules');
    
    if(KFGameType(Level.Game)==None) Destroyed();
    
    Super.PostBeginPlay();
    
    }
    
    
    
    function MatchStarting()
    
    {
    
    RulesMod.LastMosterKillTime=Level.TimeSeconds;
    
    SetTimer(CfgTimerInterval, true);
    
    }
    
    
    
    function Mutate(string MutateString, PlayerController Sender)
    
    {
    
    local string Command;
    
    local string Parametr;
    
    local array<string> parts;
    
    local Monster M;
    
    if (
    
    !Sender.PlayerReplicationInfo.bAdmin &&
    
    !InVipList(Sender) &&
    
    Level.TimeSeconds-RulesMod.LastMosterKillTime<CfgSecondsToMutateKillEnabled
    
    )
    
    return;
    
    Split( MutateString, " ", parts );
    
    Command=parts[0];
    
    Parametr=parts[1];
    
    if(Command~="KillZeds")
    
    {
    
    foreach DynamicActors(class'Monster',M)
    
    {
    
    if(!CfgWorksOnBossWave && KFGameType(Level.Game).bWaveBossInProgress) continue;
    
    AnnihilateZombie(M);
    
    }
    
    }
    
    if ( NextMutator != None )
    
    NextMutator.Mutate(MutateString, Sender);
    
    }
    
    
    
    
    
    function Timer()
    
    {
    
    if(InMapList())
    
    return;
    
    if(!CfgWorksOnBossWave && KFGameType(Level.Game).bWaveBossInProgress)
    
    return;
    
    if(!KFGameType(Level.Game).bWaveInProgress)
    
    return;
    
    
    
    LastActionTime=Max(LastActionTime,RulesMod.LastMosterKillTime);
    
    if (
    
    Level.TimeSeconds-LastActionTime>CfgSecondsToWait &&
    
    CfgTimedActionEnabled
    
    )
    
    {
    
    FillLateZombiesArray();
    
    ManageLostZombies();
    
    LastActionTime=Level.TimeSeconds;
    
    }
    
    
    
    if(!CfgInstantActionEnabled) return;
    
    FillLostZombiesArray();
    
    if(LostZombieList.Length>0)
    
    ManageLostZombies();
    
    }
    
    
    
    function FillLostZombiesArray()
    
    {
    
    local Monster M;
    
    if(LostZombieList.Length>0) LostZombieList.Length=0;
    
    foreach DynamicActors(class'Monster',M)
    
    if(!HasPathToAnyPlayer(M))
    
    LostZombieList[LostZombieList.Length]=M;
    
    }
    
    
    
    function FillLateZombiesArray()
    
    {
    
    local Monster M;
    
    if(LostZombieList.Length>0) LostZombieList.Length=0;
    
    foreach DynamicActors(class'Monster',M)
    
    LostZombieList[LostZombieList.Length]=M;
    
    }
    
    
    
    function bool HasPathToAnyPlayer(Monster M)
    
    {
    
    local KFHumanPawn P;
    
    foreach DynamicActors(class'KFHumanPawn',P)
    
    if(M.Controller.FindPathToward(P)==None) return false;
    
    return true;
    
    }
    
    
    
    function ManageLostZombies()
    
    {
    
    local Vector teleportLocation;
    
    local bool sentenceIsExecuted;
    
    local int numberOfTries;
    
    while( LostZombieList.Length>0 )
    
    {
    
    if(CfgRegime==0)
    
    {
    
    teleportLocation=GetRandomSpawnLocation(numberOfTries);
    
    sentenceIsExecuted=Teleport(LostZombieList[0],teleportLocation);
    
    }
    
    else if(CfgRegime==1)
    
    {
    
    teleportLocation=GetRandomPlayerLocation(LostZombieList[0],numberOfTries);
    
    sentenceIsExecuted=Teleport(LostZombieList[0],teleportLocation);
    
    }
    
    else
    
    {
    
    AnnihilateZombie(LostZombieList[0]);
    
    sentenceIsExecuted=true;
    
    }
    
    if(!sentenceIsExecuted && numberOfTries>CfgNumberOfTries)
    
    {
    
    AnnihilateZombie(LostZombieList[0]);
    
    sentenceIsExecuted=true;
    
    }
    
    numberOfTries++;
    
    if(sentenceIsExecuted)
    
    {
    
    numberOfTries=0;
    
    sentenceIsExecuted=false;
    
    LostZombieList.Remove(0,1);
    
    }
    
    }
    
    }
    
    
    
    function Vector GetRandomPlayerLocation(Monster M, int counter)
    
    {
    
    local array<KFHumanPawn> pList;
    
    local KFHumanPawn P;
    
    local Vector randV;
    
    local Vector rLocation;
    
    local KFHumanPawn randP;
    
    foreach DynamicActors(class'KFHumanPawn',P)
    
    pList[pList.Length]=P;
    
    randP=pList[Rand(pList.Length)];
    
    if(randP==None) return rLocation;
    
    randV=VRand();
    
    if(randV.X>0) randV.X+=1;
    
    else randV.X-=1;
    
    if(randV.Y>0) randV.Y+=1;
    
    else randV.Y-=1;
    
    randV.Z=0;
    
    rLocation=randP.Location+
    
    randV*(M.CollisionRadius+randP.CollisionRadius)*2*CfgDistanceCoiff+
    
    randV*100*(counter%10);
    
    return rLocation;
    
    }
    
    
    
    function Vector GetRandomSpawnLocation(int counter)
    
    {
    
    local Vector randV;
    
    local Vector rLocation;
    
    local ZombieVolume randZV;
    
    local int volumeListLength;
    
    volumeListLength=KFGameType(Level.Game).ZedSpawnList.Length;
    
    randZV=KFGameType(Level.Game).ZedSpawnList[Rand(volumeListLength)];
    
    if(randZV==None) return rLocation;
    
    randV=VRand();
    
    if(randV.X>0) randV.X+=1;
    
    else randV.X-=1;
    
    if(randV.Y>0) randV.Y+=1;
    
    else randV.Y-=1;
    
    randV.Z=0;
    
    rLocation=randZV.Location+200*randV+100*(counter%10)*randV;
    
    return rLocation;
    
    }
    
    
    
    function AnnihilateZombie(Monster M)
    
    {
    
    if(M!=None)
    
    {
    
    M.Destroyed();
    
    M.Destroy();
    
    }
    
    }
    
    
    
    function bool Teleport(Monster M, vector newSpawnLoc)
    
    {
    
    if (M.SetLocation(newSpawnLoc))
    
    {
    
    M.SetPhysics(PHYS_Walking);
    
    if (M.Controller.PointReachable(newSpawnLoc))
    
    {
    
    M.Velocity = vect(0, 0, 0);
    
    M.Acceleration = vect(0, 0, 0);
    
    M.SetRotation(rotator(newSpawnLoc - M.Location));
    
    M.Controller.GotoState('');
    
    MonsterController(M.Controller).WhatToDoNext(0);
    
    }
    
    }
    
    if(VSizeSq(M.Location-newSpawnLoc)<100)
    
    {
    
    return true;
    
    }
    
    return false;
    
    }
    
    
    
    static final function float VSizeSq(vector A)
    
    {
    
    return Sqrt( Square(A.X) + Square(A.Y) + Square(A.Z) );
    
    }
    
    
    
    function bool InVipList(Controller C)
    
    {
    
    local string hash;
    
    local int i;
    
    hash=PlayerController(C).GetPlayerIDHash();
    
    for(i=0;i<CfgVipList.Length;i++)
    
    if(hash~=CfgVipList[i]) return true;
    
    return false;
    
    }
    
    
    
    function bool InMapList()
    
    {
    
    local string currentMap;
    
    local int i;
    
    currentMap=GetShortUrl(Level.GetLocalURL());;
    
    for(i=0;i<CfgMapList.Length;i++)
    
    if(currentMap~=CfgMapList[i]) return true;
    
    return false;
    
    }
    
    
    
    static function string GetShortUrl(string s)
    
    {
    
    local int qPos, slashPos, startPos;
    
    local string result;
    
    qPos=InStr(s,"?");
    
    slashPos=InStr(s,"/");
    
    startPos=Max(slashPos, 0);
    
    result=Mid(s, startPos+1, qPos-startPos-1);
    
    return result;
    
    }
    
    
    
    defaultproperties
    
    {
    
    CfgSecondsToWait=25
    
    CfgSecondsToMutateKillEnabled=55
    
    CfgNumberOfTries=10
    
    CfgDistanceCoiff=4
    
    CfgRegime=1
    
    CfgWorksOnBossWave=false
    
    CfgTimerInterval=15
    
    CfgInstantActionEnabled=true
    
    CfgTimedActionEnabled=true
    
    CfgVipList(0)=111111111
    
    CfgVipList(1)=222222222
    
    CfgMapList(0)=KF-TheHiveV1
    
    bAddToServerPackages=True
    
    GroupName="LostZombiesMut"
    
    FriendlyName="LostZombiesMut"
    
    Description="LostZombiesMut"
    
    }
    
    
    Код:
    class LZGameRules extends GameRules;
    
    
    
    var float LastMosterKillTime;
    
    
    
    function PostBeginPlay()
    
    {
    
    if( Level.Game.GameRulesModifiers==None )
    
    Level.Game.GameRulesModifiers = Self;
    
    else Level.Game.GameRulesModifiers.AddGameRules(Self);
    
    }
    
    
    
    function AddGameRules(GameRules GR)
    
    {
    
    if ( GR!=Self )
    
    Super.AddGameRules(GR);
    
    }
    
    //Запоминаем время последнего убийства
    
    function ScoreKill (Controller killer , Controller killed)
    
    {
    
    if(killer!=None && killer.IsA('PlayerController'))
    
    LastMosterKillTime=Level.TimeSeconds;
    
    if (nextGameRules != none)
    
    nextGameRules.scoreKill (killer , killed);
    
    }
    
    
    
    defaultproperties
    
    {
    
    }
    
    
     
    shibata, MaThreeX, Morkleb и 9 другим нравится это.
  2. denfil777

    denfil777 Капо

    Нужная вещь :thumbsup: +
     
  3. Фрэгл

    Фрэгл Administrator

    Ммм,вещь безусловно нужная,но как выставить правильное значение времени(если допустим на карте просто пути длинные у мобов,карта большая например)...
     
  4. Flame

    Flame -Заслуженый кодер форума-

    ну фиг знает )
    можно проверять видят ли монстры игроков, видят ли игроки монстров, расстояние до игроков, можно для каждой карты сделать своё время, можно поставить 5 минут (если уж за 5 минут ни один зомбик не помер, то совсем беда) и т.д
    я простейший вариантик привёл
    у меня раньше была версия, где через 60 секунд монстры телепортировались к самому сильному игроку )
    особенно подстава была у тех кто где-то заварился и не убивает никого, а просто качает сварку )
     
    Dave_Scream, Папка01 и ЛОХМАТЫЙ нравится это.
  5. Lexass

    Lexass Капо

    60 сек. но мобы респуются Хрен знает где. а можно как нибудь поставить так ято бы он респал их в 10-20 метрах от игрока?
     
  6. Flame

    Flame -Заслуженый кодер форума-

    Мобы респаются не хрен знает где, а на своих стандартных респах ) И это решает проблему телепортации их в стену или в пропасть...
    Можно и около игроков, но ты достаточно уже разбираешься в коде чтобы это поправить
    1. Пойми около какого игрока ты хочешь, чтобы они появлялись
    2. Перепиши GetSpawnLocation - пусть возвращает не координаты ZombieVolume, а Pawn.Location, где Pawn эт тушка игрока )
    3. Ну и добавь эти 20 метров (на самом деле самое неприятное, т.к. надо проверять нет ли там стен в точке телепортации и т.д ) )

    Если не получится, то накидаю свою версию на неделе
     
    ЛОХМАТЫЙ нравится это.
  7. Lexass

    Lexass Капо

    можешь свою выложить. а то у меня ошибок под 8 стал выпрашивать.
     
  8. Flame

    Flame -Заслуженый кодер форума-

    Обновил версию мутатора
    Ну точнее переписал его полностью и расширил возможности )
    См. шапку темы
     
    Папка01 и ЛОХМАТЫЙ нравится это.
  9. MaThreeX

    MaThreeX Солдат

    забераю с руками и ногами, вообще хорошо бы просто сделать:
    Если остается 10 мобов или меньше, и их не убивают в течение 1 минуты, они умирают =) и не надо никаких команд и телепортов(хотя если только люди используют шиверов тогда еще мб и нужен тп)
     
  10. Flame

    Flame -Заслуженый кодер форума-

    Какой ты неприхотливый )
    Но я этот мутатор переделал потому что увидел потребность в этом на одном из форумов
    Куда я попал, кстати, по твоей милости ))

    Ну вот тебе тот же самый мутатор, только с вырезанным всем остальным ))
    Код GameRules тот же
    Код мутатора:
    Код:
    class LostZombiesKillMut extends Mutator config(LostZombiesKillMut);
    
    var config int CfgSecondsToWait;
    var config int CfgMonstersLeft;
    
    var bool WaveStartedOnPrevTick;
    var array<Monster> LostZombieList;
    var LZGameRules RulesMod;
    
    function PostBeginPlay()
    {
    	SaveConfig();
    	if( RulesMod==None )
    		RulesMod = Spawn(Class'LZGameRules');
    	if(KFGameType(Level.Game)==None) Destroyed();
    	Super.PostBeginPlay();
    }
    
    function MatchStarting()
    {
    	RulesMod.LastMosterKillTime=Level.TimeSeconds;
    	SetTimer(5, true);
    }
    
    function Timer()
    {
    	if(!KFGameType(Level.Game).bWaveInProgress)
    	{
    		WaveStartedOnPrevTick=false;
    		return;
    	}
    	if(!WaveStartedOnPrevTick && KFGameType(Level.Game).bWaveInProgress)
    	{
    		WaveStartedOnPrevTick=true;
    		RulesMod.LastMosterKillTime=Level.TimeSeconds;
    	}
    	
    	if	(
    			Level.TimeSeconds-RulesMod.LastMosterKillTime<CfgSecondsToWait ||
    			KFGameReplicationInfo(Level.Game.GameReplicationInfo).MaxMonsters>CfgMonstersLeft
    		)
    	return;
    
    	FillLateZombiesArray();
    	ManageLostZombies();
    }
    
    function FillLateZombiesArray()
    {
    	local Monster M;
    	if(LostZombieList.Length>0) LostZombieList.Length=0;
    	foreach DynamicActors(class'Monster',M)
    		LostZombieList[LostZombieList.Length]=M;
    }
    
    function ManageLostZombies()
    {
    	while( LostZombieList.Length>0 )
    	{
    		AnnihilateZombie(LostZombieList[0]);
    		LostZombieList.Remove(0,1);
    	}
    }
    
    function AnnihilateZombie(Monster M)
    {
    	if(M!=None)
    	{
    		M.Destroyed();
    		M.Destroy();
    	}
    }
    
    defaultproperties
    {
    	CfgSecondsToWait=60
    	CfgMonstersLeft=10
    	bAddToServerPackages=True
    	GroupName="LostZombiesKillMut"
    	FriendlyName="LostZombiesKillMut"
    	Description="LostZombiesKillMut"
    }
    
    Ссылка
    Добавлять в виде LostZombiesKillMut.LostZombiesKillMut
    Убивает зомбиков если их осталось меньше CfgMonstersLeft и они не умирали от рук игроков в течении CfgSecondsToWait секунд

    upd. Только я его почти что не тестил ) Так что пишите косяки...
     
    Папка01, ЛОХМАТЫЙ и MaThreeX нравится это.
  11. MaThreeX

    MaThreeX Солдат

    о_О плюсую =)
     
  12. Lexass

    Lexass Капо

    Извини но ты не написал как в командной строчке писать что бы убить Мобов.
     
  13. Flame

    Flame -Заслуженый кодер форума-

    Ивини, но написал )
    Ищи внимательнее

    впрочем проще повторить ))
    mutate killzeds
     
  14. MaThreeX

    MaThreeX Солдат

    упс та версия что ты мне дал убивает и патриархов ыыыыыыыыыыыыыы
     
  15. Flame

    Flame -Заслуженый кодер форума-

    Конечно убивает )
    Ты сам сказал что тебе надо - я и сделал
    Про патриарха ты ничего не говорил ))
     
    Папка01, MaThreeX, shibata и ещё 1-му нравится это.
  16. MaThreeX

    MaThreeX Солдат

    ыыыыыы
    ну как же без Пети то? ы
     
  17. Atlan

    Atlan Капо

    Флейм юморист. :teehee:
     
    MaThreeX и shibata нравится это.
  18. MaThreeX

    MaThreeX Солдат

    ага ыы, дак я не понял мне самому дописать или ты сам ? ыыыы
     
  19. Flame

    Flame -Заслуженый кодер форума-

    вот ты ленивый )
    1 минута поправить
    ну жди тогда пока я найду эту 1 минуту )
     
  20. MaThreeX

    MaThreeX Солдат

    я терпеливый ыыыыыыыы