Dynamic Scenarios

Dynamic Scenarios are Scenarios that contain custom behavior that you program in the ProcessImpulse method.  The ProcessImpulse method is executed every Impulse of the game by the host player in a MultiPlayer game.

The Scenario class contains a property called DynamicEvents, which is an IDynamicEvents interface type.  This interface contains a set of methods that you can call to perform dynamic actions within a game.  These actions are communicated to other players in a MultiPlayer game.  For example, you could move the first player's Capital StarSystem one square to the left by using the RelocateObject method:

StarSystem capital = Game.Players[0].Capital;
DynamicEvents.RelocateObject(capital, capital.X - 1, capital.Y);

Warning: Do not modify any game state without using a DynamicEvents method!  If you do, the changes will not propagate to others in a Multiplayer game.

public virtual void ProcessImpulse(int impulse)
SV5 calls this method in the host player's Scenario object on every Impulse.  Within your implementation of this method, you can examine the internal game state by using the Game property, which returns an instance of the SVGame class.  This class contains all of the internal state of the game, including lists of StarShip objects (the StarShips property), StarSystem objects (the StarSystems property) and the ability to examine the map (GetTerrain and GetObjectAt methods).  Use Visual Studio Intellisense to examine the various public properties and methods available in the Game object.  If you have questions about how to locate a specific piece of game state information, please post it to the Silicon Commander Games message board.

DynamicEvents property

The DynamicEvents property contains the following methods that you can call within ProcessImpulse.  They allow you to modify various elements in the game to create truly dynamic Scenarios.

Example:

//Any StarShips in this area move randomly 1 square
Rectangle noMansLand = new Rectangle(50, 50, 10, 10);
foreach(StarShip ship in Game.StarShips)
   if (noMansLand.Contains(ship.Location))
   {
      int x = Random(-1, 1);
      int y = Random(-1, 1);
      DynamicEvents.MoveStarShip(ship, ship.x + x, ship.y + y);
   }

public void AdjustShipValues(StarShip ship, int engines, int maxEngines, int value, int maxValue, bool repsectFixedValues)
Adjusts the current, and maximum, engine and primary system values for the specified StarShip.  If respectFixedEngineValues is false, the method even allows you to override the normal fixed engine values of StarShips (such as the E1 Emines) and assign "values" to StarShips that normally don't have them (like Drones).  See the HighEnergy.cs Scenario for an example.

public void AdjustStarSystemValues(StarSystem system, int value, int scanners, int shields, int resources)
Adjusts the Value, Scanners, Shields, and Resources of a specified StarSystem.  You can pass a -1 to any of these parameters if you do not want them to be adjusted.

public BlackHole CreateBlackHole(int x, int y, int radius)
Creates a new BlackHole on the map at the specified location.  The "radius" parameter indicates how close StarShips need to get before getting pulled toward the BlackHole.

public void CreateExplosion(int x, int y, int particles, Color startColor, Color endColor, int startDiam, int endDiam, int lifeSpan)
Produces an explosion on the map, and optionally plays an explosion sound.  The explosion is particle-based, and you control the various aspects of it via the parameters.  The number of particles in the explosion is determined by the "particles" parameter.  Each particle will be a random color ranging from "startColor" to "endColor".  Note that you can apply alpha values to "startColor" and "endColor" to get more interesting effects (for example, Color.FromArgb(20, Color.Black) for "startColor" and Color.FromArgb(255,Color.Red) for "endColor".)  Each particle is a random size in pixels between "startDiam" and "endDiam".  The explosion's life span is controlled by the "lifeSpan" parameter, expressed in animation cycles.

public Pulsar CreatePulsar(int x, int y)
Creates a new pulsar on the map.

public StarShip CreateStarShip(int x, int y, Player owner, StarShipType shipType, int engines, int extra, bool cloaked)
Creates a new StarShip on the map at the specified location.

public StarSystem CreateStarSystem(int x, int y, int value, int shields, int scanners, double resources)
Creates a new StarSystem at the specified location with the specified properties.  You can change aspects of the StarSystem further by modifying its properties, such as Name, BonusShipType and BonusValue.

