Author Topic: Outpost 2 Coding 101: Week 6  (Read 5927 times)

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 6
« on: February 22, 2010, 07:54:04 AM »
Week 6
Creating Units (Advanced) - Hooman Never Told You What Happened To Your Cargo Trucks...

Time to cover some stuff I told you not to worry about.  This week's topics:
-Creating (and keeping track of) special units
-Putting cargo in Cargo Trucks
-Intro to AIProc
-Using AIProc to do things with special units

Remember way back in week 1 when I first taught you how to create units?
Code: [Select]
Unit x;	// Don't worry about this for now.
TethysGame::CreateUnit(x, mapCommandCenter, LOCATION(64, 64), 0, mapNone, 0);

See the part I told you not to worry about?  Well, now it's time to take a closer look at it.

Unit handles allow us to keep track of special units (if we want to).  This is useful for AI and special mission objectives.  We've already been using a generic unit handle (x) to create non-special units, but it's time to move into the big leagues.  Here are some examples:
Code: [Select]
Unit Unit1;	// From now on, we will use Unit1 as our generic unit, rather than "x", which could be anything really.
Unit advLab; // A special Advanced Lab we want to remember because an objective requires the player to scan it with a Scout.
Unit AI_VF1; // An AI-controlled Vehicle Factory.  We will need to keep track of it so the AI can produce new units with it.
Unit MustLive; // We need to keep track of this unit and fail the mission if it gets destroyed.

Now let's create all of those.
Code: [Select]
TethysGame::CreateUnit(Unit1, mapCommandCenter, ...);
TethysGame::CreateUnit(Unit1, mapGuardPost, ...);
TethysGame::CreateUnit(advLab, mapAdvancedLab, ...);
TethysGame::CreateUnit(AI_VF1, mapVehicleFactory, ...);
TethysGame::CreateUnit(MustLive, mapVehicleFactory, ...);
TethysGame::CreateUnit(Unit1, mapTokamak, ...);

See?  Not so hard.  Now let's do something with those special units.
Code: [Select]
//Use the special Advanced Lab in a trigger:
int InitProc()
{
// Create a trigger that fires if Player 1 scans the special Lab with a Scout
CreateSpecialTarget(1, 1, advLab, mapScout, "LabScanned");

...
}

SCRIPT_API void LabScanned()
{
// stuff would happen here
}
I might as well explain how CreateSpecialTarget works.
Code: [Select]
CreateSpecialTarget(Enabled/Disabled, One-time Only, Unit Handle, Triggering Unit, "Trigger Function");
I should only have to explain Unit Handle and Triggering Unit.
Unit Handle: The unit that needs to be scanned.
Trigger Unit: The type of unit that needs to scan the special unit.

Code: [Select]
//This Works But Isn't Very Useful
SCRIPT_API void BuildMoreVehicles()
{
AI_VF1.DoDevelop(mapScout);
}

Code: [Select]
//Checking if a unit is still alive
void AIProc()
{
if (MustLive.IsLive() == 0)
{
  // Create a trigger that will always evaluate to true so the player fails the mission
}
}
We'll discuss AIProc a bit more down below.

One important thing I forgot to mention is that any special units should be declared globally (put them near the top of your code file, not in InitProc or any other function).
Code: [Select]
char MapName[]  = "on6_01.map";
char LevelDesc[]  = "6P, LoS, 'Some Name'";
char TechtreeName[]  = "MULTITEK.TXT";
SDescBlock DescBlock  = { MultiLastOneStanding, 6, 12, 0 };

BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
  DisableThreadLibraryCalls(hinstDLL);
}

    return TRUE;
}

// Special Unit Handles
Unit Special1;
Unit Special2;
...

int InitProc()
{
Unit Unit1;
...
}

Next up, I'll show you how you can put cargo in Cargo Trucks.
Code: [Select]
// Let's create a truck with 1000 units of food.
TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(40+31, 30-1), 0, mapNone, 0);
  Unit1.DoSetLights(1);
  Unit1.SetTruckCargo(truckFood, 1000);

