Author Topic: Outpost 2 Coding 101: Week 3  (Read 9006 times)

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 3
« on: February 01, 2010, 06:35:33 AM »
Week 3
Basic Triggers and Intro to Disasters - Warning: Meteor approaching!

Outpost 2 has a whole bunch of triggers that allow you to react to various circumstances.  You'll probably never use most of them, so for now I'll just cover some of the basic, most-used triggers.

CreateOnePlayerLeftTrigger(1, 0, "Trigger Function");
This trigger fires when only one player is left in the game.  Standard LoS/LR victory condition.
Notice that I simply set the first two settings to 1 and 0, respectively.  The first setting is "enabled".  It will always be 1, since there's no sense creating a disabled trigger.  The second setting, dictates whether the trigger fires multiple times, or only once.  Set it to 1 for a one-time trigger.  Usually, however, you want the trigger to fire multiple times.

CreateTimeTrigger(1, 0, Minimum Ticks, Maximum Ticks, "Trigger Function");
This is the "interval" time trigger.  Notice that you specify a minimum and maximum amount.  The trigger will fire at a random time between the minimum and maximum time.  Note that the unit of measurement is ticks, not marks.  Ticks = marks * 100.

CreateTimeTrigger(1, 0, Time, "Trigger Function");
Same as the first time trigger, except this one always fires after a set amount of time.

I'm only explaining these few triggers for now because I'd rather tell you how triggers in general work, rather than get into the specifics of each individual trigger.  As you can see all of these have a "Trigger Function" setting.  These specify which function is called when the trigger fires.  In layman terms, you tell OP2 the name of a book and it goes and reads the book.  Note that this DOES NOT go in InitProc!

Here's an example function:
Code: [Select]
SCRIPT_API void MyTriggerCode()
{
   // Code goes here
}

Not too bad, right?  Granted, that function doesn't actually do anything, and there's no trigger that invokes it.  I'll show you a full example later, after I explain disasters.  Note that disasters have a 10-mark delay before they spawn after they are "created" to allow time for the two disaster warning messages.

Let's only look at the basic disasters for now:
Code: [Select]
TethysGame::SetEarthquake(X, Y, Strength);      // Seismic Event (quake)
TethysGame::SetLightning(originX, originY, Strength, destinationX, destinationY);   // Electrical Storm
TethysGame::SetTornado(originX, originY, Duration, destX, destY, No Delay);  // Vortex
TethysGame::SetMeteor(X, Y, Size);         // Meteor

IMPORTANT NOTE: Never, under any circumstances, set the duration of a vortex to zero!  It will result in a vortex that never dissipates (a permavortex)!!!

As you may have noticed, you'll want most of these values to be random.  Otherwise your disasters will always be in the same place and of the same strength.  Here are my recommendations for some of those values:
Any x/y position: The size of the map is a good idea; that way disasters can stike anywhere!
Code: [Select]
TethysGame::SetLightning(TethysGame::GetRand(128)+31, TethysGame::GetRand(64)-1, ...);   // Assuming the map is 128x64
Earthquake Strength: Depends on how powerful you want, but don't go above 7.  Anything higher is ridiculously destructive.
Code: [Select]
TethysGame::SetEarthquake(..., TethysGame::GetRand(7) );
Electrical Storm Strength: I recommend a maximum value of 50~60.
Code: [Select]
TethysGame::SetLightning(..., TethysGame::GetRand(55), ...);
Meteor Strength: 3 is a good value.  I don't recommend going higher than 5.
Code: [Select]
TethysGame::SetMeteor(..., TethysGame::GetRand(3) );
Vortex duration: As I mentioned, you don't want this to be zero.  So let's add a minimum value to this after we generate the random number.
Code: [Select]
TethysGame::SetTornado(..., TethysGame::GetRand(45)+10, ... );

Okay, so now we've got all kinds of disasters all over the map.  There's just one problem: we have the pieces, but they're not arranged properly!  You should be able to figure out how to do this yourself.  If you want to try doing it on your own, that'd be amazing!  If you can't though, the solution is posted below.



Code: [Select]
// Setup the triggers in InitProc:
int InitProc()
{
   // Code from previous lessons here

   // Disaster Time Triggers
   TethysGame::CreateTimeTrigger(1, 0, 1200,  4300, "Quakes");   // Earthquake trigger
   TethysGame::CreateTimeTrigger(1, 0, 5600, 12700, "Vortex");   // Vortex trigger
   TethysGame::CreateTimeTrigger(1, 0, 3900,  9800, "Storms");   // Electrical Storm trigger
   TethysGame::CreateTimeTrigger(1, 0, 2300,  5100, "Meteor");   // Meteor trigger

   // Some more code may or may not be here
}

void AIProc()
{
   // We'll talk about AIProc later
}



// ---------- Define the trigger functions here ----------

