Ил-2 Штурмовик: Битва за Британию. Скрипты. Скрипты для чайников. Часть 3 - Загрузка подмиссий

Материал из АвиаВики
Перейти к: навигация, поиск
Автор: FG28_Kodiak
Ссылка: Перейти (перевод Google)
Samples.zip

Having in the past two lessons on the topic, the missions have loaded at the beginning in our ongoing mission, we will make it in today's time-controlled. To this end, the game presents us with the method public virtual void OnTickGame () are available, these can be for our purposes to write about.

public override void OnTickGame()

This is the game about 34 times OnTickGame() calls per second, depending on computer usage may be more or less time.

Example:

using System;
using maddox.game;
using maddox.game.world;
public class Mission : AMission
{
   public override void OnTickGame()
   {
       double WievielSekunden = 0;
       
       if (Time.tickCounter() == 334) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
       if (Time.tickCounter() == 667) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
       if (Time.tickCounter() == 1000) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
  }
} 

The example does nothing more than after 10, 20 and 30 seconds to write a short message in the chat bar. Time.tickCounter() contains the number of ticks since the mission was launched and with the help of Time.TicksToSecs (number of ticks), we can convert this number of seconds.

GamePlay.gpLogServer (null, "Meldung nach: {0} Ticks das sind {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});

then leads to the following issue:


Sfdp3-1.jpg


You can use OnTickGame() also, if you want to spend some cyclically.

Example:

using System;
using maddox.game;
using maddox.game.world;
public class Mission : AMission
{
   public override void OnTickGame()
   {
       double WievielSekunden = 0;
       
       if (Time.tickCounter() % 334 == 0) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Erste Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
       if (Time.tickCounter() % 509 == 0) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Zweite Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
   }
}

To spend our messages periodically, we use here the modulo operator in C # so%. The Modulo returns the integer remainder of a division. 3% 3 would therefore be 0, 3% 2 would be 1, 5% 3 would be 2 (for details in [1] ) The query Time.tickCounter() % 334 == 0 is always true if the value is divisible in tickCounter() with no residue, and then issues a message (about every 10 sec.). The 2nd query then after about 15sec (Well just about ) A message. Both equal to 0, by starting to appear as something no rest.


Sfdp3-2.jpg


If you want to no message (or other) at the beginning of the mission you are instead of zero to a value of not greater than or equal to the divisor is. Bad example if (Time.tickCounter() % 334 == 334) would this query could never be TRUE. Nor as if (Time.tickCounter() % 334 == 335). Since there can never be a residual value of these reaches. Example should be like:

using System;
using maddox.game;
using maddox.game.world;
public class Mission : AMission
{
   public override void OnTickGame()
   {
       double WievielSekunden = 0;
       
       if (Time.tickCounter() % 334 == 333) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Erste Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
       if (Time.tickCounter() % 509 == 508) 
       {
           WievielSekunden = Time.TicksToSecs(Time.tickCounter());
           GamePlay.gpLogServer (null, "Zweite Meldung: {0} Ticks = {1} sek.\n", new object [] {Time.tickCounter(), WievielSekunden});
       }
   }
} 

Result:

Sfdp3-3.jpg


Like today now do anything to Broken? - But The main mission of two, we modify by adding camouflage nets, they should appear only to disappear and hide the vehicles, but are not really necessary.

Sfdp3-4.jpg


This time we just need a SubMission, this involves a single vehicle that travels from one end of the runway to the other.

Sfdp3-5.jpg


The submission should be charged periodically, say every 30 sec. giving the impression that the vehicles some distance behind the other reverse actions. Especially with online servers occurs over time, but with the problem that inhabit the ever more vehicles and planes, the card, which can lead to performance problems or can result. In our mission, we therefore allow the vehicle to disappear after 75 seconds, which is the time that the vehicle needs to come from a camouflage tent to another. The player should try to destroy as many vehicles as possible. The number of vehicles (or better the number of submissions that should be loaded), we use time fixed at 10, we could also allow play to continue indefinitely. This time we will not use triggers, but our victory and the condition of the damaged vehicles are put in the code.

The code with test messages is as follows:


using System;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;
public class Mission : AMission
{    
   AiAircraft PlayerPlane;
   const int MaxAnzahlWellen = 10;
   int AnzahlWellen = 0;
   int ZerstoerteZiele = 0;    
   public override void OnBattleStarted()
   {
       base.OnBattleStarted();
       MissionNumberListener = -1;
       PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place();
   }	
   private void serverMessage(string msg)
   {
       GamePlay.gpLogServer (null, msg, new object [] {msg});
   }    
   public override void OnTickGame()
   {
       if (Time.tickCounter() % 1000 == 0 && (AnzahlWellen < MaxAnzahlWellen))  //ca. alle 30sek die Karte laden
       {
           GamePlay.gpPostMissionLoad("missions\\Single\\Samples\\TestSubmissions\\MissionNachladen5Sub1.mis");
           AnzahlWellen++;
           GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung
       }        
       if (Time.tickCounter() % 11500 == 0)     
       {
                   GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung
                   GamePlay.gpHUDLogCenter("Sie haben "+ ZerstoerteZiele.ToString() + " von " + AnzahlWellen.ToString() + " Fahrzeugen zerstört" );
       }
   }    
   public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
   {
       base.OnActorCreated(missionNumber, shortName, actor);
       if (actor is AiGroundActor)
       {
           Timeout(75, () => {
               if (actor != null)
               { 
                   (actor as AiGroundActor).Destroy(); 
               }
           });
       }
   }    
   public override void OnActorDead(int missionNumber, string shortName, AiActor actor, System.Collections.Generic.List<DamagerScore> damages)
   {
   		base.OnActorDead(missionNumber, shortName, actor, damages);        
       string KilledName;     		
    		KilledName = missionNumber.ToString()+ ":0_Chief";     		
    		if ((damages.Count != 0) && (PlayerPlane.Name().Equals(damages[0].initiator.Actor.Name())) && KilledName.Equals(actor.Name()))
    		{
    		    ZerstoerteZiele++;
    		    serverMessage(ZerstoerteZiele.ToString());
    	  }
   }
}

So we look at the code closer The first thing to using the new statement:

using System.Collections.Generic;
this we need the code to access the class list of C # to get the List class provides methods to insert and read this (and much more) make a list of objects. To be given more time. 

This time we need the following variables have in the entire context of validity: AiAircraft PlayerPlane; The game engine provides us with the class AiAircraft available, all aircraft in the game, except the members of this group are static, so to speak. const int MaxAnzahlWellen = 10; This constant specifies the number of submissions runs. int AnzahlWellen = 0; waves, wave number is used as a counter in the course of the current number of runs saved. int ZerstoerteZiele; This variable contains the number of targets already destroyed.

public override void OnBattleStarted()
{
   base.OnBattleStarted();
   MissionNumberListener = -1;
   PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place();
}

In OnBattleStarted we establish with MissionNumberListener = -1, that all events are taken from the missions. And with the help of: PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place(); we have to plan the player of the variables from the player occupied aircraft. As happens in this mission, only one aircraft by sitting the player can an assignment is sufficient to start the mission, several aircraft to be in the game, it makes sense to check before important the players relevant events whether it is sitting still in the early airplane and if not reassign . But certainly something we need in a later lesson. For us, the assignment IGamePlay class method gpPlayer () to disposition by the (AiAircraft) we share the game with what we mean in this case, the class AiAircraft, there are several derived classes it is necessary to inform the system that we because my (eg, the player is a member of the class AiActor, AiCart, AiAircraft..). Place () belongs to the class and tells players where the player is currently located. Note also that you can only use gpPlayer in single missions, multiplayer games coming gpRemotePlayers used. Important is currently the only one with the help of (AiAircraft)GamePlay.gpPlayer().Place() in a single player game the player gets the plane as a return.

public override void OnTickGame()
{
   if (Time.tickCounter() % 1000 == 0 && (AnzahlWellen < MaxAnzahlWellen))  //ca. alle 30sek die Karte laden
   {
       GamePlay.gpPostMissionLoad("missions\\Single\\Samples\\TestSubmissions\\MissionNachladen5Sub1.mis");
       AnzahlWellen++;
       GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung
   }
       
   if (Time.tickCounter() == 11500)     
   {
       GamePlay.gpLogServer (null, "{0} nach {1} sek.\n", new object [] {AnzahlWellen, Time.TicksToSecs(Time.tickCounter())});//Testmeldung
       GamePlay.gpHUDLogCenter("Sie haben "+ ZerstoerteZiele.ToString() + " von " + AnzahlWellen.ToString() + " Fahrzeugen zerstört" );
       MissionAbgeschlossen = true;
   }
}

OnTickGame () if (Time.tickCounter ()% 1000 == 0 & & (number of waves <MaxAnzahlWellen)) The query load the map every 30 seconds. and that is the number of waves <MaxAnzahlWellen long as, in our case just 10th without this "& & (count waves <MaxAnzahlWellen)" The submission would be charged indefinitely, or just until the player has no more desire. Where, if I'm considering the name and number of waves in a vehicle MaxAnzahlWellen were somewhat exaggerated . If the condition is true our SubMission charged and thereby caused the vehicle on the road. Then increases the number of waves around an issue and issued a check in the chat bar so you can adjust the times may still, as I said the number of ticks per second can vary depending on usage. Should of course be removed from the final version. if (Time.tickCounter () == 11500) is our Abruchbedingung the 11 500 ticks should of course be chosen so that the last vehicle can also complete the route. This condition makes the use of a time trigger unnecessary. So the time is expired, a control message is output which outputs the number of waves and the time required to remove this message also in the final. There is still a message on the screen:

Sfdp3-6.jpg


public override void OnActorCreated (int mission number, string ShortName, AiActor actor) { base.OnActorCreated (mission number, short name, actor);

if (actor is AiGroundActor) { Timeout (75, () => { if (actor! = null) { (As actor AiGroundActor) Destroy ().; } }); } } The method OnActorCreated (int mission number, string ShortName, AiActor actor) is called each time a new Actor is created, an Actor in Cliffs of Dover is anything to either move or function (eg artillery), has something that only stupid in the area is not part of it (ie buildings, trucks static, static aircraft, etc.). Also here is the first base call to make sure everything is initialized properly. if (actor is AiGroundActor) here is checked whether the current actor is among the AiGroundActor class in this class are all items that are traveling on the ground, thus moving trucks, artillery, ships, etc. If the query is TRUE is next (75, () => {statements}) timeout; executed. When the timeout is specified first time, after something is to be executed, in this case 75 seconds. in the curly brackets are the instructions to be executed then why is the spelling with () => a little strange, beyond the scope of this lesson, we say stop is just so . The timeout after 75 seconds then executes instructions If the query in this query is whether the actor is also currently available (it may already have been removed elsewhere), if nothing happens, but if (as actor AiGroundActor) we put hereby determine that the actor should be treated as AiGroundActor (if we do not do this, we get an error message because the system does not know what we mean Actor) with. Destroy () then this is completely removed from the mission, then simply disappears. This makes you an "overpopulation" of the card to avoid running so essentially multiplayer maps (as is the despawn time course much larger) the number of times. But here it fits quite well purely .

public override void OnActorDead (int mission number, string ShortName, AiActor actor, System.Collections.Generic.List <DamagerScore> damages) { base.OnActorDead (mission number, short name, actor, damages);

Killed string name;

Killed missionNumber.ToString name = () + ": 0_Chief";

if ((damages.Count! = 0) & & (PlayerPlane.Name (). Equals (damages [0]. initiator.Actor.Name ())) & & KilledName.Equals (actor.Name ())) { ZerstoerteZiele + +; message server (ZerstoerteZiele.ToString ()); / / test message } } To register if we have destroyed a target, we overloaded the method OnActorDead (..) public override void OnActorDead (int mission number, string ShortName, AiActor actor, System.Collections.Generic.List <DamagerScore> damages) This method is used by system called each time when an actor is destroyed (or better Incapacitate is) and that this happens twice, once for the vehicle and then for the imaginary occupant, here you realize it is in the game also provided the ground vehicles and by human players can be controlled. Since we do not want our "dead-counter" is incremented twice, we introduce the variable name of type String killed. Killed name then sets up the name to be observed, because here you have to decide actor.Name () (ie the name of the destroyed target) once the value of "1:0 _Chief" and the second call "1:0 _Chief0" (one that varies depending on mission number), according to the number after the occupants of the Chief is all spent. The base name can be found in the Mis-file in our example SubMission here: [Chiefs] 0_Chief Vehicle.Austin_10_Tilly gb One can of course use the Mis-file and edit there own. I signed up for "Mission Number: 0_Chief" decided, that the vehicle itself if ((damages.Count! = 0) & & (PlayerPlane.Name (). Equals (damages [0]. initiator.Actor.Name ())) & & KilledName.Equals (actor.Name ())) Thus the explanation for the If statement is again somewhat larger ! damages.Count = 0 System.Collections.Generic.List <DamagerScore> damages of the type, well actually not a type but a list, this list is by us from C #; provided (using System.Collections.Generic). This list contains elements of type DamagerScore be on this list from the game all the actuators were placed in the destruction of this object (Actor) involved. The more players than can be had even AIs. With the help of. Count one can count the number of items in the list, this value is zero, no one was involved, the query is needed because the method. Destroy () method throws the OnActorDead because we were only on the Players interested destroyed vehicles, we ignore the system simply eliminated. & & (PlayerPlane.Name (). Equals (damages [0]. Initiator.Actor.Name ())) this is to ensure that even the player is the one who destroyed the vehicle has PlayerPlane.Name () contains the name of the pilot ( has fired in my case, therefore, Kodiak) and damages [0]. initiator.Actor.Name () returns the name of the person as the last of the car (or plane). damages [0] indicates that the first item in the list of damages is meant, in our case it is sufficient because only one aircraft and a player were on the road. Both will be compared and if consensus is part of this perception. With & & KilledName.Equals (actor.Name () is then queried even if the target is consistent with our desired. Thus, if the entire if statement is true, the ZerstoerteZiele counter incremented by one and spent a brief test message on the screen.

But do not worry in the next lessons will deepen the whole still. As always, I am grateful for criticism and suggestions.

The attachment contains the current instance missions.