Easy, right?
Code: [Select]
Valid Cargo List:
truckEmpty  // No cargo.
truckFood  // Food
truckCommonOre  // Common Ore
truckRareOre  // Rare Ore
truckCommonMetal // Common Metal
truckRareMetal  // Rare Metal
truckCommonRubble // Common Rubble
truckRareRubble  // Rare Rubble

truckSpaceport  // Starship module/satellite
truckGarbage  // Wreckage

Note that for truckSpaceport, the cargo amount determines the starship component/satellite loaded into the truck.
Code: [Select]
//Starship parts listed by Map ID.

mapEDWARDSatellite   = 88
mapSolarSatellite    = 89
mapIonDriveModule    = 90
mapFusionDriveModule = 91
mapCommandModule     = 92
mapFuelingSystems    = 93
mapHabitatRing       = 94
mapSensorPackage     = 95
mapSkydock           = 96
mapStasisSystems     = 97
mapOrbitalPackage    = 98
mapPhoenixModule     = 99

mapRareMetalsCargo   = 100
mapCommonMetalsCargo = 101
mapFoodCargo         = 102
mapEvacuationModule  = 103
mapChildrenModule    = 104

The same thing applies for truckGarbage, except replace "starship part" with "tech the wreckage gives you".  You'll have to look in the techtree file you're using, and set the amount to the approparite tech ID.

BONUS LESSON: More stuff with units.

Here's some more things you can do to your units:
Structures:
Unit1.DoIdle();      // Idles a structure
Unit1.DoUnIdle();   // Activates a structure if it's operational requirements are met
Unit1.DoInfect();   // Forces structure to "Disabled - Infected" status.  Can only be used in maps with only one player (that player count includes AIs!)

Vehicles:
Unit1.DoAttack(Special Unit);   // Attacks the designated unit
Unit1.DoMove(LOCATION(X,Y) );   // Moves to the designated location
Unit1.DoStop();         // Stops the unit
Unit1.DoSelfDestruct();      // Forces the unit to self-destruct

Both:
Unit1.DoTransfer(Recipient);   // Trades the vehicle or structure to the designated player
Unit1.DoDeath();      // Kills the unit
Unit1.SetDamage(value);      // Remove specified amount of HP from the unit.  Note that this can result in a structure or unit having negative HP if you're not careful!

Unit1.ClearSpecialTarget();   // You know that green outline that appears around some special units?  This gets rid of that.  Use it in the response to a Special Target Trigger.

If you want to put units in a Garage at game start-up, go here.


Hmm...  That's odd.  I feel like I've forgotten something...  Oh well.


Now let's take a look at AIProc.
« Last Edit: January 11, 2017, 09:19:21 PM by Sirbomber »
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 6
« Reply #1 on: February 22, 2010, 07:54:29 AM »
Intro to AIProc - Any Mistake At This Point Will Doom You And Your Colonists To Certain Death.  Have A Nice Day!

Despite the name, AIProc doesn't necessarily have anything to do with coding an AI.  It's actually a function that OP2 automatically runs every 4 ticks.  You probably won't use it too often in a regular LoS (it might have some uses in Land Rush though; I'm still exploring this).

However, OP2 has no triggers that detect the death of a specific unit.  So, as I demonstrated above, AIProc is a good way to do that.
Code: [Select]
//Checking if a unit is still alive
void AIProc()
{
if (MustLive.IsLive() == 0)
{
  // Assume Trigger trig is defined above.  NEVER declare variables in AIProc!!!
  trig = CreateCountTrigger(1, 0, mapAny, mapAny, 0, cmpGreaterEqual, "NoResponseToTrigger");
  CreateFailureCondition(1, 0, trig, "LOL N00B");
}
}

That code will check if the special MustLive unit is still alive every 4 ticks.  If it is, nothing happens.  If the unit has died, however, that bogus trigger is created (notice that it will always be true), failing the mission immediately.

We'll do a lot more with AIProc later as we start to work on AI, so I'm not really providing any examples of things you can do with the function.  Try to think of some uses on your own though.

Anyways, we really can't do much with AIProc right now, so I guess that's it for this lesson.  Sorry!

Next week: Advanced Triggers






Hey, since the AIProc part of this lesson was short, how about I make it up to you by showing you how playlists work?
Bonus Lesson: Playlists