// Quakes
SCRIPT_API void Quakes()
{
   TethysGame::SetEarthquake( TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1, TethysGame::GetRand(4) );
}

// Vortexes (Vortices?)
SCRIPT_API void Vortex()
{
   TethysGame::SetTornado( TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1, TethysGame::GetRand(20)+10, TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1 );
}

// Electrical Storms
SCRIPT_API void Storms()
{
   TethysGame::SetLightning( TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1, TethysGame::GetRand(25), TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1 );
}

// Meteors
SCRIPT_API void Meteor()
{
   TethysGame::SetMeteor( TethysGame::GetRand(128)+31, TethysGame::GetRand(128)-1, TethysGame::GetRand(3) );
}

// ---------- End of trigger functions ----------

Notice how we deal with x/y offset after we generate a random value.

You should play around with the various disaster settings.  Try to figure out settings you like!

One last thing: What if disasters are disabled?
Code: [Select]
if(TethysGame::CanHaveDisasters() == 1)
{
   // All triggers that spawn disasters go here
}

There you have it!  As always, feel free to post results, questions, and comments!

Next week: More Disasters; Victory and Defeat















BONUS LESSON: THE BLIGHT IS APPROACHING!

This is gonna be one of those triggers you don't want repeated!
Code: [Select]
CreateTimeTrigger(1, 1, 1000, "Blight");

SCRIPT_API void Blight()
{
   // Setup Blight
   GameMap::SetVirusUL(LOCATION(8+31, 19-1), 1);  // Spawn the Blight
   TethysGame::SetMicrobeSpreadSpeed(60);     // Set the Blight's spread speed

   // Warning Message
   TethysGame::AddMessage(1248, 576, "Microbe growth detected!", -1, 152);
}

AddMessage is needed because the Blight isn't a "normal" disaster and no warning message is played when it spawns.  So be sure to warn people if you use it!  Or not... :evil laugh:  For those curious about AddMessage:
TethysGame::AddMessage(X*32, Y*32, "Message", Receiving Player, Sound ID);
The x/y values allow you to "jump" to a specific location.  The values must be multiplied by 32 (or set them to -1 to disable jumping).  The rest is fairly self-explanitory.  A list of sounds can be found in the EnumSoundId.h file in your SDK's Include directory.

Okay, that's it.

2020 update: Check out my Disaster Creator, which makes it significantly easier to add all kinds of disasters (including volcanoes!) to your levels!
« Last Edit: May 21, 2020, 04:20:40 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 AmIMeYet

  • Full Member
  • ***
  • Posts: 128
Outpost 2 Coding 101: Week 3
« Reply #1 on: February 01, 2010, 09:49:07 AM »
Hm.. do the X and Y of disasters need the same +31,-1 added as structures do?
Also, I find it weird and quite frankly bad style that TethysGame::DistasterFunc(X, Y, Size) is used instead of TethysGame::DistasterFunc(LOCATION(X,Y), Size) .. the latter is more consistent and therefore, in my opinion, better. ..it's irrelevant though..

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Outpost 2 Coding 101: Week 3
« Reply #2 on: February 01, 2010, 10:38:36 AM »
Yes AmIMeYet, they do.

Quote
Ticks = marks * 100
To clear thing up for those of us who may understand 2 opposite things from this line: 1 mark = 100 ticks. (Yes, the true meaning of the equation did strike me soon after reading it, but it was not the first thing that came to mind)


Might be worth pointing out that even if you use an interval time trigger, once it picks a value, it will fire with the same value until disabled or destroyed. Not easily noticeable, I guess, but I did notice that my disasters would just come back every x intervals when I first tried, where x never changed, unless I restarted the level.
« Last Edit: February 01, 2010, 10:47:49 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline CK9

  • Administrator
  • Hero Member
  • *****
  • Posts: 6226
    • http://www.outpost2.net/~ck9
Outpost 2 Coding 101: Week 3
« Reply #3 on: February 01, 2010, 10:38:39 AM »
Are volcanic eruptions not considered disasters in OP2 coding, or is that next week?
CK9 in outpost
Iamck in runescape (yes, I still play...sometimes...)
srentiln in minecraft (I like legos, and I like computer games...it was only a matter of time...) and youtube...
xdarkinsidex on deviantart

yup, I have too many screen names

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 3
« Reply #4 on: February 01, 2010, 12:40:24 PM »
Quote
Are volcanic eruptions not considered disasters in OP2 coding, or is that next week?
Quote
Next week: More Disasters; Victory and Defeat

Next week.  You need to prep the map for a volcanic eruption, otherwise nothing happens.  It's kind of a pain, especially when OP2 doesn't feel like doing it right.

Anyways, don't worry about that yet.

Hidiot: You raise a good point, so for clarification:
1 mark = 100 ticks
So if you want a Time Trigger to fire at mark 145, here's the equation:
ticks = marks * 100
ticks = 145 * 100
ticks = 14500

