Food Feud
Food Feud is a networked multiplayer game with a quirky flair built using UDK. Players compete to collect and protect customers in this custom capture-the-flag game. Food Feud features four unique weapons, four custom classes, network support and one custom game mode. I worked on Food Feud as lead programmer. My responsibilities included leading the programming team, as well the artificial intelligence systems and custom capture-the-flag game mode. The game was developed by a team of seven over three months. |
View Code
class FFSquadAI extends UTSquadAI; var FFBaseObjective homeBase, enemyBase; var FFFlag ownedFlags[ 3 ]; var FFFlag enemyFlags[ 3 ]; var FFFlag neutralFlags[ 3 ]; var int nOwnedFlags; var int nEnemyFlags; var int nNeutralFlags; var float AIDropFlagDistTolerance; var float AIIgnoreFlagDistance; /* FindPathToObjective() Returns path a bot should use moving toward a base */ function bool FindPathToObjective( UTBot B, Actor O ) { // don't ever use gather points when have flag if ( UTPlayerReplicationInfo(B.PlayerReplicationInfo).bHasFlag ) { B.bFinalStretch = true; } return Super.FindPathToObjective(B, O); } // Find out who owns which flags function RecheckFlagStatus() { local FFFlag curFlag; nOwnedFlags = 0; nEnemyFlags = 0; nNeutralFlags = 0; foreach AllActors(class'FoodFeud.FFFlag', curFlag ) { if ( curFlag.Team == Team ) { ownedFlags[ nOwnedFlags ] = curFlag; ++nOwnedFlags; } else if ( curFlag.Team == none ) { neutralFlags[ nNeutralFlags ] = curFlag; ++nNeutralFlags; } else { enemyFlags[ nEnemyFlags ] = curFlag; ++nEnemyFlags; } } } /* OrdersForFlagCarrier() Tell bot what to do if he's carrying the flag */ function bool OrdersForFlagCarrier( UTBot B ) { //local UTCTFBase FlagBase; B.GoalString = "Return to Base with enemy flag!"; if ( !FindPathToObjective( B, homeBase ) ) { B.GoalString = "No path to home base for flag carrier"; // FIXME - suicide after a while `log( "Bot could not find path to home base" ); return false; } if ( B.MoveTarget == homeBase ) { B.GoalString = "Near my Base with enemy flag!"; if ( VSize( B.Pawn.Location - homeBase.Location ) < AIDropFlagDistTolerance ) FFPawn( B.Pawn ).DropFlag(); } return true; } function bool CheckSquadObjectives( UTBot B ) { local FFFlag closestFlag; local float closestFlagDist; local FFCTF game; local UTGameObjective testObjective; if ( UTPlayerReplicationInfo(B.PlayerReplicationInfo).bHasFlag ) return OrdersForFlagCarrier(B); AddTransientCosts(B,1); // Always grab a free flag when it's visible and close enough game = FFCTF( WorldInfo.Game ); closestFlag = game.ClosestVisibleFreeFlag( B ); if ( closestFlag != none ) { // I see a free flag closestFlagDist = VSize( closestFlag.Location - B.Pawn.Location ); if ( closestFlagDist < AIIgnoreFlagDistance ) { // Flag is close enough to matter if ( closestFlagDist < game.FlagGrabDistance ) { // Flag is close enough to grab FFPawn( B.Pawn ).GrabFlag( closestFlag ); return OrdersForFlagCarrier( B ); } // Move to the flag if ( FindPathToObjective( B, closestFlag ) ) return true; } } // Don't see a free flag, or no path to it. // If I'm not grabbing a free flag, then... // If we have a delivery guy who is boosting, go grab a granny. if ( FFBot( B ).bBoosting ) { if ( FFFlagSpawnPoint( SquadObjective ) == none ) { testObjective = FFCTF( WorldInfo.Game ).FindReadyFlagBaseObjective(); if ( testObjective != none ) { if ( FFFlagSpawnPoint( testObjective ).bFlagIsHere ) SquadObjective = testObjective; } } if ( FFFlagSpawnPoint( SquadObjective ) == none && B.Enemy != none ) return false; } // I should go to the squad's objective only if I'm not actively fighting else if ( B.Enemy != none ) { return false; } // If I've reached my squad's objective, send my squad somewhere else if ( SquadObjective == none || VSize( B.Pawn.Location - SquadObjective.Location ) < AIDropFlagDistTolerance ) { UTTeamInfo( Team ).AI.FindNewObjectiveFor( self, true ); // Or TellBotHowToDisable() could set a new squad objective. return true; } return Super.CheckSquadObjectives(B); } DefaultProperties { AIDropFlagDistTolerance = 100; AIIgnoreFlagDistance = 1000; }
class GreaseTrapProjectile extends Actor; var float BounceRatio; var float maxLifespan; var float curAge; var float greaseDuration; var float greaseGrowTime; var float greaseShrinkTime; var float greaseMaxRadius; var float greaseRadius; var byte nBounces; var byte maxBounces; var GreaseBlob myBlob; var Controller damageInstigator; //========================================================================= //========================================================================= auto simulated state Flying { simulated function Tick( float DeltaTime ) { curAge += DeltaTime; if ( curAge > maxLifespan ) Landed( Velocity, none ); } //========================================================================= //========================================================================= simulated function Landed( Vector HitNormal, Actor FloorActor ) { SetPhysics( PHYS_NONE ); GotoState('Resting'); } //========================================================================= //========================================================================= simulated function HitWall (vector norm, actor wall, primitivecomponent something ) { if ( wall.bWorldGeometry ) { if ( norm.Z > 0.7 ) { ++nBounces; if ( nBounces > maxBounces ) { Landed( norm, wall ); return; } } Velocity = BounceRatio * (( Velocity dot norm ) * norm * (-2.0) + Velocity); } } //========================================================================= //========================================================================= simulated function BeginState( Name PreviousStateName ) { curAge = 0; } } //========================================================================= //========================================================================= simulated state Resting { simulated function Tick( float DeltaTime ) { curAge += DeltaTime; if ( curAge > greaseDuration ) { myBlob.Destroy(); Destroy(); return; } else if ( curAge > greaseDuration - greaseShrinkTime ) { greaseRadius = ( greaseDuration - curAge ) / greaseShrinkTime * greaseMaxRadius; myBlob.setSize( greaseRadius ); } else if ( curAge > greaseGrowTime ) { if ( greaseRadius < greaseMaxRadius ) { greaseRadius = greaseMaxRadius; myBlob.setSize( greaseRadius ); } } else { greaseRadius = curAge / greaseGrowTime * greaseMaxRadius; myBlob.setSize( greaseRadius ); } } simulated function BeginState( Name PreviousStateName ) { if ( Role == ROLE_Authority ) { myBlob = Spawn( class'FoodFeud.GreaseBlob' ); myBlob.DamageInstigator = damageInstigator; } curAge = 0; } } //========================================================================= //========================================================================= replication { if ( Role==ROLE_Authority ) BounceRatio, maxLifespan, curAge, greaseDuration, greaseGrowTime, greaseShrinkTime, greaseMaxRadius, nBounces, maxBounces, myBlob; } //========================================================================= //========================================================================= DefaultProperties { Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment End Object Components(0)=MyLightEnvironment Begin Object Class=StaticMeshComponent Name=MyStaticMesh LightEnvironment=MyLightEnvironment StaticMesh=StaticMesh'FoodFued.Models.fry_basket_mesh_01' End Object Components(1)=MyStaticMesh CollisionComponent=MyStaticMesh; RemoteRole=ROLE_SimulatedProxy; bCollideWorld=true Physics=PHYS_Falling bStatic=False bMovable=True bAlwaysRelevant=true; bBounce = true curAge = 0 nBounces = 0; greaseRadius = 0; // How bouncy is it ( 0 - no bounce, 1 - crazy bouncy ) BounceRatio = 0.3 // How many times does the grease trap bounce on the ground before landing maxBounces = 1; // How long will it bounce around before exploding due to timeout maxLifespan = 5 // How long is the grease ball active greaseDuration = 13; // How much of that time is spent growing to full size? greaseGrowTime = 2; greaseShrinkTime = 1; greaseMaxRadius = 500; }