class Effect_ShadowController extends Actor config(User); // the type of shadow projector we're going to use var class ShadowClass; // an array of shadows, the maximum allowed per player can be specified below var array Shadows; // an array of static lights var array LightList; // a special variable type, lastlight is used for fading struct LightGroup { var Actor CurrentLight; var Actor LastLight; }; // an array of lightgroups, filled when spawned var array Lights; // the maximum distance a light can be from a player to cast a shadow var float MaxLightDistance; // update frequency for filling light array var float UpdateFrequency; // the sun var SunLight SunLightActor; // turns on/off all shadows var bool bShadowActive; // maximum allowed shadows per player, configurable var globalconfig int MaxShadows; simulated function Initialize() { local Light LightActor; local array SunLights; local int i; // set the sunlight, pick the brightest one if we have multiple foreach AllActors(class'Light',LightActor) { if (SunLight(LightActor) != None) { SunLights[i] = SunLight(LightActor); i++; } else if (LightActor.LightType != LT_None && LightActor.LightBrightness > 1) { LightList[LightList.Length] = LightActor; } } for (i=0;i OrigLight; local float Diff; if(Pawn(Owner) != None && Pawn(Owner).Health < 1) return; // clear array of lights, leave LastLight alone to fade for (i=0;i (Owner.CollisionRadius * 0.5) && IsVisible(LightList[i].Location)) { if (Lights[0].CurrentLight != None && LightPriority(Lights[0].CurrentLight.LightBrightness,Lights[0].CurrentLight.LightRadius,VSize(Lights[0].CurrentLight.Location-Owner.Location)) > LightPriority(LightList[i].LightBrightness,LightList[i].LightRadius,Diff)) continue; // this puts them in order of priority for (j=1;j 1) { Diff = VSize(LightActor.Location - Owner.Location); if(Diff < MaxLightDistance && LightActor.LightRadius >= (Diff * 0.041) && Diff > (Owner.CollisionRadius * 0.5) && IsVisible(LightActor.Location)) { if (Lights[0].CurrentLight != None && LightPriority(Lights[0].CurrentLight.LightBrightness,Lights[0].CurrentLight.LightRadius,VSize(Lights[0].CurrentLight.Location-Owner.Location)) > LightPriority(LightActor.LightBrightness,LightActor.LightRadius,Diff)) continue; // this puts them in order of priority for (i=1;i 0) { if (OrigLight[i] == Lights[i-1].CurrentLight || OrigLight[i] == OrigLight[i-1]) OrigLight[i] = None; } Lights[i].LastLight = OrigLight[i]; } } // loop it, loop it good SetTimer(UpdateFrequency,false); } // simple function for determining the priority of a light function float LightPriority(float Brightness, float Radius, float Distance) { local float Priority; // brightness takes higher priority Priority = (Brightness*10)/Distance; // lights that are very close get higher priority if (Distance < 0.1 * MaxLightDistance) Priority *= 1.5; // lights with very small radii shouldn't really cast shadows if (Radius < 2.0) Priority *= (Radius*0.38); return Priority; } function bool IsVisible(vector Loc) { local vector FootLocation; // get a location near the feet FootLocation = Owner.Location; FootLocation.Z -= Owner.CollisionHeight*0.49; // not very clean, returns true if either the head, feet, or middle torso of the player is visible to Loc if (FastTrace(Loc,Owner.Location) || FastTrace(Loc,Owner.GetBoneCoords('head').Origin) || FastTrace(Loc,FootLocation)) return true; } function Tick(float dt) { // fallback if (Owner == None) return; // update all shadows UpdateShadows(dt); } function UpdateShadows(float dt) { local int i; for (i=0;i