AmIMeYet: ALL X/Y coordinates, unless otherwise stated, must have the +31/-1 offset (-1/-1 for world maps).
"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 3
« Reply #5 on: February 02, 2010, 12:44:37 AM »
You might want to check those offsets for the random location of your disasters.

Also, some disaster strength values have more specific meanings, like small, medium, and large. Anything outside the values of 0, 1, 2 may very well produce undefined behavior. I believe the meteor strength is an example of that. Other disasters seem to have their duration set by the "strength" value.

Also, you should be able to use the EnumSoundId.h named constants instead of just copying the values out of there. Granted a lot of the names suck. Maybe they should be updated with alternate names.


Btw, you can shorten this check, by removing the "== 1" part.
Code: [Select]
if(TethysGame::CanHaveDisasters() == 1)
In C/C++, any non-zero value is considered true. In fact, consider how your code would behave if a value of 2 was ever returned. Technically, any non-zero value should be true, but with a comparison like that, it would be treated like disasters are set to false. You should avoid doing direct comparisons against a "true" value. Actually, you should avoid doing a direct comparison against anything where a single meaning can be multivalued. If you do that, then only one of the values will have the intended meaning.

You should try to write your conditions more of the form
Code: [Select]
if (booleanExpression)
if (!booleanExpression)
Avoid comparing against true/false values.
 

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 3
« Reply #6 on: February 02, 2010, 07:24:44 AM »
Hooman, I appreciate the input, but this guide is not for people who know (and presumably don't want to know) a lot of C/++.  I'm trying to make this accessible to people who have never written a line of code in their life.  So rather than go into in-depth explanations of the various ways you can check if a boolean is true or not, I'm just telling people "do this" and I'm afraid that if you launch into a full-fledged lecture on programming conventions you'll scare people off.  While I know that comparing CanHaveDisasters to 1 and hoping OP2 didn't return some other value is a bad idea, it will be important in later lessons; now when we need to do other comparisons I can say "remember when we did if (TethysGame::CanHaveDisasters() == 1)?  Well, it's just like that!".

And I'll fix the lack of offsets for the random disaster code.
"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 Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Outpost 2 Coding 101: Week 3
« Reply #7 on: February 02, 2010, 08:14:18 AM »
Using as little code as possible and keeping it as tidy as possible is also a very important consideration when the .dll (code) file grows in detail. More so, the concepts of code tidiness and efficiency are pretty important for any kind of programing.
"Nothing from nowhere, I'm no one at all"

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 3
« Reply #8 on: February 02, 2010, 08:31:41 AM »
Tch, fine.  You both win.  I'll be careful in all future tutorials and examples.
"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 3
« Reply #9 on: February 04, 2010, 01:06:40 PM »
So, how are people doing?

Enjoying the tutorials so far?

Do you find them useful?

Nobody's posted any DLLs, so I don't know how people are doing.

I'll post Week 4 Sunday evening/night or Monday morning.
"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 AmIMeYet

  • Full Member
  • ***
  • Posts: 128
Outpost 2 Coding 101: Week 3
« Reply #10 on: February 04, 2010, 02:23:17 PM »
If I had the time I'm sure I'd be doing great.
School's just bugging me for the next couple of months.
Haven't even got VC installed, lol.

The tutorials are great though. Easy to follow.

Offline CK9

  • Administrator
  • Hero Member
  • *****
  • Posts: 6226
    • http://www.outpost2.net/~ck9
Outpost 2 Coding 101: Week 3
« Reply #11 on: February 04, 2010, 05:50:03 PM »
I don't have any of my personal maps finished, or else I'd be working on .dll's

However, so far the tutorials are explaining a lot that left me confused from the old wiki pages :)
CK9 in outpost
Iamck in runescape (yes, I still play...sometimes...)
srentiln in minecraft (I like legos, and I like computer games...it was only a matter of time...) and youtube...
xdarkinsidex on deviantart

yup, I have too many screen names

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Outpost 2 Coding 101: Week 3
« Reply #12 on: February 04, 2010, 06:16:42 PM »
Quote
I don't have any of my personal maps finished, or else I'd be working on .dll's
You should practice on the stock Dynamix maps so you can work out any problems you may have when you code for your own maps.  Practice makes perfect and all.
"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 CK9

  • Administrator
  • Hero Member
  • *****
  • Posts: 6226
    • http://www.outpost2.net/~ck9
Outpost 2 Coding 101: Week 3
« Reply #13 on: February 04, 2010, 06:47:55 PM »
Aye, but you find the problems on your own maps just as easily :P

When I have enough time agian (probably will next quarter based on what I have left to take, lol) I'll probably do a little coding
CK9 in outpost
Iamck in runescape (yes, I still play...sometimes...)
srentiln in minecraft (I like legos, and I like computer games...it was only a matter of time...) and youtube...
xdarkinsidex on deviantart

yup, I have too many screen names