Here's an example of a chunky script that uses entities to provide a basic single player game with multiple levels.
First off we've got a basic building script file that's used to provide an access point for the player where they can start the minigame:
$kPlayGamePlinthBuildingType = 5 Event( "OSDSelect", "GameOSD:PlaySingle" ) { $gPlayerKey[DroneGameMode] = 1 // Play game music *playmusic %PLAYER% http://yyy.com/musicfile.mp3 *crowspawn %PLAYER% 128 128 Sleep( 5 ) *gocrow %PLAYER% *texteffect %PLAYER%,1,First wave incoming! Ready Up! Sleep( 20 ) CustomEvent( "StartGame" ) // Defined in LevelSpawner.mit } Event( "AccessBuilding", "$kPlayGamePlinthBuildingType" ) { osdcreate(OSDBUILDING,"GameOSD", "" ) osdadd(EXITBUTTON, 100, 80, 400, 35, "PlaySingle", "Example Single Player Game" ) osdactivate() }
All pretty standard so far. Now we get on to the good stuff..
//---------------------------------------------------------- // LevelSpawner.mit // //---------------------------------------------------------- $mSpawnPositionType = 1 // ------------------------------- // Here we're definining a 'kindof' struct thats used to specify the details of each level // Each row in our table has 7 values, and we store that in a constant $kSizeOfWavesStruct // Each row corresponds to a 'level' in the game, so if we want to access the values for level 3 // we start with the array value at 3 * $kSizeOfWavesStruct ( + 1 coz arrays are not zero-indexed _rolls_eyes_) //--------------------- $kSizeOfWavesStruct = 7 $maEnemyWaves[] = { // num2spawn(1) min lead(2) max lead(3) min speed(4) max spd(5) min acc(6) max acc(7) 2, 20, 50, 1700, 2100, 800, 100, // Wave 1 4, 30, 50, 2000, 2700, 1100, 200, // Wave 2 4, 50, 70, 2100, 2600, 1400, 1600, // Wave 3 5, 60, 70, 2300, 3000, 1100, 1400, // Wave 4 6, 80, 100, 2400, 3100, 1200, 1700, // Wave 5 7, 90, 100, 2500, 3200, 1300, 1500, // Wave 6 8, 90, 100, 2700, 3500, 1300, 1800 // Wave 7 10, 90, 100, 3000, 4000, 1200, 1900, // Wave 8 10, 90, 100, 3100, 4500, 1500, 2000, // Wave 9 } //---------------------------------------------------------------------------------------------------- // ------------------------------- // The table contains a few numbers that define a min--max range for properties of the enemies. // This function returns a random number between those ranges. // It uses the $gPlayerKey[WaveNum] to determine which level we're on and then the baseIndex tells us where in // each 'row' we should be looking. // (Of course, we could do away with all this nonsense if the script language supported more than just integer arrays, but thats for another time :] ) //--------------------- Function GetTableMinMaxVal( $baseIndex ) { $waveTable = $gPlayerKey[WaveNum] - 1 if ( $waveTable > 8 ) { $waveTable = 8 } $waveTable *= $kSizeOfWavesStruct $min = $maEnemyWaves[$waveTable+$baseIndex] $max = $maEnemyWaves[$waveTable+$baseIndex+1] $diff = $max - $min $min += sysRand( $diff ) return( $min ) } ///------------------------------------------------ // The custom StartGame event is triggered from the game access building defined separately //------------------------------------ Event( "Custom", "StartGame" ) { // Delete all entities for the current player EntityDeleteAll( $gPlayerID ); $gPlayerKey[NumEntitiesAlive] = 0 $gPlayerKey[WaveNum] = 1 $gPlayerKey[NumKills] = 0 SpawnMoreBadGuys() } ///------------------------------------------------ // SpawnMoreBadGuys // Called at the start of each 'wave'/level to trigger a new wave // of enemies //--------------------------------------------- Function SpawnMoreBadGuys( ) { $waveNum = $gPlayerKey[WaveNum] *notifylarge %PLAYER% Wave $waveNum $loop = 0 $waveTable = $waveNum - 1 $waveTable *= $kSizeOfWavesStruct $numEntitiesToSpawn = $maEnemyWaves[$waveTable+1] while ( $loop < $numEntitiesToSpawn ) { SpawnRandomHunter( 15000, 25000 ) $loop += 1 } $gPlayerKey[NumEntitiesAlive] += $numEntitiesToSpawn } //------------------------------------------------- // SpawnRandomHunter // Earlier code has determined we need an extra enemy , and it provides the min/max range where // that new enemy should appear. This function converts that range to an actual X,Y world position // and then calls the 'SpawnBadGuy' function above to add an entity //------------------ Function SpawnRandomHunter( $minrange, $maxrange ) { // Spawn somewhere randomnly near the player if ( $mSpawnPositionType == 0 ) { $spawnAngle = sysRand( 360 ) $rangeval = $maxrange - $minrange $spawnRange = sysRand( $rangeval ) $spawnRange += $minrange $spawnSin = sysSin( $spawnAngle, $spawnRange ) $spawnCos = sysCos( $spawnAngle, $spawnRange ) $xpos = $gPlayerWorldX + $spawnSin $ypos = $gPlayerWorldY + $spawnCos } else // Spawn on the edges of the Drone Shooter pitch { $side = sysRand(4) if ( $side == 1 ) { $mapPosX = 103 $mapPosY = sysRand( 50 ) $mapPosY += 103 } else if ( $side == 2 ) { $mapPosX = 153 $mapPosY = sysRand( 50 ) $mapPosY += 103 } else if ( $side == 3 ) { $mapPosX = sysRand( 50 ) $mapPosX += 103 $mapPosY = 103 } else if ( $side == 4 ) { $mapPosX = sysRand( 50 ) $mapPosX += 103 $mapPosY = 153 } $xpos = sysMapToWorld( $mapPosX ) $ypos = sysMapToWorld( $mapPosY ) } SpawnBadGuy( $xpos, $ypos ) } // ------------------------------- // SpawnBadGuy // Here we'll have some fun with entities. The calling function has worked out where to spawn a new enemy, // So here we calculate some of its properties and then create the actual entity //--- Function SpawnBadGuy( $xpos, $ypos ) { $waveNum = $gPlayerKey[WaveNum] $targetLeadPercentage = GetTableMinMaxVal( 2 ) $moveSpeed = GetTableMinMaxVal( 4 ) $moveAcc = GetTableMinMaxVal( 6 ) // Create an entity that is managed locally (i.e. is effectively just run for the one player) // with a HUNT behaviour. (This means the entity will attempt to hunt down the local player). // Note that the entity does not actually get sent to the player until we add it to the world, later in this function $mhTestEntity = EntityCreate( $gPlayerID, "LOCAL", "HUNT" ) // Note, currently all entity graphics need to be present in the game's main web content folder on the CDN EntitySetModel( $mhTestEntity, "uniRobocrow2.atm", "uniRobocrow2.jpg" ) EntitySetPosition( $mhTestEntity, $xpos, $ypos, 0 ) // Behaviour Control flags // FaceTarget = Set the entity to always to always look towards the target EntitySetValue( $mhTestEntity, "FaceTarget", 1 ) // AttackProx = Start attacking when within the ProxRange EntitySetValue( $mhTestEntity, "AttackProx", 1 ) // DieOnTargetDeath = Entity is destroyed if the target dies EntitySetValue( $mhTestEntity, "DieOnTargetDeath", 1 ) // Parameters and values // ZOffset = Vertical position offset above the ground EntitySetValue( $mhTestEntity, "ZOffset", 800 ) // ProxRange = Used to determine attack range EntitySetValue( $mhTestEntity, "ProxRange", 6000 ) $targetDist = $waveNum * 200 $targetDist += 2300 // Distance from the target the entity will try to maintain EntitySetValue( $mhTestEntity, "TargetDist", $targetDist ) // Who the target is.. EntitySetValue( $mhTestEntity, "Target", $gPlayerID ) EntitySetValue( $mhTestEntity, "Weapon", 1 ) // Basically this sets how good the entity is at aiming EntitySetValue( $mhTestEntity, "TargetLead", $targetLeadPercentage ) $health = $waveNum * 25 $health += 100 // Health = how much damage this entity can take before dieing EntitySetValue( $mhTestEntity, "Health", $health ) // Set Speed and acceleration (Determined by the level settings table) EntitySetValue( $mhTestEntity, "MoveSpeed", $moveSpeed ) EntitySetValue( $mhTestEntity, "MoveAcc", $moveAcc ) // Now all set.. add the entity to the world EntityAddToWorld( $mhTestEntity ) } ///------------------------------------------------ // Every time an entity is destroyed we update the player's kill count and decrease the // count of enemies remaining. Once that gets to 0 we start the next wave //------------------------------------ Event( "EntityDestroyed", "" ) { $gPlayerKey[NumKills] += 1 $gPlayerKey[NumEntitiesAlive] -= 1 if ( $gPlayerKey[NumEntitiesAlive] == 0 ) { $gPlayerKey[WaveNum] += 1 SpawnMoreBadGuys() } } ///------------------------------------------------ // GameEnd is triggered from RobocrowDeath Event and displays final score etc Event ("RobocrowDeath", "" ) { if ( $gPlayerKey[DroneGameMode] == 1 ) { *event %PLAYER% GameEnd } } //------------------------------------ Event( "Custom", "GameEnd" ) { *fademusic %PLAYER% 5 Sleep(10) *texteffect %PLAYER%,1,Game Over Sleep(20) $numKills = $gPlayerKey[NumKills] if ( $numKills > $gPlayerKudos ) { *setkudos %PLAYER% $numKills *announce %PLAYER% acheived a new personal best of $numKills kills ( Level $gPlayerKey[WaveNum] ) } else { *announce %PLAYER% reached level $gPlayerKey[WaveNum] with $numKills kills } }