Let Spawnkiller Explode

Discussions about Coding and Scripting
User avatar
Baardman
Adept
Posts: 300
Joined: Mon Oct 02, 2017 9:39 am

Let Spawnkiller Explode

Post by Baardman »

Is it hard to script a mutator that gives a spawnkiller a warning after 5 or 10 ( adjustable amount) spawnkills and then after another amount of spawnkills ( adjustable ) kills the spawnkiller with the "explode into gibs style"

Ive seen the message on a server saying " .... is a spawnkilling lamer"
It would think its a cool idea to have a mutator that also uses that message but kills the spawnkiller after a certain amount of spawnkills. And have the gibs everywhere. Also i could expand on it with different variety's for instance give spawnkiller bright flashing color overlay for a certain amount of time, make him like the fatboy mutator, mske him frozen like freeze-tag or just kick him of server.

I have no idea where to start, i know how to set up my folders and use uccmake but that about it.

Wich script should i start with?
User avatar
TigerTheGreat
Adept
Posts: 376
Joined: Thu Mar 25, 2010 6:00 pm
Personal rank: UMS R&D CEO

Re: Let Spawnkiller Explode

Post by TigerTheGreat »

A much more simpler solution would be to give players on spawning a temporary shieldbelt. Unlike other armors, shieldbelts eat all damage first before health starts dropping, so a 99999-value shieldbelt that disappears after a few seconds would get the job done.

As for telefragging, some coop servers on Newbies have, as I have observed, a mechanic which allows players to spawn beside the existing spawnpoints if area is taken. At least that's what I ASSUME is happening since I've never been telefragged or haven't telefragged anyone in coop sessions there. Translating this mechanic to UT gametypes should get the job done, and even prevent translocator telefragging if we'd so desire.
Image
I am the Unreal archivist and historian. If you have something from the past of Unreal that I don't have, do tell.
~formerly Delacroix
User avatar
Baardman
Adept
Posts: 300
Joined: Mon Oct 02, 2017 9:39 am

Re: Let Spawnkiller Explode

Post by Baardman »

TigerTheGreat wrote: Sat Apr 26, 2025 2:08 pm A much more simpler solution would be to give players on spawning a temporary shieldbelt. Unlike other armors, shieldbelts eat all damage first before health starts dropping, so a 99999-value shieldbelt that disappears after a few seconds would get the job done.

As for telefragging, some coop servers on Newbies have, as I have observed, a mechanic which allows players to spawn beside the existing spawnpoints if area is taken. At least that's what I ASSUME is happening since I've never been telefragged or haven't telefragged anyone in coop sessions there. Translating this mechanic to UT gametypes should get the job done, and even prevent translocator telefragging if we'd so desire.
thats not funny enough.

i tried with chatgpt today but its useless. giving me wrong code everytime. programmers looking at this probably laughing their ass of how crappy it is.

example

Code: Select all

class SpawnKillPunisher extends Mutator;

var config int MaxSpawnKills;
var config float SpawnKillTime;

struct SpawnKillTracker
{
    var Pawn P;
    var float LastSpawnTime;
    var int SpawnKillCount;
};

var array<SpawnKillTracker> Trackers;

function PostBeginPlay()
{
    Super.PostBeginPlay();

    MaxSpawnKills = 3;
    SpawnKillTime = 5.0;

    // Show message that Mutator is active
    local PlayerPawn P;

foreach AllActors(class'PlayerPawn', P)
{
    P.ClientMessage("[SpawnKillPunisher] Mutator Loaded!");
}

}

function ModifyPlayer(Pawn Other)
{
    local int i;

    Super.ModifyPlayer(Other);

    if (Other == None)
        return;

    // Check if already tracked
    for (i = 0; i < Trackers.Length; i++)
    {
        if (Trackers[i].P == Other)
            return;
    }

    // Add new tracker
    Trackers.Length = Trackers.Length + 1;
    Trackers[Trackers.Length-1].P = Other;
    Trackers[Trackers.Length-1].LastSpawnTime = Level.TimeSeconds;
    Trackers[Trackers.Length-1].SpawnKillCount = 0;

    if (Other.IsA('PlayerPawn'))
        PlayerPawn(Other).ClientMessage("[SpawnKillPunisher] You are now being tracked!");
}

