Need help with special weapon spawn

Discussions about UT99
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Need help with special weapon spawn

Post by Hbgr »

I am creating a side room in a map with weapons racks along a wall. I want the racks to.hold one weapon, spawned at the default interval when one is taken. However, i only want one weapon spawned at a time randomly on one of the racks. So imagine 7 empty weapons racks, except one of them has a weapon ready to pick up. When a player or bot takes the weapon, now the racks are all empty for the default time (30 secs, i think?). When its time to respawn, a RANDOM rack is chosen to hold its weapon, while the others are empty. And it continues like this. At any time only one rack, chosen at random, will have a weapon.

Please tell me this can be done without scripting.

Anyone can help?
User avatar
papercoffee
Godlike
Posts: 10433
Joined: Wed Jul 15, 2009 11:36 am
Personal rank: coffee addicted !!!
Location: Cologne, the city with the big cathedral.

Re: Need help with special weapon spawn

Post by papercoffee »

Hbgr wrote: Wed Oct 25, 2023 5:36 pm Please tell me this can be done without scripting.
I don't think so. There are triggers that can be set up to spawn something or prevent it ...but I don't think you can randomize it.
I'm no coder but I have never seen this in vanilla game without a little bit of scripting.
User avatar
ExpEM
Adept
Posts: 298
Joined: Wed Nov 09, 2016 1:48 am

Re: Need help with special weapon spawn

Post by ExpEM »

This is all theoretical:

1: Finalise the map with everything except the special weapon otherwise every time you rebuild Pathing, shit will break.
2: Build a number of 32*32*32 cube movers equal to the number of randomised weapons, hide them somewhere out in the void.
3: Set the second location of the mover 1024uu below its origin.
4: Place all of the weapons in the "spawn" location.
5: Rebuild ALL, this will spawn the markers for each weapon and fix up the movers.
6: Attach each weapon AND it's marker to it's corresponding mover.
7: Set all weapons Events to something unique. (Event will fire when the weapon is picked up iirc)
8: Work out yourself how to link way too many Stochastic Triggers and Dispatchers together to ensure that only one weapon is present at any one time.

I think this will probably still break the Bots navigation unfortunately, something something, thinking they will be able to pick up the Weapons by walking to the Marker even though we moved it.
We can't modify the reach specs of the Marker without coding.

If you don't care about Bots then this will be fine and you wont have to worry about moving the Marker.
Signature goes here.
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Re: Need help with special weapon spawn

Post by Hbgr »

Wow! Way to think outside of the box @expEM! 8)

Scripting it is...(it does need to be SP).

Anyone can help with a script then? Or at least the process? :noidea
User avatar
Barbie
Godlike
Posts: 2770
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Need help with special weapon spawn

Post by Barbie »

Should be a certain rack specific for one weapon or may any weapon respawn at any rack?
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Re: Need help with special weapon spawn

Post by Hbgr »

Either way. But i prefer a random weapon for any rack. :D
User avatar
Barbie
Godlike
Posts: 2770
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Need help with special weapon spawn

Post by Barbie »

Here you are:

Code: Select all

/******************************************************************************
Class RandomWeaponSpawner:
Place up to 8 SpawnPoints with the same Tag as me and fill up to 8 Weapon types
into the *Weapons* array. Then one random chosen weapon is spawned at one
random chosen SpawnPoint. If that weapon is taken, the timeout of given
*SpawnDelay* starts and after it has run out, another random weapon is spawned
at a random SpawnPoint.

The array *Weapons* may contain gaps.


By SeriousBarbie AT Barbies DOT World, 2023-10-27
******************************************************************************/
class RandomWeaponSpawner expands Triggers;

var() bool bDebug;
var() bool bRotationWeapon;
var() class<weapon> Weapons[8];
var byte WeaponsCount;
var() Byte SpawnDelay;
var SpawnPoint SpawnPoints[8];
var byte SpawnPointsCount;
var(Events) name SpawnedEvent;
var WeaponWatcher WeaponWatcher;

