Spawning system issue
Soul_Rider
Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
I'm looking at making an alternate spawning system for aliens, but I am getting confused in the current code, so some advice in the right direction would help.
Here is my plan:
Player dies and joins spectator.
Player specs for 2 secs
Hive then creates an egg for player and player is immediately placed in it.
Player spawns from egg after x secs.
I want to use the code for working out where to place an egg to immediately spawn and put the player in it, but only create it when needed, kind of like old NS used to :)
Any assistance is greatly appreciated, I'll post more on the topic when my head is a bit clearer :)
Here is my plan:
Player dies and joins spectator.
Player specs for 2 secs
Hive then creates an egg for player and player is immediately placed in it.
Player spawns from egg after x secs.
I want to use the code for working out where to place an egg to immediately spawn and put the player in it, but only create it when needed, kind of like old NS used to :)
Any assistance is greatly appreciated, I'll post more on the topic when my head is a bit clearer :)
Comments
It would make more sense to change the behavior of the current spawn queue system.
I'm pretty sure the current egg placement uses the AI Pathing system to determine where and if a new egg can be placed in a specific spot.
Separately the hive checks for timing and location of placing an egg.
I want to combine the two into one. There is no timing, and the finding of a suitable location for an egg is done, when the player is ready to be placed in the egg. It's just that code relevant to 'egg' spans 34 different files, and following the loop is getting me very confused :) Not all of it is relevant of course, and that makes it worse :)
Oh and I'm looking forward to seeing your MvM mod :)
I have been working on this for a while now and have got it working to a point, but I have now reached a stuck point.
At the moment I check the team for all players who are not alive.
For each person not alive, I increment a number ipsToBuild.
When the IP is built, ipsToBuild is - 1.
The problem is, I have had to put the check for not alive code in the marineteam:update code. This creates a rather large problem...
Everytime the update code is run, it checks the queue for someone dead and adds an ip for them. So in the current code, a new Ip gets placed for each person in the queue each update. As you are queueing for quite a few updates, you can imagine what happens - Spam IPS!!! I was aware this would happen if the code worked, but I just wanted working code in the first instance :)
There are 2 ways I can see to implement this, one is a hackaround, and the other is the graceful solution. As usual, I don't know how to do the graceful version so i'd like some help...
Here is the current code:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function MarineTeam:UpdateIPBuild()
for index, player in ipairs(self:GetPlayers()) do
if not player:GetIsAlive() then
ipsToBuild = ipsToBuild + 1
end
self:SpawnInfantryPortals(self:GetInitialTechPoint())
end
end<!--c2--></div><!--ec2-->
The elegant solution I'd like to work out is:
Initially all players are alive.
Get the number of players in the dead queue
No of players in queue should equal ipsToBuild + IP's built.
If no of players in queue exceed this total, then ipstobuild +1
The hack around idea is:
Shorten the spawn time and only run the update every spawn time period, so in theory anyone in the queue will have spawned before the next update is run, resulting in 1 IP per person. That is a hack though so I'd rather not do it :)
-----Edit----
Little video of IP spam caused by mod...
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/XRichLbIY70"></param><embed src="http://www.youtube.com/v/XRichLbIY70" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
-------Edit 2-----
The problem is because I am trying to work off the dead queue, I need to trigger the IP spawn on player death. Is there any location other than onkill() that handles what happens when a player dies? I can't find anything. Preferably something within the team framework, but it is very small :P
Here is the original code that I wrote, that turned out to be server side only. This code works 100% of the time if you are hosting your own listen server:
Marine_Server.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:SpawnInfantryPortals(techPoint)
local techPointOrigin = techPoint:GetOrigin() + Vector(0, 2, 0)
local origin = CalculateRandomSpawn(nil, techPointOrigin, kTechId.InfantryPortal, true, kInfantryPortalMinSpawnDistance * 1, kInfantryPortalMinSpawnDistance * 5, 3)
if origin then
local ip = CreateEntity(InfantryPortal.kMapName, origin, self:GetTeamNumber())
SetRandomOrientation(ip)
ip:SetConstructionComplete()
end
end<!--c2--></div><!--ec2-->
Also in the Marine:OnKill() function, I added the call to the create IP function:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:OnKill(damage, attacker, doer, point, direction)
self:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint())
......
... etc etc
end<!--c2--></div><!--ec2-->
Here is the code working on my listen server...
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/6bU_5RlT9qY"></param><embed src="http://www.youtube.com/v/6bU_5RlT9qY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
This works as the server host on a listen server, but not for anyone else playing the game. So how do I get this code to work for everyone and not just the server? How do I trigger it?
I have tried many different ways around, but somewhere along the line the same problem occurs, the team information is lost. Here is the latest example, which I thought was the most promising:
Marine_Server.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:OnKill(damage, attacker, doer, point, direction)
// Drop main weapon, destroy the others.
self:Drop(self:GetWeaponInHUDSlot(kPrimaryWeaponSlot), true)
self:DestroyWeapons()
Player.OnKill(self, damage, attacker, doer, point, direction)
self:PlaySound(Marine.kDieSoundName)
MarineTeam:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint())
// Don't play alert if we suicide
if player ~= self then
self:GetTeam():TriggerAlert(kTechId.MarineAlertSoldierLost, self)
end
// Remember our squad and position on death so we can beam back to them
self.lastSquad = self:GetSquad()
self.originOnDeath = self:GetOrigin()
end<!--c2--></div><!--ec2-->
Above I just added the line: MarineTeam:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint()) into the function.
This calls the function in MarineTeam.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function MarineTeam:SpawnInfantryPortals(techPoint)
local techPointOrigin = techPoint:GetOrigin() + Vector(0, 2, 0)
local origin = CalculateRandomSpawn(nil, techPointOrigin, kTechId.InfantryPortal, true, kInfantryPortalMinSpawnDistance * 1, kInfantryPortalMinSpawnDistance * 5, 3)
if origin then
local ip = CreateEntity(InfantryPortal.kMapName, origin, self:GetTeamNumber())
SetRandomOrientation(ip)
ip:SetConstructionComplete()
end
end<!--c2--></div><!--ec2-->
Now the IP is created and it tries to pull the player out of the respawn queue. This is where the code flags the loss of team value, in InfantryPortal.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function InfantryPortal:QueueWaitingPlayer()
if self:GetIsAlive() and self.queuedPlayerId == Entity.invalidId then
// Remove player from team spawn queue and add here
local team = self:GetTeam()
local playerToSpawn = team:GetOldestQueuedPlayer()
if playerToSpawn ~= nil then
playerToSpawn:SetIsRespawning(true, self:GetId())
team:RemovePlayerFromRespawnQueue(playerToSpawn)
self.queuedPlayerId = playerToSpawn:GetId()
self.queuedPlayerStartTime = Shared.GetTime()
self:StartSpinning()
playerToSpawn:AddTooltipOncePer("SPAWNING_PORTAL_TOOLTIP")
if Server then
if playerToSpawn.SetIsThirdPerson then
playerToSpawn:SetIsThirdPerson(3)
end
if playerToSpawn.SetSpectatorMode then
playerToSpawn:SetSpectatorMode(Spectator.kSpectatorMode.FreeLook)
end
if playerToSpawn.SetOrigin then
playerToSpawn:SetOrigin(self:GetOrigin())
end
end
end
end
end<!--c2--></div><!--ec2-->
Specifically the initial part of the function is pointed out in the error:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function InfantryPortal:QueueWaitingPlayer()
if self:GetIsAlive() and self.queuedPlayerId == Entity.invalidId then
// Remove player from team spawn queue and add here
local team = self:GetTeam()
local playerToSpawn = team:GetOldestQueuedPlayer() <---------------------<!--c2--></div><!--ec2-->
The complete error log for this is very short:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Script Error #1: lua/InfantryPortal.lua:110: attempt to index local 'team' (a nil value)
Call stack:
#1: QueueWaitingPlayer lua/InfantryPortal.lua:110
self = Entity{....reams of options.....}
team = nil
#2: lua/InfantryPortal.lua:359
self = Entity{....reams of options......... }<!--c2--></div><!--ec2-->
now as this is the first occurrence of nil value in team, it is important to remember team number is first passed in Marine:OnKill() so the loss of team may not be at this specific point. Saying that, I have lost team at other points using different methods, but have got passed the initial errors I had with those other methods, this time I have got as far as the ip being created, but it doesn't have a spawn queue to pull from, because it has no valid team.
I am sure this is a fairly simple oversight, if anyone can help, I would greatly appreciate it. I've been working on this code for 12 hours straight and my mind is logic blocked :P
Here is a video showing how far it gets in the process. I think I have resolved all the other team issues, as the IP now creates and everything, the only problem seems to be finding the spawn queue:
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/ieqOhwectxE"></param><embed src="http://www.youtube.com/v/ieqOhwectxE" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Any help greatly appreciated :)
Otherwise it could go wrong on the GetTeam() side, it looks to be here :
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->/**
* The team object only exists on the Server.
*/
function TeamMixin:GetTeam()
assert(Server)
if not GetHasGameRules() then
return nil
end
return GetGamerules():GetTeam(self:GetTeamNumber())
end<!--c2--></div><!--ec2-->
Is everything done server side ? Is GetGamerules() defined ?
I manually set team = GetGameRules():GetTeam1()
So now I test it locally and it works, test it on the server and nothing. Marine:OnKill() seems to be the problem. Using this from the Marine_Server file seems to make the things only happen if the server and client are the same machine.
I need another alternative instead of Marine:OnKill() to call the function, but there is nowhere that runs on both client and server related to the player dying. Team has OnKill function, which I tried in MarineTeam:OnKill() but the entities wouldn't pass through.
I can't find, on the client code, anything to do with player death, except animate deathcam. I don't think it's right to try and create an IP in that code. One of my earlier versions had me writing 5 different functions in MarineTeam to try and handle the changes, but still didn't work properly. I am almost the certain that calling this on Marine_Server is the root cause of the issue only happening when machine is server and client. I need a way around that.
It looks like I may need to go back to the first version posted and try and control the death queue through the hack I mentioned :)