function ScoreKill(Pawn Killer, Pawn Other)
{
    local int i;
    local float TimeSinceSpawn;

    Super.ScoreKill(Killer, Other);

    if (Killer == None || Other == None)
        return;

    for (i = 0; i < Trackers.Length; i++)
    {
        if (Trackers[i].P == Other)
        {
            TimeSinceSpawn = Level.TimeSeconds - Trackers[i].LastSpawnTime;

            if (TimeSinceSpawn <= SpawnKillTime)
            {
                // Find killer tracker
                for (i = 0; i < Trackers.Length; i++)
                {
                    if (Trackers[i].P == Killer)
                    {
                        Trackers[i].SpawnKillCount++;

                        if (Killer.IsA('PlayerPawn'))
                        {
                            PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] Spawnkill detected! ("$Trackers[i].SpawnKillCount$"/"$MaxSpawnKills$")");
                        }

                        if (Trackers[i].SpawnKillCount >= MaxSpawnKills)
                        {
                            if (Killer.IsA('PlayerPawn'))
                                PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] You have been punished for spawnkilling!");

                            Killer.TakeDamage(9999, Killer, Killer.Location, vect(0,0,0), 'FlakShell');
                            Trackers[i].SpawnKillCount = 0;
                        }
                        break;
                    }
                }
            }
            break;
        }
    }

    // Update victim's spawn time
    for (i = 0; i < Trackers.Length; i++)
    {
        if (Trackers[i].P == Other)
        {
            Trackers[i].LastSpawnTime = Level.TimeSeconds;
            break;
        }
    }
}

defaultproperties
{
}


i tried starting a match with lots of bots in a modified map where spawnpoints are close together and after starting the match i used "loaded" and "fly" to hover over the enemy base and shoot rockets but none of the 20 different version from chatgpt worked, atleast i geuss its just disfunctional code, i remove the old .u file everytime before recompiling, not sure what else i can do wrong to not make it work.


-
-
User avatar
Barbie
Godlike
Posts: 3093
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Let Spawnkiller Explode

Post by Barbie »

The code is close to what my idea was: You have to track spawned players for a while - maybe some seconds - and if they are killed within this interval (and eventually within a certain range around the spawn point), it is counted as a spawn kill. Then you can do what you want with the killer: ban, freeze, decrease health, kill, …

But the code looks like for a newer version of unreal; UT has no dynamic arrays nor things like Trackers.Length.   
Auto merged new post submitted 28 minutes later
I rewrote the code for UT. Untested, but at least it compiles.
Todo: add a cleanup for outdated SpawnKillTracker

Code: Select all

class SpawnKillTracker expands Info;

var Pawn P;
var float LastSpawnTime;
var int SpawnKillCount;

Code: Select all

class SpawnKillPunisher expands Mutator;

var config int MaxSpawnKills;
var config float SpawnKillTime;


function bool FindTrackerFor(Pawn P, out SpawnKillTracker SKT) {

	foreach AllActors(class'SpawnKillTracker', SKT, P.Name)
		break;
	return SKT != None;
}



function ModifyPlayer(Pawn Other) {
local SpawnKillTracker Tracker;

	Super.ModifyPlayer(Other);

	if (Other == None) return;

    // Check if already tracked
    if (FindTrackerFor(Other, Tracker)) return;

    // Add new tracker
    Tracker = Spawn(class'SpawnKillTracker');
    if (Tracker != None)
    {
	    Tracker.Tag = Other.Name;
	    Tracker.P = Other;
	    Tracker.LastSpawnTime = Level.TimeSeconds;
	    Tracker.SpawnKillCount = 0;
    }
    else
    	warn("Could not spawn a SpawnKillTracker");

    if (Other.IsA('PlayerPawn'))
        PlayerPawn(Other).ClientMessage("[SpawnKillPunisher] You are now being tracked!");
}


function ScoreKill(Pawn Killer, Pawn Other) {
local float TimeSinceSpawn;
local SpawnKillTracker AVictim, Akiller;

	Super.ScoreKill(Killer, Other);

	if (Killer == None || Other == None) return;

	if (FindTrackerFor(Other, AVictim))
	{
		TimeSinceSpawn = Level.TimeSeconds - AVictim.LastSpawnTime;
		if (TimeSinceSpawn <= SpawnKillTime)
		{
        	// Find killer's tracker
			if (FindTrackerFor(Other, AKiller))
			{
				AKiller.SpawnKillCount++;
				if (Killer.IsA('PlayerPawn')) PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] Spawnkill detected! (" $ AKiller.SpawnKillCount $ "/" $ MaxSpawnKills$")");
				if (AKiller.SpawnKillCount >= MaxSpawnKills)
				{
					if (Killer.IsA('PlayerPawn')) PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] You have been punished for spawnkilling!");
					// do punishment here:
					Killer.TakeDamage(9999, Killer, Killer.Location, vect(0,0,0), 'FlakShell');
					// reset killer's AKiller:
					AKiller.SpawnKillCount = 0;
				}
			}
		}
	}

    // Update victim's spawn time
	AVictim.LastSpawnTime = Level.TimeSeconds;
}