function bool CollectSpawnPoints() {
local SpawnPoint SP;
local byte i;

	foreach AllActors(class'SpawnPoint', SP, Tag)
	{
		SpawnPoints[SpawnPointsCount++] = SP;
		if (SpawnPointsCount >= ArrayCount(SpawnPoints))
		{
			warn("only 8 SpawnPoints are supported");
			break;
		}
	}
	if (SpawnPointsCount == 0)
	{
		warn("No SpawnPoints with Tag=" $ Tag @ "found, exiting");
		destroy();
		return false;

	}
	if (bDebug)
	{
		logger(SpawnPointsCount @ "SpawnPoints found:");

		for (i = 0; i < SpawnPointsCount; i++)
			logger("SpawnPoints[" $ i $ "]=" $ SpawnPoints[i]);
	}
	return true;
}



function bool CompactWeaponArray() {
local byte i, j;

	for (i = 0; i < ArrayCount(Weapons); i++)
	{
		if (Weapons[i] == None)
		{
			for (j = i +1; j < ArrayCount(Weapons); j++)
				if (Weapons[j] != None)
				{
					Weapons[i] = Weapons[j];
					Weapons[j] = None;
					WeaponsCount++;
					break;
				}
		}
		else
			WeaponsCount++;
	}
	if ( WeaponsCount == 0)
	{
		warn("No Weapons given, exiting");
		destroy();
		return false;
	}
	if (bDebug)
	{
		logger(WeaponsCount @ "Weapons found:");

		for (i = 0; i < WeaponsCount; i++)
			logger("Weapon[" $ i $ "]=" $ Weapons[i]);
	}
	return true;
}



function Logger(string msg) {

	if (bDebug) log(self $ ":" @ msg);
}



Event PostBeginPlay() {
	Super.PostBeginPlay();
	if ( ! CollectSpawnPoints()) return;
	if ( ! CompactWeaponArray()) return;
	WeaponWatcher = Spawn(class'WeaponWatcher');
}



function RaiseEvent(name EventName, Actor Other, Pawn EventInstigator) {
local Actor A;

	if (EventName != '')
		foreach AllActors(Class'Actor', A, EventName)
			A.Trigger(Other, EventInstigator);
}



function bool SpawnWeapon(byte WeaponIndex, byte SpawnPointIndex) {
local Weapon W;

	W = Spawn(Weapons[WeaponIndex], , , SpawnPoints[SpawnPointIndex].Location, SpawnPoints[SpawnPointIndex].Rotation);
	if (W == None)
	{
		warn("Could not spawn" @ Weapons[WeaponIndex] @ "at" @ SpawnPoints[SpawnPointIndex]);
		return false;
	}
	logger(W @ "spawned at" @ SpawnPoints[SpawnPointIndex]);
	//W.Event = self.Tag;
	W.bRotatingPickup = bRotationWeapon;
	W.RespawnTime = 0;
	WeaponWatcher.WatchedWeapon = W;
	RaiseEvent(SpawnedEvent, W, None);
	WeaponWatcher.SetTimer(1.414, true);
}



auto State ready {

	Event Timer() {
		logger("Timer waked up, spawning weapon now");
		SpawnWeapon(Rand(WeaponsCount), Rand(SpawnPointsCount));
	}


	event Trigger(Actor Other, Pawn EventInstigator) {
		logger("tiggered, Other=" $ Other $ ", EventInstigator=" $ EventInstigator);
		SetTimer(SpawnDelay, false);
	}


begin:
	Tag = Name;
	WeaponWatcher.Event = self.Name;
	// spawn first weapon:
	Timer();
}

Code: Select all

//=============================================================================
// WeaponWatcher.
//=============================================================================
class WeaponWatcher expands Keypoint;

var Weapon WatchedWeapon;



event Timer() {
local Actor A;

	if (WatchedWeapon.bHeldItem || WatchedWeapon.bDeleteMe)
	{
		if (Event != '' )
			ForEach AllActors(Class'Actor', A, Event)
				A.Trigger(self, Pawn(WatchedWeapon.Owner));
		WatchedWeapon = None;
		SetTimer(0, false);
	}
}
You do not have the required permissions to view the files attached to this post.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Re: Need help with special weapon spawn

Post by Hbgr »

Okay that looks doable. Im seriously impressed. :tu:
But what do i do with this code? Im guessing i need to create a scriptable object, but im not sure where to go from here. :|
User avatar
Barbie
Godlike
Posts: 2770
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Need help with special weapon spawn

Post by Barbie »