UDO CreateUDO(string name, int x, int y, string imageName, bool autoPickup, bool ignoreBlackHoles, bool isTaggable, int frameCount, int frameDelay, bool randomizeFrames, bool randomizeDelay)
Allows you to create a new UDO during the game.  All of the UDO properties are contained in parameters of this method.  Remember, you cannot change a UDO's properties after it is created, although you can move it or relocate it using the MoveUDO or RelocateObject methods.

public Wormhole CreateWormhole(int x, int y, int destX, int destY)
Creates a new Wormhole on the map, with the specified location and destination point.

public void DamageStarShip(StarShip ship, int damage)
Inflicts damage to a StarShip in the amount specified in the "damage" parameter.  Will destroy the StarShip if Engines or Primary System falls below zero.  This is the preferred method for reducing a StarShip's strength, although you can also AdjustStarShipValues, and not get the explosive effect.

public void DestroyStarShip(StarShip ship)
Destroys the specified StarShip outright.

public void DisplayMessage(string msg)
Displays a Scenario message on the map the the player will have to clear by clicking an OK button.  You should only call this method on a specific numeric Impulse, or when a specific event occurs that will not be repeated.  Otherwise, the message will continually appear on top of the map.

void EjectUDO(StarShip ship, UDO udo)
Causes the specified StarShip to eject the specified UDO it is carrying.

public void MoveStarShip(StarShip ship, int x, int y)
Causes a StarShip to smoothly move toward the specified destination.

void MoveUDO(UDO udo, int x, int y)
Causes a UDO to smoothly move toward the specified destination.

void PickUpUDO(StarShip ship, UDO udo)
Causes the specified StarShip to pick up the specified UDO.

public void RelocateObject(SVMapObject svm, int x, int y)
Use this method to re-position an object on the map.  The SVMapObject is the base class for objects that can be found on the map.  The following classes are derived from SVMapObject: StarShip, StarSystem, BlackHole, Wormhole, Pulsar, and UDO.

public void RemoveObject(SVMapObject svm)
Removes an object from the map.  SVMapObject is a base class that all map objects descend from, including StarShips, StarSystems, Pulsars, BlackHoles, Wormholes, and UDOs.  So, you can pass any of these objects into this method to remove them from play.

public void SetBlackHoleRadius(BlackHole bh, int radius)
Allows you to dynamically change the radius of a BlackHole.

public void SetTerrain(int x, int y, char terrain)
Allows you to change terrain on the map dynamically.  The current supported terrains are an empty space (' ') for clear terrain, and 'N' for Nebula.

Passing Scenario Information to other Players

In MultiPlayer games it can be important to properly synchronize data needed in the ProcessImpulse method with the clients in the game.  Only the game's "host" player gets the ProcessImpulse called every Impusle, and communicates any dynamic changes to other players via the DynamicEvents methods.  If the host player is eliminated, then one of the other players assumes the role of the host.  If the Scenario relies on variables initialized during the BuildScenario method, or previous calls to ProcessImpulse, then the new host will be "out of synch" and the Scenario may not work correctly after the transition.

To avoid this, you should pass required information to the other players by calling SetValue (see Scenario Programming for details of this method.)  Each required piece of information should be encoded in a string and persisted with a SetValue call.  You can also call SetValue during a game from within the ProcessImpulse method, the values will be communicated to other players.

When another player joins the game, their Scenario object calls PostLoadInitialize, instead of BuildScenario.  Within PostLoadInitialize, you can call GetValue to read the values that were communicated from the game host's calls to SetValue.  In this way you can ensure that the game clients are passed any required information that was determined in the host's BuildScenario method.

The Scenario PsiWars.cs uses this mechanism to flag which StarSystems give birth to RemoteViewers.  In the Scenario code, this information is read by the clients in the PostLoadInitialize method so they can update their internal data structures.  If the host player is eliminated, one of the clients will assume the role of the host and have the correct data ready when their ProcessImpulse calls happen.