defaultproperties {
	MaxSpawnKills=3
	SpawnKillTime=5.0
}
"If Origin not in center it be not in center." --Buggie
User avatar
Baardman
Adept
Posts: 300
Joined: Mon Oct 02, 2017 9:39 am

Re: Let Spawnkiller Explode

Post by Baardman »

Barbie wrote: Sun Apr 27, 2025 1:14 am The code is close to what my idea was: You have to track spawned players for a while - maybe some seconds - and if they are killed within this interval (and eventually within a certain range around the spawn point), it is counted as a spawn kill. Then you can do what you want with the killer: ban, freeze, decrease health, kill, …

But the code looks like for a newer version of unreal; UT has no dynamic arrays nor things like Trackers.Length.   
Auto merged new post submitted 28 minutes later
I rewrote the code for UT. Untested, but at least it compiles.
Todo: add a cleanup for outdated SpawnKillTracker

Code: Select all

class SpawnKillTracker expands Info;

var Pawn P;
var float LastSpawnTime;
var int SpawnKillCount;

Code: Select all

class SpawnKillPunisher expands Mutator;

var config int MaxSpawnKills;
var config float SpawnKillTime;


function bool FindTrackerFor(Pawn P, out SpawnKillTracker SKT) {

	foreach AllActors(class'SpawnKillTracker', SKT, P.Name)
		break;
	return SKT != None;
}



function ModifyPlayer(Pawn Other) {
local SpawnKillTracker Tracker;

	Super.ModifyPlayer(Other);

	if (Other == None) return;

    // Check if already tracked
    if (FindTrackerFor(Other, Tracker)) return;

    // Add new tracker
    Tracker = Spawn(class'SpawnKillTracker');
    if (Tracker != None)
    {
	    Tracker.Tag = Other.Name;
	    Tracker.P = Other;
	    Tracker.LastSpawnTime = Level.TimeSeconds;
	    Tracker.SpawnKillCount = 0;
    }
    else
    	warn("Could not spawn a SpawnKillTracker");

    if (Other.IsA('PlayerPawn'))
        PlayerPawn(Other).ClientMessage("[SpawnKillPunisher] You are now being tracked!");
}


function ScoreKill(Pawn Killer, Pawn Other) {
local float TimeSinceSpawn;
local SpawnKillTracker AVictim, Akiller;

	Super.ScoreKill(Killer, Other);

	if (Killer == None || Other == None) return;

	if (FindTrackerFor(Other, AVictim))
	{
		TimeSinceSpawn = Level.TimeSeconds - AVictim.LastSpawnTime;
		if (TimeSinceSpawn <= SpawnKillTime)
		{
        	// Find killer's tracker
			if (FindTrackerFor(Other, AKiller))
			{
				AKiller.SpawnKillCount++;
				if (Killer.IsA('PlayerPawn')) PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] Spawnkill detected! (" $ AKiller.SpawnKillCount $ "/" $ MaxSpawnKills$")");
				if (AKiller.SpawnKillCount >= MaxSpawnKills)
				{
					if (Killer.IsA('PlayerPawn')) PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] You have been punished for spawnkilling!");
					// do punishment here:
					Killer.TakeDamage(9999, Killer, Killer.Location, vect(0,0,0), 'FlakShell');
					// reset killer's AKiller:
					AKiller.SpawnKillCount = 0;
				}
			}
		}
	}

    // Update victim's spawn time
	AVictim.LastSpawnTime = Level.TimeSeconds;
}


defaultproperties {
	MaxSpawnKills=3
	SpawnKillTime=5.0
}

Thank you, its not really working yet. i had a alot of trial and error this morning with using Chatgpt ( each time it says; here is the real working version and i fails again :) but im getting close i think, it gives messages saying that im being tracked and each time im spawnkilling i get message 1/3 , 2/3 , /3/3. but i'm not being killed yet at the last 3/3 kill ( increased time to 20 for testing purpose )

Also because i had some problem when compiling and told me no file could be found and now i have duplicate source files in seperate folders but it does not seem to care.