Open map RandomWeaponSpawn.unr in UnrealEd, then open your map without closing Editor. All Actors of previous loaded map will stay in memory.
Then add Actor>Triggers>RandomWeaponSpawner somewhere in your map and configure it as you like. Remember that the Tags of RandomWeaponSpawner and SpawnPoints must match.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Re: Need help with special weapon spawn

Post by Hbgr »

Ok i got one RandomWeaponSpawner, and 6 WeaponWatcher keypoints. I set the RWS spawnedEvent name to RSpawn, and set the Tags of each WW to the same. I also set the SpawnDelay to 5 secs for testing, and put 6 different UT weapons (such as Class'Botpack.UT_Eightball') in Weapons slots 0 - 5.
I rebuilt everything, saved, and went to play with no bots.

None of the weapons were there. Do i need to preplace one of the weapons? How do i get it active?

With that said, im gonna need the weapons vertically placed in their slot. Is there a way to control that? Where are the weapons supposed to be spawned?
User avatar
OjitroC
Godlike
Posts: 3585
Joined: Sat Sep 12, 2015 8:46 pm

Re: Need help with special weapon spawn

Post by OjitroC »

You need to use NavigationPoint->Spawnpoint (setting the Tag to that of RWS) and not the WeaponWatcher. Just tried it myself and it works well.
User avatar
Barbie
Godlike
Posts: 2770
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Need help with special weapon spawn

Post by Barbie »

Hbgr wrote: Sat Oct 28, 2023 11:00 pm How do i get it active?
Maybe read the comment in the beginning of the code.
Hbgr wrote: Sat Oct 28, 2023 11:00 pm With that said, im gonna need the weapons vertically placed in their slot. Is there a way to control that?
You can rotate the SpawnPoints as desired. I did that in the test map.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
ExpEM
Adept
Posts: 298
Joined: Wed Nov 09, 2016 1:48 am

Re: Need help with special weapon spawn

Post by ExpEM »

My attempt:

Code: Select all

//=============================================================================
// OneAtATimePlease.
// By Michael 'ExpEM' Nunn.
//=============================================================================
class OneAtATimePlease expands Triggers;

var Weapon MyWeapons[8];
var byte WeaponsCount;
var() Byte SpawnDelay;
var() name MyWeaponsTag;
var int OldWeapon;
var() bool bForceNewWeapon;

//=============================================================================

Function FindWeapons()
{
	local Weapon W;

	foreach AllActors(class'Weapon', W, MyWeaponsTag)
	{
		MyWeapons[WeaponsCount++] = W;
		//Log (Self@"Found Weapon:"@W);
		if (WeaponsCount >= ArrayCount(MyWeapons))
		{
			Log(Self@"Too many Weapons! Only 8 Weapons are supported!");
			break;
		}
	}
}

Function PickWeapon()
{
	local int NewWeapon;
	local Weapon W;

	NewWeapon = Rand(WeaponsCount);

	if (bForceNewWeapon && WeaponsCount > 1)
		While (NewWeapon == OldWeapon)
		{
			//Log(Self@"Re-Roll");
			NewWeapon = Rand(WeaponsCount);
		}

	OldWeapon = NewWeapon;

	//Unfuckinate weapons before they can be dropped.
	foreach AllActors(class'Weapon', W, MyWeaponsTag)
	{
		if (W.Owner != None && W.Event == Tag)
		{
			W.Event = '';
			//Log(Self@"Unfuckinated"@W);
		}
	}
}

Function LeetHaxoring_YesIAmThatOld()
{
	local int I;

	for (I=0; I<WeaponsCount; I++)
	{
		if (I != OldWeapon)
			MyWeapons[I].ReSpawnTime = 999999999; // Never ReSpawn.
		else
			MyWeapons[I].RespawnTime = SpawnDelay;

		MyWeapons[I].GotoState('Sleeping');
	}
	//Log(Self@"New Weapon");
}

Function Trigger( actor Other, pawn EventInstigator )
{
	//Log(Self@"Weapon Pickup");
	GotoState('WaitForEvent', 'NextWeapon');
}

//=============================================================================

Auto State StartUp
{
	Function LeetHaxoring_YesIAmThatOld()
	{
		local int I;

		for (I=0; I<WeaponsCount; I++)
		{
			if (I != OldWeapon)
				MyWeapons[I].ReSpawnTime = 999999999; // Never ReSpawn.
			else
				MyWeapons[I].RespawnTime = -1; //Spawn now.

			MyWeapons[I].GotoState('Sleeping');
		}
		//Log(Self@"New Weapon");
	}

Begin:
	Sleep (0.1); //Is this required?
	OldWeapon = -1;
	FindWeapons();
	PickWeapon();
	LeetHaxoring_YesIAmThatOld();
	GotoState('WaitForEvent', 'Sleeping');
}

