From time to time, sophisticated missions that manage moving objects like ships will receive "MissionChronoMilestone" updates from the MissionCommander. These missions need to check for arrival of these messages frequently. Here is some sample source code for that task:
Several of our new, sample missions include code like that. You will find it inserted into the block of mission code that gets executed 10 times per second (previously that little block of code had been used only to rotate the RADAR antenna).
As you can see, that code consults the externally managed "MissionChronoMilestone" variable and compares it with the locally updated "PriorChronoMilestone" variable. If they are not identical, then it knows that a new MissionChronoMilestone has been received by LAC's network logic external to our mission code, and it takes steps to display appropriate progress text on the cockpit's "SystemMessagePanel", it vocalizes "Mission State change detected", and it updates "PriorChronoMilestone" with the updated value of "MissionChronoMilestone" to prevent repeated triggering of this logic until a new value of "MissionChronoMilestone" is received.
More sophisticated missions will add more logic at that point to update any relevant timers and to move, re-orient, and reconfigure any affected mission objects according to hard-coded data associated with the value of MissionChronoMilestone. Take a look at the source code for MissionNetworkBattle07.cpp for a working example. Just search for this line of code to find the right area:
switch (MissionChronoMilestone)
All of this is done to ensure that remote players become synchronized with the corresponding objects of the MissionCommander, even if one or more of them enters the mission long after others have been advancing them forward through mission logic. Each of the ten cases of the big "switch" statement at the end of that listing handles receipt of one of the ten MissionChronoMilestone values, and, if Legacy Mission Mobile objects have moved since the prior MissionChronoMilestone, additional code must be inserted in each case, to update attributes or affecting any and all mission objects that are known to change at the corresponding MissionChronoMilestone. (Several of our sample missions already do all of this. See MissionNetworkBattle07.cpp for example.)
By way of illustration, let's assume that the mission design assigns a RedTeam Battleship as ThreeDObject[15] and determines that when the mission's timers advance to a point we define as "MissionChronoMilestone 1", its XZ Position is 420.0, 955.2, and that it is headed directly East (for a compass heading of 90 degrees). We would then be expected to insert code like this into "case 1" to correspond with receipt of a message declaring arrival at MissionChronoMilestone 1:
case1:
{
////Getherewithin100msofreceiptofaMorseCodemessagealertingus//oftheneedtoimmediatelyupdatetheposition, orientation, velocity,
//durability, oranyotherattributesofanyandallmissionobjectsthat//changeasaresultofthemission's design upon reaching//MissionChronoMilestone1.
//ThreeDObjects[15]->tl->x=420.0; // Move object 15 to X 420.0ThreeDObjects[15]->tl->z=955.2; // Move object 15 to Z 955.2ThreeDObjects[15]->phi=90; // Change object 15 compass heading to 90.break;
}
Within that same "case 1" block, the updated position of any other Mobile Mission Objects at MissionChronoMilestione 1 would be updated according to that same pattern. (Note that the "y" position of any ship is always unchanged, since ships are always at Sea Level. Same for gamma (climb angle), and theta, since surface ships don't climb or dive or roll very much unless under tremendous stress.)
Other "case" blocks would be coded according to that same pattern, but updating positions and compass headings according to the mission's plan for subsequent MissionChronoMilestones. The source code for MissionNetworkBattle07.cpp is a great resource for more sophisticated use of these concepts.
To make all of this work properly, new Mission Designers must put together a master logistics plan for each mission. This plan must determine three fundamental mission design parameters. They are:
1 of 3: The number of "MissionStates". All of our sample missions have timers that advance through 201 of these states, defined as a global variable named MissionStateNetworkBattle advances from "0" through "201". Most of the existing timers advance from state to state every ten seconds. That arrangement will probably work for most missions without any big changes.
2 of 3: The position of ten "MissionChronoMilestones" among those "MissionStates". As many as ten times during the mission, existing logic can be called upon to synchronize the position of all mission objects among all players, even if some of them have been participating in the mission for a long time but others have just joined. Unless the Mission Designer identifies disruptive events of an unusual nature, it generally works out well to separate MissionChronoMilestones by about twenty MissionStates. All of the sample missions activate MissionChronoMilestone #1 at MissionState 15, MissionChronoMilestone #2 at MissionState 20, MissionChronoMilestone #3 at MissionState 40, MissionChronoMilestone #4 at MissionState 60, and the remaining six MissionChronoMilestones according to that same advancing pattern, at MissionStates 60, 80, 100, 120, 140, 160, and 180. That arrangement will probably work for most missions without any big changes.
3 of 3: The XYZ Positions and orientations of all Mobile Mission Objects at each of the ten MissionChronoMilestones. For example, all of the sample missions that have a moving Aircraft carrier have code like this:
As you can see, that code implements a big table of floating-point variables with descriptive names referencing the XZ position and "phi" orientation (compass heading) for aircraft carriers, in Mission 07, at each of ten MissionChronoMilestones.
The specific position and orientation values listed above assume that the aircraft carriers are cruising along, at medium speeds, in a big, lazy circle. At the time of this writing in early July of 2020, all of the sample missions with aircraft carriers follow that mission design, and simple code in every MissionState designates a new compass heading to perfect that circular course.
If your mission design requires more complex navigation, you will need to build your own table of floating-point numbers, like the one above, but with different XZ positions and different "Phi" compass headings.
All of the sample missions have ten nearly identical blocks of special code in them (one block in each of the ten MissionChronoMilestone handlers) to help you with that task, but all of that code is normally "commented out", because it is only used during mission development (in order to capture the floating-point data needed to build the table shown above). To find an example for your study, look for blocks of code like this in the sample missions:
//
// FOR EARLY DEVELOPMENT WORK, It is necessary to capture the exact position of moving
// aircraft carriers (and any other moving objects) as soon as the mission advances to
// MissionChronoMilestone 3. We do that during development here, and later on we will
// use the resulting XZ positions as hard-coded data upon receipt of MissionChronoMilestone
// #3 messages from a MissionCommander.
//
/
* The following eleven lines of code may or may not be commented out because they were only used during
* development use, to capture the referenced values at the moment of MissionChronoMilestone #3.
* We are retaining the commented-out code block for future reference, but NOT for ordinary
* use:
RedTeamCarrier07XPositionAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->tl->x;
RedTeamCarrier07ZPositionAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->tl->z;
RedTeamCarrier07PhiAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->phi;
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07XPositionAtMilestone3 = %f", RedTeamCarrier07XPositionAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07ZPositionAtMilestone3 = %f", RedTeamCarrier07ZPositionAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07PhiAtMilestone3 = %f", RedTeamCarrier07PhiAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer()b: MissionStateNetworkBattle = %d", MissionStateNetworkBattle);
display (DebugBuf,LOG_MOST); /
At some point during your work to perfect a new mission involving more complex navigation, after you hard-code logic that moves your ships or other Mobile Mission Objects around the way you want them, you will activate all ten blocks of that code, causing it to calculate the XZ position and orientation of your ship(s) at each of the ten MissionChronoMilestones. The resulting data is stored in LAC's log file, which you can always find at ~home/.LAC/logfile.txt. After taking that step you must copy the resulting data from the log file into your source code according to the pattern shown in the table above. Then you can return those ten code blocks to their de-activated state, since you won't be needing them anymore.
If the remaining code of your new mission follows the existing patterns as documented in our samples, your ships will move around on the map according to your mission design and will synchronize their positions with one another. It shouldn't be necessary for you to change the logic of mission flow at all. Just follow the existing pattern that we have used for our moving aircraft carriers. If you decide to add other Mobile Mission Objects, you will need to add corresponding, additional logic and expand the sample data tables, but you can simply duplicate the existing pattern and make up your own descriptive names for any new variables that your new objects may demand.
Last edit: bbosen 2020-07-13
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
From time to time, sophisticated missions that manage moving objects like ships will receive "MissionChronoMilestone" updates from the MissionCommander. These missions need to check for arrival of these messages frequently. Here is some sample source code for that task:
Several of our new, sample missions include code like that. You will find it inserted into the block of mission code that gets executed 10 times per second (previously that little block of code had been used only to rotate the RADAR antenna).
As you can see, that code consults the externally managed "MissionChronoMilestone" variable and compares it with the locally updated "PriorChronoMilestone" variable. If they are not identical, then it knows that a new MissionChronoMilestone has been received by LAC's network logic external to our mission code, and it takes steps to display appropriate progress text on the cockpit's "SystemMessagePanel", it vocalizes "Mission State change detected", and it updates "PriorChronoMilestone" with the updated value of "MissionChronoMilestone" to prevent repeated triggering of this logic until a new value of "MissionChronoMilestone" is received.
More sophisticated missions will add more logic at that point to update any relevant timers and to move, re-orient, and reconfigure any affected mission objects according to hard-coded data associated with the value of MissionChronoMilestone. Take a look at the source code for MissionNetworkBattle07.cpp for a working example. Just search for this line of code to find the right area:
switch (MissionChronoMilestone)
All of this is done to ensure that remote players become synchronized with the corresponding objects of the MissionCommander, even if one or more of them enters the mission long after others have been advancing them forward through mission logic. Each of the ten cases of the big "switch" statement at the end of that listing handles receipt of one of the ten MissionChronoMilestone values, and, if Legacy Mission Mobile objects have moved since the prior MissionChronoMilestone, additional code must be inserted in each case, to update attributes or affecting any and all mission objects that are known to change at the corresponding MissionChronoMilestone. (Several of our sample missions already do all of this. See MissionNetworkBattle07.cpp for example.)
By way of illustration, let's assume that the mission design assigns a RedTeam Battleship as ThreeDObject[15] and determines that when the mission's timers advance to a point we define as "MissionChronoMilestone 1", its XZ Position is 420.0, 955.2, and that it is headed directly East (for a compass heading of 90 degrees). We would then be expected to insert code like this into "case 1" to correspond with receipt of a message declaring arrival at MissionChronoMilestone 1:
Within that same "case 1" block, the updated position of any other Mobile Mission Objects at MissionChronoMilestione 1 would be updated according to that same pattern. (Note that the "y" position of any ship is always unchanged, since ships are always at Sea Level. Same for gamma (climb angle), and theta, since surface ships don't climb or dive or roll very much unless under tremendous stress.)
Other "case" blocks would be coded according to that same pattern, but updating positions and compass headings according to the mission's plan for subsequent MissionChronoMilestones. The source code for MissionNetworkBattle07.cpp is a great resource for more sophisticated use of these concepts.
To make all of this work properly, new Mission Designers must put together a master logistics plan for each mission. This plan must determine three fundamental mission design parameters. They are:
1 of 3: The number of "MissionStates". All of our sample missions have timers that advance through 201 of these states, defined as a global variable named MissionStateNetworkBattle advances from "0" through "201". Most of the existing timers advance from state to state every ten seconds. That arrangement will probably work for most missions without any big changes.
2 of 3: The position of ten "MissionChronoMilestones" among those "MissionStates". As many as ten times during the mission, existing logic can be called upon to synchronize the position of all mission objects among all players, even if some of them have been participating in the mission for a long time but others have just joined. Unless the Mission Designer identifies disruptive events of an unusual nature, it generally works out well to separate MissionChronoMilestones by about twenty MissionStates. All of the sample missions activate MissionChronoMilestone #1 at MissionState 15, MissionChronoMilestone #2 at MissionState 20, MissionChronoMilestone #3 at MissionState 40, MissionChronoMilestone #4 at MissionState 60, and the remaining six MissionChronoMilestones according to that same advancing pattern, at MissionStates 60, 80, 100, 120, 140, 160, and 180. That arrangement will probably work for most missions without any big changes.
3 of 3: The XYZ Positions and orientations of all Mobile Mission Objects at each of the ten MissionChronoMilestones. For example, all of the sample missions that have a moving Aircraft carrier have code like this:
As you can see, that code implements a big table of floating-point variables with descriptive names referencing the XZ position and "phi" orientation (compass heading) for aircraft carriers, in Mission 07, at each of ten MissionChronoMilestones.
The specific position and orientation values listed above assume that the aircraft carriers are cruising along, at medium speeds, in a big, lazy circle. At the time of this writing in early July of 2020, all of the sample missions with aircraft carriers follow that mission design, and simple code in every MissionState designates a new compass heading to perfect that circular course.
If your mission design requires more complex navigation, you will need to build your own table of floating-point numbers, like the one above, but with different XZ positions and different "Phi" compass headings.
All of the sample missions have ten nearly identical blocks of special code in them (one block in each of the ten MissionChronoMilestone handlers) to help you with that task, but all of that code is normally "commented out", because it is only used during mission development (in order to capture the floating-point data needed to build the table shown above). To find an example for your study, look for blocks of code like this in the sample missions:
//
// FOR EARLY DEVELOPMENT WORK, It is necessary to capture the exact position of moving
// aircraft carriers (and any other moving objects) as soon as the mission advances to
// MissionChronoMilestone 3. We do that during development here, and later on we will
// use the resulting XZ positions as hard-coded data upon receipt of MissionChronoMilestone
// #3 messages from a MissionCommander.
//
/
* The following eleven lines of code may or may not be commented out because they were only used during
* development use, to capture the referenced values at the moment of MissionChronoMilestone #3.
* We are retaining the commented-out code block for future reference, but NOT for ordinary
* use:
RedTeamCarrier07XPositionAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->tl->x;
RedTeamCarrier07ZPositionAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->tl->z;
RedTeamCarrier07PhiAtMilestone3 = ThreeDObjects[MissionObjectCarrierRed1]->phi;
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07XPositionAtMilestone3 = %f", RedTeamCarrier07XPositionAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07ZPositionAtMilestone3 = %f", RedTeamCarrier07ZPositionAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer() RedTeamCarrier07PhiAtMilestone3 = %f", RedTeamCarrier07PhiAtMilestone3);
display (DebugBuf, LOG_MOST);
sprintf (DebugBuf, "MissionNetworkBattle07::processtimer()b: MissionStateNetworkBattle = %d", MissionStateNetworkBattle);
display (DebugBuf,LOG_MOST); /
At some point during your work to perfect a new mission involving more complex navigation, after you hard-code logic that moves your ships or other Mobile Mission Objects around the way you want them, you will activate all ten blocks of that code, causing it to calculate the XZ position and orientation of your ship(s) at each of the ten MissionChronoMilestones. The resulting data is stored in LAC's log file, which you can always find at ~home/.LAC/logfile.txt. After taking that step you must copy the resulting data from the log file into your source code according to the pattern shown in the table above. Then you can return those ten code blocks to their de-activated state, since you won't be needing them anymore.
If the remaining code of your new mission follows the existing patterns as documented in our samples, your ships will move around on the map according to your mission design and will synchronize their positions with one another. It shouldn't be necessary for you to change the logic of mission flow at all. Just follow the existing pattern that we have used for our moving aircraft carriers. If you decide to add other Mobile Mission Objects, you will need to add corresponding, additional logic and expand the sample data tables, but you can simply duplicate the existing pattern and make up your own descriptive names for any new variables that your new objects may demand.
Last edit: bbosen 2020-07-13