This is what i have now; spawnkillmanager is in its own folder but also in spawnkillpunisher folder, spawnkillpunisher is in its own folder only ( no duplicate) together with the spawnkillpunisher.int and the spawnkillmanger.uc for now because im to afraid to delete one it right now while its working like its now at the moment. under editpackages i have both spawnkillmanager and spawnkillpunisher.

so i just needed to share my tiny progress this morning before going on family visit.


Code: Select all

  // SpawnKillManager.uc
class SpawnKillManager expands Actor;

var config int MaxSpawnKills;       // How many spawnkills allowed before punishment
var config float SpawnKillTime;     // Time window to detect spawnkill (seconds)

struct TrackerData
{
    var Pawn P;                    // The player
    var float LastSpawnTime;        // When they spawned
    var int SpawnKillCount;         // How many spawnkills
};

var TrackerData Trackers[32];        // Static array (no dynamic arrays in UT99)
var int TrackerCount;

event PostBeginPlay()
{
    SetTimer(1.0, true);
}

function Timer()
{
    local Pawn P;
    local int i;
    
    // Look for new players to track
    foreach AllActors(class'Pawn', P)
    {
        if (!IsTracked(P))
        {
            AddTracker(P);
            if (P.IsA('PlayerPawn'))
                PlayerPawn(P).ClientMessage("[SpawnKillPunisher] You are now being tracked!");
        }
    }

    // Cleanup: Remove dead players
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == None || Trackers[i].P.bDeleteMe || Trackers[i].P.Health <= 0)
        {
            RemoveTracker(i);
            i--; // Shifted, recheck this index
        }
    }
}

function bool IsTracked(Pawn P)
{
    local int i;
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == P)
            return true;
    }
    return false;
}

function AddTracker(Pawn P)
{
    if (TrackerCount >= 32)
        return;
    Trackers[TrackerCount].P = P;
    Trackers[TrackerCount].LastSpawnTime = Level.TimeSeconds;
    Trackers[TrackerCount].SpawnKillCount = 0;
    TrackerCount++;
}

function RemoveTracker(int index)
{
    local int i;
    for (i = index; i < TrackerCount-1; i++)
        Trackers[i] = Trackers[i+1];
    TrackerCount--;
}

function NotifyKilled(Pawn Killer, Pawn Victim)
{
    local int i;
    local float TimeSinceSpawn;

    if (Killer == None || Victim == None)
        return;

    // Find Victim tracker
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == Victim)
        {
            TimeSinceSpawn = Level.TimeSeconds - Trackers[i].LastSpawnTime;
            if (TimeSinceSpawn <= SpawnKillTime)
            {
                Punish(Killer);
            }
            break;
        }
    }
}

function Punish(Pawn Killer)
{
    local int i;

    // Find Killer tracker
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == Killer)
        {
            Trackers[i].SpawnKillCount++;
            if (Killer.IsA('PlayerPawn'))
                PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] Spawnkill detected! (" $ Trackers[i].SpawnKillCount $ "/" $ MaxSpawnKills $ ")");
            
            if (Trackers[i].SpawnKillCount >= MaxSpawnKills)
            {
                if (Killer.IsA('PlayerPawn'))
                    PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] You have been punished for spawnkilling!");
                Killer.TakeDamage(9999, Killer, Killer.Location, vect(0,0,0), 'SpawnKillPunish');
                Trackers[i].SpawnKillCount = 0;
            }
            break;
        }
    }
}

defaultproperties
{
    MaxSpawnKills=3
    SpawnKillTime=20.0
}


Code: Select all

// SpawnKillPunisher.uc
class SpawnKillPunisher expands Mutator;

var SpawnKillManager Manager;

function PostBeginPlay()
{
    Super.PostBeginPlay();
    Manager = Spawn(class'SpawnKillManager');
}

function ScoreKill(Pawn Killer, Pawn Other)
{
    Super.ScoreKill(Killer, Other);

    if (Manager != None)
        Manager.NotifyKilled(Killer, Other);
}

defaultproperties
{
}

User avatar
Barbie
Godlike
Posts: 3093
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Let Spawnkiller Explode

Post by Barbie »

Anything of interest in the log file?
"If Origin not in center it be not in center." --Buggie
User avatar
Baardman
Adept
Posts: 300
Joined: Mon Oct 02, 2017 9:39 am

Re: Let Spawnkiller Explode

Post by Baardman »

Barbie wrote: Sun Apr 27, 2025 10:28 am Anything of interest in the log file?
No nothing, i think this version is now functioning with help of Chatgpt , changed spawnkillmanager into this

Code: Select all


// SpawnKillManager.uc
class SpawnKillManager expands Actor;