State WaitForEvent
{
NextWeapon:
	PickWeapon();
	LeetHaxoring_YesIAmThatOld();
Sleeping:
	//Log(Self@"Sleeping");
}

The differences Between Barbie's code and mine is that Barbie creates new Weapons on demand, my code affects pre-existing Weapons.
Barbie's code will create a random Weapon in a random location where mine always creates the same Weapon in the same location (With pre-existing rotation etc.).
Effectively little is different except that my Weapons are attached to the Pathing network so Bots can navigate from across the map, in Barbie's implementation the Bots will only pick up while they are nearby.
Either implementation can easily be modified to support more than 8 Weapons too.

EDIT:
Took out two lines of code that were left in from an experiment.
Last edited by ExpEM on Mon Oct 30, 2023 5:51 am, edited 1 time in total.
Signature goes here.
Hbgr
Novice
Posts: 8
Joined: Thu Oct 19, 2023 2:44 am

Re: Need help with special weapon spawn

Post by Hbgr »

Thanks for the immeasurable help @Ojitroc! That last bit of knowledge was enough to get @Barbie's beautiful invention working!

Theres only a couple of things that keep it from working perfectly the way i envisioned.
1. Theres no spawn sound for the weapons. Would love to have that instead of it just appearing coldly.
2. Since these particular weapons are on racks (standing vertically), some of the weapons, even though i corrected the spawnPoints' Rotation attribute, are not popping up on the racks properly rotated. Namely, the pulsegun and the ripper, which apparently are faced differently by default. I used real weapons to figure out their XYZs, then translated that to the spawn points. It seems the only way to control that is by allowing rotation XYZs for each weapon slot.

I cant believe you guys came up with these scripts so fast! Left up to me, i'd still be trying to figure out just how to get started. 8)

It occurs to me this actor could be used for anything right? Ammos, health units, even custom pickups!
User avatar
ExpEM
Adept
Posts: 298
Joined: Wed Nov 09, 2016 1:48 am

Re: Need help with special weapon spawn

Post by ExpEM »

Seeing as you are using Barbie's implementation I modified his code.
Hbgr wrote: Mon Oct 30, 2023 1:40 am 1. Theres no spawn sound for the weapons. Would love to have that instead of it just appearing coldly.
Fixed.
Hbgr wrote: Mon Oct 30, 2023 1:40 am 2. Since these particular weapons are on racks (standing vertically), some of the weapons, even though i corrected the spawnPoints' Rotation attribute, are not popping up on the racks properly rotated. Namely, the pulsegun and the ripper, which apparently are faced differently by default. I used real weapons to figure out their XYZs, then translated that to the spawn points. It seems the only way to control that is by allowing rotation XYZs for each weapon slot.
Fixed, a new variable called WeaponRotations.
Line up the rotation you want for Weapons[x] with WeaponsRotations[x].
NOTE: You can no longer have gaps in your Weapons array!
Hbgr wrote: Mon Oct 30, 2023 1:40 am It occurs to me this actor could be used for anything right? Ammos, health units, even custom pickups!
I had that thought while writing my implementation, as it stands, no, Barbie's code and mine are for Weapons only.
My code wont be too hard to modify to work with non-weapon pickups too, not so sure about Barbie's.

I modified Barbie's code as you appear to already have it implemented.

Code: Select all

/******************************************************************************
Class RandomWeaponSpawner:
Place up to 8 SpawnPoints with the same Tag as me and fill up to 8 Weapon types
into the *Weapons* array. Then one random chosen weapon is spawned at one
random chosen SpawnPoint. If that weapon is taken, the timeout of given
*SpawnDelay* starts and after it has run out, another random weapon is spawned
at a random SpawnPoint.

The array *Weapons* may contain gaps. -No it can't, ExpEM.
 
By SeriousBarbie AT Barbies DOT World, 2023-10-27

*******************************************************************************
Modified by ExpEM:
-Added per weapon rotation.
-Broke support for gaps in *Weapons* Array.
-Fixed spawn Effect and Sound.
30/10/23.
******************************************************************************/
class RandomWeaponSpawner expands Triggers;

