Under suggestion from Ferali I removed this feature from my contest entry and I'm attempting to fix it apart from the rest of the game. I spent about 10 hours on this yesterday and it's incredibly frustrating. I keep thinking I have it and then I realize I just don't once I work back through the logic to see what's wrong. It's so easy to miss little things on something like this.
Ferali gave me some perfectly appropriate advice last night. He told me to stop trying to solve the big picture. Instead break things down into smaller, constituent parts. Work on the first part then move on to the second. In doing that I was able to walk from unsolved to very close to solved on this problem.
In case you want to see how I did this, here's the code. It's long but it's full of logging lines so I can see what is going on every step of the way. Logging outputs like this:
ScriptLog: PING
ScriptLog: Firing!
ScriptLog: NavPoint : 17
ScriptLog: Found the nav point
ScriptLog: HitActor: DM-StalwartXL.LevelInfo0
ScriptLog: Hit the level here : -335.623627,511.587708,102.062286
ScriptLog: Origin location: -335.623627,510.587708,102.062286
ScriptLog: Start Trace1 : -335.623627,510.587708,102.062286
ScriptLog: End Trace1 : -399.623627,510.612244,166.062286
ScriptLog: 2nd pass Start Trace1 : -399.623627,510.612244,166.062286
ScriptLog: 2nd pass End Trace1 : -399.622467,513.612244,166.062286
ScriptLog: 2nd pass Other : DM-StalwartXL.LevelInfo0
ScriptLog: Start Trace2 : -335.623627,510.587708,102.062286
ScriptLog: End Trace2 : -271.623627,510.563171,166.062286
ScriptLog: 2nd pass Start Trace2 : -271.623627,510.563171,166.062286
ScriptLog: 2nd pass End Trace2 : -271.622467,513.563171,166.062286
ScriptLog: 2nd pass Other : DM-StalwartXL.LevelInfo0
ScriptLog: Start Trace3 : -335.623627,510.587708,102.062286
ScriptLog: End Trace3 : -399.623627,510.612244,38.062286
ScriptLog: 2nd pass Start Trace3 : -399.623627,510.612244,38.062286
ScriptLog: 2nd pass End Trace3 : -399.622467,513.612244,38.062286
ScriptLog: 2nd pass Other : DM-StalwartXL.LevelInfo0
ScriptLog: Start Trace4 : -335.623627,510.587708,102.062286
ScriptLog: End Trace4 : -271.623627,510.563171,38.062286
ScriptLog: 2nd pass Start Trace4 : -271.623627,510.563171,38.062286
ScriptLog: 2nd pass End Trace4 : -271.622467,513.563171,38.062286
ScriptLog: 2nd pass Other : DM-StalwartXL.LevelInfo0
ScriptLog: Spawned a rocket yo
ScriptLog: Rocket hit wall here : -335.623627,510.587708,102.062286 <--difference here is Hitnormal + HitLocation, still same spot
ScriptLog: Spray Attempts : 27
The mod is grabbing a random pathnode and tracing out from it in a random 360 arc and with up to 10 degrees of upwards angle. It runs the checks for a 128X128 texture and if they all pass it spawns a rocket subclass that has my graffiti as the scorch. The rocket is spawned at the trace origin (Hitlocation + Hitnormal) and aimed with -Hitnormal. This immediately impacts it onto the wall at the right spot.
Here's the code:
Code: Select all
class GraffitiMod extends Mutator config(GraffitiMod);
var int NumNodes, NavPoint, SprayAttempts;
var bool Initialized, GraffitiAllDone;
var NavigationPoint PNodes[5001];
var config bool UseGraffiti;
var config int GraffitiNumber;
replication
{
reliable if ( Role == ROLE_Authority )
GraffitiNumber;
}
function PostBeginPlay()
{
local NavigationPoint NP;
if (Initialized)
return;
Initialized = True;
SprayAttempts = 0;
for (NP = Level.NavigationPointList; NP != None; NP = NP.NextNavigationPoint)
{
if (NP.IsA('Pathnode') && !NP.Region.Zone.bWaterZone)
{
if(NumNodes <= 5000)
{
PNodes[NumNodes] = NP;
NumNodes++;
}
}
}
SetTimer(1,True);
}
simulated Function addMutator(mutator M)
{
if(M.class==self.class)
m.destroy();
else super.addMutator(M);
}
function SpawnGraffiti()
{
local int PointCount;
local NavigationPoint NP;
local rotator newRot;
local vector HitLocation, HitNormal, FireDir, X, Y, Z, Origin, StartTrace, EndTrace;
local actor HitActor, Other;
local int i, j, N, M, SpriteX, SpriteY;
local float yOffset, zOffset;
local tag1 SpawnedGraffitiRocket;
BroadcastMessage("Firing!");
log("Firing!");
NavPoint = int(RandRange(0,NumNodes));
log("NavPoint :"@NavPoint);
for (NP = Level.NavigationPointList; NP != None; NP = NP.NextNavigationPoint)
{
if (NP.IsA('PathNode'))
{
if (PointCount == NavPoint)
{
log("Found the nav point");
newRot.Yaw = Rand(65535); //360 degrees around
newRot.Pitch = Rand(1820); //from 0 to roughly 10 degrees upward angle
newRot.Roll = 0;
FireDir = vector(newRot);
HitActor = Trace(HitLocation, HitNormal, location + FireDir * 1500, Location, false);
log("HitActor: "@Hitactor);
if(( HitActor == Level) && ( HitNormal.Z < 0.03 ) && ( HitNormal.Z > -0.03 ))
{
log("Hit the level here :"@HitLocation);
GetAxes( rotator(-HitNormal), X, Y, Z);
Origin = HitLocation + HitNormal;
log("Origin location: "@Origin);
//Pass 1 (64, 64)
StartTrace = Origin;
log("Start Trace1 :"@StartTrace);
EndTrace = Origin + Y * 64 + Z * 64;
log("End Trace1 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != none)
return;
else
{
StartTrace = Origin + Y * 64 + Z * 64;
log("2nd pass Start Trace1 :"@StartTrace);
EndTrace = StartTrace + X * 3;
log("2nd pass End Trace1 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
log("2nd pass Other :"@Other);
if (Other != none)
{
//Pass 2 (-64, 64)
StartTrace = Origin;
log("Start Trace2 :"@StartTrace);
EndTrace = Origin + Y * -64 + Z * 64;
log("End Trace2 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != none)
return;
else
{
StartTrace = Origin + Y * -64 + Z * 64;
log("2nd pass Start Trace2 :"@StartTrace);
EndTrace = StartTrace + X * 3;
log("2nd pass End Trace2 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
log("2nd pass Other :"@Other);
if (Other != none)
{
//Pass 3 (64, -64)
StartTrace = Origin;
log("Start Trace3 :"@StartTrace);
EndTrace = Origin + Y * 64 + Z * -64;
log("End Trace3 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != none)
return;
else
{
StartTrace = Origin + Y * 64 + Z * -64;
log("2nd pass Start Trace3 :"@StartTrace);
EndTrace = StartTrace + X * 3;
log("2nd pass End Trace3 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
log("2nd pass Other :"@Other);
if (Other != none)
{
//Pass4 (-64, -64)
StartTrace = Origin;
log("Start Trace4 :"@StartTrace);
EndTrace = Origin + Y * -64 + Z * -64;
log("End Trace4 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != none)
return;
else
{
StartTrace = Origin + Y * -64 + Z * -64;
log("2nd pass Start Trace4 :"@StartTrace);
EndTrace = StartTrace + X * 3;
log("2nd pass End Trace4 :"@EndTrace);
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
log("2nd pass Other :"@Other);
if (Other != none)
{
log("Spawned a rocket yo");
SpawnedGraffitiRocket = Spawn(class'tag1',,, Origin,rotator(-HitNormal));
}
}
} else return;
}
} else return;
}
} else return;
}
} else return;
} PointCount++;
}
}
}
simulated function Timer()
{
local Tagz1 T;
local int Q;
local PathNode PN;
if (Level.Game.bGameEnded) return;
if(!GraffitiAllDone)
{
SprayAttempts +=1;
log("Spray Attempts :"@SprayAttempts);
if (SprayAttempts > 60) //cap number of tries to prevent runaway
GraffitiAllDone = true;
Q=0;
forEach AllActors(class'Tagz1', T) //cap number of sprays for the map
{
if (T !=none)
Q +=1;
log("Q ="@Q);
if (Q >= GraffitiNumber)
GraffitiAllDone = true;
}
if(!GraffitiAllDone)
{
BroadcastMessage("PING!");
log("PING");
SpawnGraffiti();
}
else
SetTimer(0, False);
}
}
defaultproperties
{
GraffitiAllDone=False
UseGraffiti=true
GraffitiNumber=4
}
I broke the checks down into a linear progression so I could understand them better and see everything that's going on. I'm sure they could be done in a 'For' loop but I really want to understand each line of code and why it's doing what it's doing.
Whew. Thanks for reading so far....Mind a couple of questions? First, if you see improvements to the checks I'd very much love to hear them. Turns out it's rather hard to randomly select a proper spot. Very often the mod runs out of attempts before it finds enough candidates to place 5 graffiti. Any speed improvement would be very helpful. Secondly, I have the check running anew every second. Can I speed that up some without impacting the server? I don't really know how fast these traces are running. I still need to give time for the spawning of the graffiti but can I run these at 4 or 5 a second you think?