var config int MaxSpawnKills;       // How many spawnkills allowed before punishment
var config float SpawnKillTime;     // Time window to detect spawnkill (seconds)

struct TrackerData
{
    var Pawn P;                    // The player
    var float LastSpawnTime;        // When they spawned
    var int SpawnKillCount;         // How many spawnkills
};

var TrackerData Trackers[32];        // Static array (no dynamic arrays in UT99)
var int TrackerCount;

event PostBeginPlay()
{
    SetTimer(1.0, true);
}

function Timer()
{
    local Pawn P;
    local int i;
    
    // Look for new players to track
    foreach AllActors(class'Pawn', P)
    {
        if (!IsTracked(P))
        {
            AddTracker(P);
            if (P.IsA('PlayerPawn'))
                PlayerPawn(P).ClientMessage("[SpawnKillPunisher] You are now being tracked!");
        }
    }

    // Cleanup: Remove dead players
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == None || Trackers[i].P.bDeleteMe || Trackers[i].P.Health <= 0)
        {
            RemoveTracker(i);
            i--; // Shifted, recheck this index
        }
    }
}

function bool IsTracked(Pawn P)
{
    local int i;
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == P)
            return true;
    }
    return false;
}

function AddTracker(Pawn P)
{
    if (TrackerCount >= 32)
        return;
    Trackers[TrackerCount].P = P;
    Trackers[TrackerCount].LastSpawnTime = Level.TimeSeconds;
    Trackers[TrackerCount].SpawnKillCount = 0;
    TrackerCount++;
}

function RemoveTracker(int index)
{
    local int i;
    for (i = index; i < TrackerCount-1; i++)
        Trackers[i] = Trackers[i+1];
    TrackerCount--;
}

function NotifyKilled(Pawn Killer, Pawn Victim)
{
    local int i;
    local float TimeSinceSpawn;

    if (Killer == None || Victim == None)
        return;

    // Find Victim tracker
    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == Victim)
        {
            TimeSinceSpawn = Level.TimeSeconds - Trackers[i].LastSpawnTime;
            if (TimeSinceSpawn <= SpawnKillTime)
            {
                Punish(Killer);
            }
            break;
        }
    }
}


function Punish(Pawn Killer)
{
    local int i;

    if (Killer == None || Killer.bDeleteMe || Killer.Health <= 0)
        return; // Already dead or being destroyed, skip punishment!

    for (i = 0; i < TrackerCount; i++)
    {
        if (Trackers[i].P == Killer)
        {
            Trackers[i].SpawnKillCount++;
            if (Killer.IsA('PlayerPawn'))
                PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] Spawnkill detected! (" $ Trackers[i].SpawnKillCount $ "/" $ MaxSpawnKills $ ")");
            
            if (Trackers[i].SpawnKillCount >= MaxSpawnKills)
            {
                if (Killer.IsA('PlayerPawn'))
                    PlayerPawn(Killer).ClientMessage("[SpawnKillPunisher] You have been punished for spawnkilling!");

                // Avoid infinite recursion:
                Killer.Health = -10000;
                Killer.Died(None, 'SpawnKillPunish', Killer.Location);

                Trackers[i].SpawnKillCount = 0;
            }
            break;
        }
    }
}


defaultproperties
{
    MaxSpawnKills=3
    SpawnKillTime=20.0
}

so it works, gives warning of being tracked when match begins and when spawnkilling gives message `" spawnkill detected 1/3 - 3/3 " and then "you are being punished" and then kills you ( no fancy stuff yet just death ) only noticed it continuesly gives messages "you are being tracked" right after being killed by the mutator. For testing purpose i set the spawntime way to high ( 20 seconds ) so that should be lowered in a final version or adjustable, also that time is for how long ago a player/bot spawned i think, not for the time in between spawnkills the spawnkiller spawnkilled. not sure what to do with that yet.
consoletgpts.jpg
i hope to get rid of that and build nice version with warnings on screen instead of the console to make violations more visible and maybe add other option like gibs, freeze, bright colors if thats even possible. not sure, any suggestions?

someone wants to test it?
spawnkillpunisher.7z
-
-
You do not have the required permissions to view the files attached to this post.
User avatar
Barbie
Godlike
Posts: 3093
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Let Spawnkiller Explode

Post by Barbie »

Just a hint for better efficiency: Instead of checking the Trackers mostly useless in every timer period (aka "polling"), I'd check them only when needed: on Player join and logoff (aka "event driven").
"If Origin not in center it be not in center." --Buggie