You'll probably need this RAR containg MP3s of the in-game music to know which music you're picking.
And you'll need the in-game music file to hear the results.

First you need to setup your playlist:
Code: [Select]
SongIds MyPlaylistName[] = { (your songs here) };

Here's each MP3 filename's corresponding code name.
Code: [Select]
// Music List
Eden & Plymouth 1 = songEP41
Eden & Plymouth 2 = songEP42
Eden & Plymouth 3 = songEP43
Eden & Plymouth 4 = songEP51
Eden & Plymouth 5 = songEP52
Eden & Plymouth 6 = songEP61
Eden & Plymouth 7 = songEP62
Eden & Plymouth 8 = songEP63
Eden 1 = songEden11
Eden 2 = songEden21
Eden 3 = songEden22
Eden 4 = songEden31
Eden 5 = songEden32
Eden 6 = songEden33
Plymouth 1 = songPlymth11
Plymouth 2 = songPlymth12
Plymouth 3 = songPlymth21
Plymouth 4 = songPlymth22 (the main menu music!)
Plymouth 5 = songPlymth31
Plymouth 6 = songPlymth32
Plymouth 7 = songPlymth33
Static 1 = songStatic01
Static 2 = songStatic02
Static 3 = songStatic03
Static 4 = songStatic04 (standard multiplayer theme)
Static 5 = songStatic05

Now here's how to use your playlist:
Code: [Select]
TethysGame::SetMusicPlayList(Total Number of Songs, Song to Start From On Repeat, Playlist Name);
Note: Remember that OP2 begins counting at zero, so if you set the repeat song to 1, you'll be skipping the first track!

Code: [Select]
//Full Example
// Setup Music
SongIds ColdWarSongs[] = { songStatic02, songPlymth12, songEP41, songEP62, songEden21, songEP51, songEP52, songEden11 };
TethysGame::SetMusicPlayList(8, 0, ColdWarSongs);

Enjoy!
« Last Edit: January 11, 2017, 09:20:32 PM by Sirbomber »
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Outpost 2 Coding 101: Week 6
« Reply #2 on: February 23, 2010, 02:31:13 AM »
Quote
One important thing I forgot to mention is that any special units should be declared globally (put them near the top of your code file, not in InitProc or any other function).

Technically, this is what ScriptGlobal/GetSaveRegions is for. You should be placing global variables inside of a global struct, and registering that struct with GetSaveRegions. If you don't put said variables in such a struct, there is no way to register their memory space with Outpost 2, and the game won't know to save them to saved game files.

I suppose you can get away with not doing this in multiplayer games as you can't save there anyway, but it's still a good habit to get into, and can make code reuse between a multiplayer game and a colony game easier.

Code: [Select]
// Define the struct format
struct ScriptGlobal
{
   // Special Unit Handles
   Unit special1;
   Unit special2;
};
ScriptGlobal scriptGlobal;  // Actually create a global instance of the struct

// ...

int InitProc()
{
   TethysGame::CreateUnit(scriptGlobal.special1, ...); // Note "scriptGlobal" prefix
   TethysGame::CreateUnit(scriptGlobal.special2, ...); // Note "scriptGlobal" prefix
   // ...
}

// ...

Export void __cdecl GetSaveRegions(BufferDesc& bufferDesc)
{
   // Buffer for Saved Game files
   bufferDesc.bufferStart = &scriptGlobal;
   bufferDesc.length = sizeof(scriptGlobal);
}

Btw, thank you for that note about DoInfect only working in single player games. I wasn't aware of that limitation before. I have just checked the code, and it does indeed have a short circuiting return if the number of players is greater than 1. I have no idea why they decided to do that though. Seems like an artifical and arbitrary limitation on that function.

Hmm.... patch?

Actually, it might have something to do with unit interface updates. Changing the currently selected units and such. Still, that can be checked for and optionally done.
« Last Edit: February 23, 2010, 02:32:33 AM by Hooman »

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 6
« Reply #3 on: February 23, 2010, 08:46:49 AM »
We're going to talk about save data and structs when we do a colony game, Hooman.

But still, not a bad idea to introduce the concept to people now I guess.
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials