I've implemented the corrupt data segment basis (check Wiki Appendix for further details).
Features implemented:
- the volume: replace pawn inventory by the checktool, allow the player to scan or heal the corrupt data segment
- the corrupt data segment: scan and heal mechanism implemented, display current scan or heal amount and corruptdata tag name on screen as well.
- send localmessage at scan and heal end
- 2 Damage types: (primary and secondary) used by corrupt data segment class to know what FireMode the player is using.
Temporary Feature:
- CheckTool: a basic weapon has been created, it inherits from the Enforcer (could be replaced later depends of what should the CheckTool looks like)
CheckTool secondary fire sucks but as I said it's temporary
Here are some pictures in Game:
Phase Scanning
Phase Healing
Message End Phase
Source Code
Corrupt Data Segment
class DataRun_CorruptDataSegment extends Actor placeable; var() string corruptDataTagName; var() int scanDuration; var() int healDuration; var() string scanEndMessage; var() string healEndMessage; //this boolean is updated according to pawn location. true when pawn entering the //volume and false when leaving. This is used to prevent scan or heal outside //the volume var bool segmentCanBeHit; var float currentScanAmount; var float currentHealAmount; var float scanIncrement; var float healIncrement; event TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { if(!segmentCanBeHit || self.IsInState('healed')) return; if(DataRun_CheckTool(DamageCauser) == None) return; //compute scan and heal increment if(scanIncrement == -1 || healIncrement == -1) { scanIncrement = DataRun_CheckTool(DamageCauser).fireInterval[0] * 100 / scanDuration; healIncrement = DataRun_CheckTool(DamageCauser).fireInterval[1] * 100 / healDuration; } if(DamageType == class'DataRun_CheckTool_DmgType_PrimaryFire' && currentScanAmount < 100) { GotoState('scanning'); } if(DamageType == class'DataRun_CheckTool_DmgType_SecondaryFire' && currentScanAmount >= 100 && currentHealAmount < 100) { GotoState('healing'); } } state scanning { event TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { if(!segmentCanBeHit || self.IsInState('healed') || DamageType != class'DataRun_CheckTool_DmgType_PrimaryFire') return; currentScanAmount += scanIncrement; if(currentScanAmount >= 100) { PlayerController(EventInstigator).ReceiveLocalizedMessage(MessageClass,0,,,self); GotoState('healing'); } } function BeginState(Name PreviousStateName) { //First we enter state increase scan amount currentScanAmount += scanIncrement; } } state healing { event TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { if(!segmentCanBeHit || self.IsInState('healed') || DamageType != class'DataRun_CheckTool_DmgType_SecondaryFire') return; currentHealAmount += HealIncrement; if(currentHealAmount >= 100) { PlayerController(EventInstigator).ReceiveLocalizedMessage(MessageClass,1,,,self); GotoState('healed'); } } function BeginState(Name PreviousStateName) { //First we enter state increase heal amount currentHealAmount += healIncrement; } } //final state for corrup data segment state healed { function BeginState(Name PreviousStateName) { } } simulated event PostRenderFor(PlayerController PC, Canvas Canvas, vector CameraPosition, vector CameraDir) { local float XL, YL, HealthX, TextXL; local vector ScreenLoc; local string ScreenName; ScreenLoc = Canvas.Project(Location); // make sure not clipped out if (screenLoc.X < 0 || screenLoc.X >= Canvas.ClipX || screenLoc.Y < 0 || screenLoc.Y >= Canvas.ClipY) { return; } if(currentScanAmount > 0 && currentScanAmount < 100) { ScreenName = corruptDataTagName@"Scan Phase in Progress ..."; } else if(currentHealAmount > 0 && currentHealAmount < 100) { ScreenName = corruptDataTagName@"Heal Phase in Progress ..."; } else { ScreenName = ""; } if(ScreenName != "") { Canvas.StrLen(ScreenName, TextXL, YL); Canvas.DrawColor = class'UTHUD'.default.LightGreenColor; Canvas.SetPos(ScreenLoc.X-0.5*TextXL,ScreenLoc.Y-60); Canvas.DrawTextClipped(ScreenName, true); } if(currentScanAmount < 100) { HealthX = currentScanAmount; } else { HealthX = currentHealAmount; } XL = 100; class'UTHUD'.static.DrawHealth(ScreenLoc.X-0.5*XL, ScreenLoc.Y - 50, HealthX, XL, 20, Canvas); } defaultproperties { scanDuration = 2 healDuration = 5 scanEndMessage = "scanning complete" healEndMessage = "healing complete" scanIncrement = -1 healIncrement = -1 currentScanAmount = -1 currentHealAmount = -1 MessageClass = class'DataRun_CorruptDataSegmentMessage'; Begin Object class=DynamicLightEnvironmentComponent Name=OnslaughtFlagLightEnvironment bDynamic=FALSE bCastShadows=FALSE End Object Components.Add(OnslaughtFlagLightEnvironment) Begin Object class=CylinderComponent Name=CollisionCylinder ObjName=CollisionCylinder Archetype=CylinderComponent'Engine.Default__CylinderComponent' CollisionHeight=25.000000 CollisionRadius=25.000000 CollideActors=True BlockActors=true BlockZeroExtent=true BlockNonZeroExtent=true HiddenGame=false Name="CollisionCylinder" ObjectArchetype=CylinderComponent'Engine.Default__CylinderComponent' End Object Components.Add(CollisionCylinder) Begin Object class=StaticMeshComponent Name=StaticMeshComponent0 StaticMesh=StaticMesh'Pickups.PowerCell.Mesh.S_Pickups_PowerCell_Cell01' LightEnvironment=OnslaughtFlagLightEnvironment scale=2 End Object Components.Add(StaticMeshComponent0) bCanBeDamaged = true bCollideActors = true bBlockActors = true CollisionComponent=CollisionCylinder CollisionType=COLLIDE_CustomDefault name="Default__DataRun_CorruptDataSegment" ObjectArchetype=Actor'Engine.Default__Actor' }
Corrupt Data Volume
class DataRun_CorruptDataVolume extends PhysicsVolume placeable; var DataRun_CorruptDataSegment segmentActor; var(ExistingSegment) string segmentTag; var class<Weapon> checkToolClass; var InventoryManager PawnBackupInvManager; var Weapon PawnBackupWeapon; simulated function PostBeginPlay() { local DataRun_CorruptDataSegment a; foreach WorldInfo.AllActors(class'DataRun_CorruptDataSegment', a) { if(a.corruptDataTagName == segmentTag) { segmentActor = a; break; } } } event PawnEnteredVolume(Pawn Other) { local PlayerController PC; PC = PlayerController(Other.Controller); if(PC != None) { //enable segment segmentActor.segmentCanBeHit = true; //enable postRender UTHUD(PC.myHUD).AddPostRenderedActor(segmentActor); giveCheckTool(Other); } } event PawnLeavingVolume(Pawn Other) { local PlayerController PC; PC = PlayerController(Other.Controller); if(PC != None) { //disable segment segmentActor.segmentCanBeHit = false; //disable postRender UTHUD(PC.myHUD).RemovePostRenderedActor(segmentActor); restituteInventory(Other); } } function giveCheckTool(Pawn P) { local Inventory inv; local InventoryManager checkToolInvManager; //backup inventoryManager and weapon PawnBackupInvManager = P.InvManager; PawnBackupWeapon = P.Weapon; //set new inventory and select CheckTool Weapon checkToolInvManager = spawn(class'UTInventoryManager'); UTInventoryManager(checkToolInvManager).bInfiniteAmmo = true; checkToolInvManager.SetupFor(P); P.InvManager = checkToolInvManager; P.InvManager.CreateInventory(checkToolClass, true); //we have to force CheckTool selection Inv = P.FindInventoryType(checkToolClass); P.InvManager.SetPendingWeapon(Weapon(Inv)); P.InvManager.ChangedWeapon(); } function restituteInventory(Pawn P) { //restitute previous inventory P.InvManager = PawnBackupInvManager; if(PawnBackupWeapon != None) { P.InvManager.SetPendingWeapon(PawnBackupWeapon); P.InvManager.ChangedWeapon(); } } defaultproperties { checkToolClass = class'DataRun_CheckTool' }
Corrupt Data Message
class DataRun_CorruptDataSegmentMessage extends UTLocalMessage; static function string GetString( optional int Switch, optional bool bPRI1HUD, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) { local DataRun_CorruptDataSegment CR; CR = DataRun_CorruptDataSegment(OptionalObject); if( CR != None) { switch(Switch) { case 0: return CR.scanEndMessage; case 1: return CR.healEndMessage; } } return ""; } defaultproperties { bIsUnique=true bCountInstances=true DrawColor=(R=255,G=255,B=128,A=255) FontSize=2 bIsConsoleMessage=false MessageArea=5 }
Temporary CheckTool
class DataRun_CheckTool extends UTWeap_Enforcer; defaultproperties { WeaponFireTypes[0]=EWFT_InstantHit WeaponFireTypes[1]=EWFT_InstantHit InstantHitDamageTypes(0)=class'DataRun_CheckTool_DmgType_PrimaryFire' InstantHitDamageTypes(1)=class'DataRun_CheckTool_DmgType_SecondaryFire' FireInterval(0)=+0.25 FireInterval(1)=+0.25 InstantHitDamage(0)=0 InstantHitDamage(1)=0 FiringStatesArray(0)=WeaponFiring FiringStatesArray(1)=WeaponFiring }
PrimaryFireDamageType
class DataRun_CheckTool_DmgType_PrimaryFire extends UTDamageType; static function DoCustomDamageEffects(UTPawn ThePawn, class<UTDamageType> TheDamageType, const out TraceHitInfo HitInfo, vector HitLocation) { //Ze goggles! Zey do nuthing!! } defaultproperties { bUseTearOffMomentum=false bCausedByWorld=false bOverrideHitEffectColor=true HitEffectColor=(R=0,G=0,B=0) }
SecondaryFireDamageType
class DataRun_CheckTool_DmgType_SecondaryFire extends UTDamageType; static function DoCustomDamageEffects(UTPawn ThePawn, class<UTDamageType> TheDamageType, const out TraceHitInfo HitInfo, vector HitLocation) { //Ze goggles! Zey do nuthing!! } defaultproperties { bUseTearOffMomentum=false bCausedByWorld=false bOverrideHitEffectColor=true HitEffectColor=(R=0,G=0,B=0) }
Questions? Comments?