var() bool bDebug;
var() bool bRotationWeapon;
var() class<weapon> Weapons[8];
var byte WeaponsCount;
var() Byte SpawnDelay;
var SpawnPoint SpawnPoints[8];
var byte SpawnPointsCount;
var(Events) name SpawnedEvent;
var WeaponWatcher WeaponWatcher;

var() Rotator WeaponRotations[8]; // Added by ExpEM.

function bool CollectSpawnPoints() {
local SpawnPoint SP;
local byte i;

	foreach AllActors(class'SpawnPoint', SP, Tag)
	{
		SpawnPoints[SpawnPointsCount++] = SP;
		if (SpawnPointsCount >= ArrayCount(SpawnPoints))
		{
			warn("only 8 SpawnPoints are supported");
			break;
		}
	}
	if (SpawnPointsCount == 0)
	{
		warn("No SpawnPoints with Tag=" $ Tag @ "found, exiting");
		destroy();
		return false;
		
	}
	if (bDebug)
	{
		logger(SpawnPointsCount @ "SpawnPoints found:");

		for (i = 0; i < SpawnPointsCount; i++)
			logger("SpawnPoints[" $ i $ "]=" $ SpawnPoints[i]);
	}
	return true;
}



function Logger(string msg) {

	if (bDebug) log(self $ ":" @ msg);
}



function bool CompactWeaponArray() { //Modified by ExpEM.
local byte i;

	for (i = 0; i < ArrayCount(Weapons); i++)
	{
		if (Weapons[i] != None)
			WeaponsCount++;
	}
	if ( WeaponsCount == 0)
	{
		warn("No Weapons given, exiting");
		destroy();
		return false;
	}
	if (bDebug)
	{
		logger(WeaponsCount @ "Weapons found:");

		for (i = 0; i < WeaponsCount; i++)
			logger("Weapon[" $ i $ "]=" $ Weapons[i]);
	}
	return true;
}


Event PostBeginPlay() {
	Super.PostBeginPlay();
	if ( ! CollectSpawnPoints()) return;
	if ( ! CompactWeaponArray()) return;
	WeaponWatcher = Spawn(class'WeaponWatcher');
}



function RaiseEvent(name EventName, Actor Other, Pawn EventInstigator) {
local Actor A;

	if (EventName != '')
		foreach AllActors(Class'Actor', A, EventName)
			A.Trigger(Other, EventInstigator);
}



function bool SpawnWeapon(byte WeaponIndex, byte SpawnPointIndex) {
local Weapon W;

	W = Spawn(Weapons[WeaponIndex], , , SpawnPoints[SpawnPointIndex].Location, WeaponRotations[WeaponIndex]); //Modified by ExpEM.
	if (W == None)
	{
		warn("Could not spawn" @ Weapons[WeaponIndex] @ "at" @ SpawnPoints[SpawnPointIndex]);
		return false;
	}
	logger(W @ "spawned at" @ SpawnPoints[SpawnPointIndex]);
	//W.Event = self.Tag;
	W.bRotatingPickup = bRotationWeapon;
	W.RespawnTime = 0;
	W.GotoState('Sleeping'); //Added by ExpEM.
	Log(W.RespawnSound);
	WeaponWatcher.WatchedWeapon = W;
	RaiseEvent(SpawnedEvent, W, None);
	WeaponWatcher.SetTimer(1.414, true);
}



auto State ready {

	Event Timer() {
		logger("Timer waked up, spawning weapon now");
		SpawnWeapon(Rand(WeaponsCount), Rand(SpawnPointsCount));
	}


	event Trigger(Actor Other, Pawn EventInstigator) {
		logger("tiggered, Other=" $ Other $ ", EventInstigator=" $ EventInstigator);
		SetTimer(SpawnDelay, false);
	}


begin:
	Tag = Name;
	WeaponWatcher.Event = self.Name;
	// spawn first weapon:
	Timer();
}
It's easy to get going in your map.
If you select a RandomWeaponSpawner you are using, right click it and select EditScript.
This will open it in the script editor.
Select all and press delete.
Copy all my code above and paste it into the script editor.
Click Compile Changed Scripts.
All done!

You may have to delete your original RandomWeaponSpawner before hitting compile to avoid a crash or garbage data appearing in variables.
Signature goes here.