Update 6DEC: Added a version # to top of DisasterHelper.h. Now of version 1.0. See attached .zip file that contains .cpp/.h for newest code.
I finished a
polished final draft of the DisasterHelper class. I'm happy to receive feedback on the mess, but since it is about 400 lines of code, I understand if people do not want to read through it. I'll be passing it off to Dave for use if he still wants it in his multiplayer rebalancing scenarios, so it would be easier change things now before that happens.
Due to limits on how functions are passed to Triggers, you cannot directly pass the function CreateRandomDisaster from DisasterHelper to an Outpost 2 Trigger function. However, you can simply wrap the function and then pass it without problem. See the initialization example below on what I mean.
If using this code in a single player scenario, you must ensure DisasterHelper is initialized after a game is re-loaded. This is best done by calling DisasterHelper.MapPropertiesSet(). If this is false, then you need to re-initialize it before calling. Not initializing the class before calling will not crash the game, it will just cause disasters to not be created when called for.
DebuggingIn Visual Studio (or another IDE), if you leave the Solution Configuration in Debug mode instead of release mode, DisasterHelper will send warning messages via the in game chat console. In particular warnings about not initializing the class, not being able to find a LOCATION outside of a safe area, trying to create a vortex without first setting a VortexCorridor (MAP_RECT), or setting innapropriate duration/strength values are sent.
How to use it:Below are three examples of how to integrate DisasterHelper into a scenario. They will all get disasters on the map in a reasonable manner. A lot more properties of DisasterHelper can be set if you want to massage them, such as disaster duration, disaster strength, percent chance of each disaster, etc. The default values should be noticeable without being too powerful.
Single Player (Colony Game) ConcernsIf you use DisasterHelper in a colony game, you have to place your triggers in ScriptGlobal and do the rest of the requirements to ensure it is available for use between Saves/Loads of the scenario. When saving/loading the scenario, the class DisasterHelper will not retain its settings. The code below checks if DisasterHelper is not initialized every time CreateRandomDisaster is called to ensure the class data is restored after a load.
Since multiplayer scenarios cannot be saved/loaded, If you are designing a multiplayer scenario, you can disregard placing the trigger in ScriptGlobal and just initialize DisasterHelper in the function InitProc and not worry about checking if its properties are set later.
Example 1: Pairing DisasterHelper with BaseHelper in a multiplayer scenario. Safe Areas set Manually.#include "DisasterHelper.h"
DisasterHelper disasterHelper;
//Shows setting up 4 base locations for a 4 player LoS game.
//Base starting locations are randomized.
int playerSlots[] = { 0, 1, 2, 3 };
const MAP_RECT baseSafeRects[] = {
{ 10 + X_, 10 + Y_, 30 + X_, 30 + Y_ },
{ 100 + X_, 10 + Y_, 30 + X_, 30 + Y_ },
{ 10 + X_, 100 + Y_, 30 + X_, 30 + Y_ },
{ 100 + X_, 100 + Y_, 30 + X_, 30 + Y_ },
};
Export int InitProc()
{
disasterHelper.SetMapProperties(256, 64, false); //MapWidth, MapHeight, Does map wrap East/West
RandomizeList(AutoSize(playerSlots));
for (int i = 0; i < TethysGame::NoPlayers(); i++)
{
// Create bases loop
CreateBase(i, startLocation[playerSlots[i]]); // See BaseHelper.h for documentation on creating startLocation array.
// Loop to create safe rects
disasterHelper.AddSafeRect(baseSafeRects[playerSlots[i]]);
}
CreateTimeTrigger(true, false, 1500, 3500, "CreateDisaster"); //Set time in ticks (marks / 100)
}
Export void CreateDisaster()
{
disasterHelper.CreateRandomDisaster();
}
Example 2: Auto find Command Centers and add MAP_RECTs of a pre-determined size to DisasterHelper. Designed for a use in a multiplayer scenario.#include "DisasterHelper.h"
DisasterHelper disasterHelper;
Export int InitProc()
{
disasterHelper.SetMapProperties(256, 64, false); //MapWidth, MapHeight, Does map wrap East/West
AutoSetBaseSafeRects(30, 30);
CreateTimeTrigger(true, false, 1500, 3500, "CreateDisaster"); //Set time in ticks (marks / 100)
}
// Places a safeRectangle centered on all command centers currently in game.
void AutoSetBaseSafeRects(int safeAreaWidth, int safeAreaHeight)
{
for (int i = 0; i < TethysGame::NoPlayers(); i++)
{
PlayerBuildingEnum playerBuildingEnum(i, map_id::mapCommandCenter);
Unit unit;
while (playerBuildingEnum.GetNext(unit))
{
LOCATION loc = unit.Location();
MAP_RECT safeRect = MAP_RECT(loc.x - safeAreaWidth / 2, loc.y - safeAreaHeight / 2, loc.x + 30, loc.y + 30);
disasterHelper.AddSafeRect(safeRect);
}
}
}
Export void CreateDisaster()
{
disasterHelper.CreateRandomDisaster();
}
Example 3: Use DisasterHelper in a colony game scenario where dealing with Saving/Loading games must be taken into account.#include "DisasterHelper.h"
DisasterHelper disasterHelper;
Export int InitProc()
{
scriptGlobal.DisasterTimeTrig = CreateTimeTrigger(true, false, 1500, 3500, "CreateDisaster"); //Set time in ticks (marks / 100)
}
Export void CreateDisaster()
{
if (!disasterHelper.MapPropertiesSet())
{
disasterHelper.SetMapProperties(256, 64, false); //MapWidth, MapHeight, Does map wrap East/West
disasterHelper.AddSafeRect(MAP_RECT(10 + X_, 10 + Y_, 30 + X_, 30 + Y_));
}
disasterHelper.CreateRandomDisaster();
}
The Actual CodeThe header and CPP file for DisasterHelper are attached in a ZIP file. Beyond Outpost 2 they depend on vector, cmath and climits. You need a C++11 compliant compiler, but that should be pretty standard now (I think?). This code is currently contained in the repository at
https://svn.outpostuniverse.org:8443/!/#outpost2/view/head/LevelsAndMods/trunk/Levels/RescueEscort. I'm using the scenario RescueEscort to test it, although this scenario is far from being completed I'm ensuring RescueEscort always compiles/runs fine when committing to it.
*
Note: You may need to login with an Outpost Universe Forum Account to see the attachment.