Announcement

Collapse
No announcement yet.

scenario problem

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Originally posted by hatschy
    Ok, I modified the example a little bit. Now any scenario map saved with scenario name "Welcome" (via the button "Save Scenario As" of the cheat dialog), renamed "savegame.csg" and copied to the Welcome scenario's "scen0000" folder should work. Of course you can replace "Welcome" with the name of your own scenario.

    The problem with the previous version was the "g.year == 0" in the "when" clause of the welcome message trigger. CtP doesn't fire this kind of trigger for the first civ when it loads a scenario with a map. So I'm now using the "unit.selected" event instead. This works, if there is a unit for your civ on the scenario map (e.g. your first settler) and if CtP autoselects your first unit (which should be the default and I don't know if this can be turned off).

    As for the videos: I don't know, if they can be turned off. They play automatically when using the "GameOver" function. So, if you don't call that function, the movies won't play. But then you'll have to find another way to end the game.

    I suggest you read the descriptions of the available SLIC functions to get an impression of what is possible.
    Hi, I'm RAH and I'm a Benaholic.-rah

    Comment


    • #17
      HOWTO

      Here is a small HOWTO for writing a scenario that presents a series of welcome messages and ends after a given number of turns.

      Let me explain the basics first.

      CtP can be extended by writing program code in a scripting language that looks pretty much like a tiny subset of the "C" programming language and by packaging that code in scenarios. CtP will find a scenario, if it is placed in the "scenario" folder below the CtP installation directory, and it will load the code within, if the user chooses to play a game with that scenario enabled.

      CtP executes the code of a scenario based on events in the running game. This means, that when certain things happen, a piece of code will be executed, if one is defined for that event. Events can be things like "a new turn has begun", "a new unit was finished", "the player selected a unit", etc. See SLIC Built-in variables and trigger events for game events that can trigger the execution of code.

      To relate a piece of code and a game event, a "trigger" must be defined. A trigger has the following form:

      trigger 'TriggerName' when (TriggerCondition) {
        Code to execute
      }

      The italic parts are just placeholders.
      - TriggerName is an arbitrary but unique name for the trigger (restrictions on allowed characters apply).
      - TriggerCondition is a "C"-style conditional expression.
      - Code to execute stands for a list of statements you want to be executed when the TriggerCondition evaluates to true.

      For our specific scenario problem we need a trigger condition that becomes true, if a human player's turn has just begun. So we use the condition IsHumanPlayer(g.player). The expression g.player is a built-in variable of an integer type and represents the index of the active player in the list of all players.
      As we don't want the welcome messages to be displayed every turn but only for the first turn, we must provide some additional logic. Unfortunately we can't use an extesion to the trigger condition like IsHumanPlayer(g.player) && g.year == 0 (where g.year is the built-in turn counter variable). This expression evaluates to true only if it's a human player's turn and the current turn is the first one (the turn counter starts at zero). But CtP doesn't handle this correctly, if the scenario includes a map, so we must choose something different. The trigger we use looks like

      trigger 'T_Welcome' when (IsHumanPlayer(g.player)) {
        if (messageFlag < g.player) {
          Message(g.player, 'M_Welcome');
          messageFlag = g.player;
        }
        else {
          DisableTrigger('T_Welcome');
        }
      }

      As explained above, this trigger will fire, whenever a human player's turn begins. We use a variable named messageFlag to keep track of whether we have already displayed the welcome message. Non-built-in variables (i.e. the variables defined by the scenario programmer) are of the integer type, if used without a special definition and are automatically initialized to zero, like in the trigger above. So initially messageFlag has the value zero and g.player is one (blue civ) or two (orange civ) or three (green civ) or... We use an if-statement to get one of two code blocks executed, depending on the outcome of a comparison. If the value of the messageFlag variable is smaller than the value of g.player, then the block immediately following the condition is executed, otherwise the else-block is executed. The statement messageFlag = g.player assigns the current value of the built-in variable g.player to the variable messageFlag. In that way, the condition of the if-statement will evaluate to true only once. The DisableTrigger-statement in the else-block will disable the trigger at the beginning of the player's second turn. We could do without that else-block, but disabling a trigger when it is no longer needed is always a good idea, as this saves processing time and avoids unintended behavior, if things get more complicated than in this simple scenario.

      Our trigger includes the following statement in the if-block: Message(g.player, 'M_Welcome'). This statement displays a messagebox named M_Welcome for the active player. The definition for the messagebox looks like this:

      messagebox 'M_Welcome' {
        MessageType("CIVILIZATION");
        Title(ID_SCENARIO_TITLE);
        Text(ID_WELCOME_TEXT);
        DisableClose();
        CantEndTurn(1);
        Button(ID_BUTTON_CLOSE) {
          Kill();
          Message(g.player, 'M_Welcome2');
        }
        Show();
      }

      Here is an explanation of what the statements in the message box definition do:
      - MessageType defines the type of icon that is shown for the message box
      - Title defines the title
      - Text defines the message body
      - DisableClose() prevents closing the message box by doing other things than using the provided button
      - CantEndTurn(1) prevents ending the turn
      - Button defines a button with its text and a block of code to be executed when the button is pressed
      - Show() will result in the message box to be shown immediately (without the need to click the icon).
      The texts for the title, the message body and the button are defined in the resource file "scen_str.txt". The resource file defines one text resource per line (lines starting with "#" are ignored), the "ID_" prefix for the text resources is omitted in the resource file. Look at the scenarios attached to previous posts for an example of a resource file.
      The statements that are executed when the button is pressed are:
      - Kill(): Closes the message box (has nothing to do with killing units).
      - Message: Shows another message box (the next part of the welcome message).
      The message box that shows the last part of the welcome message contains the additional statement block

        OnClose {
          CantEndTurn(0);
        }

      which will enable the player to end the turn when the message box is closed.

      Now for the scenario's second functionality: Ending the game after a given number of turns. As mentioned somewhere above, there is a built-in turn counter variable g.year, which counts the turns starting at zero. So what we need is a trigger that fires when the turn counter reaches the given limit. You can already guess what the trigger looks like:

      trigger 'T_GameOver' when (IsHumanPlayer(g.player) && g.year == 10) {
        if (CitiesRank(g.player) == 1) {
          GameOver(g.player, 1);
        }
        else {
          GameOver(g.player, 2);
        }
      }

      As we want the trigger to fire only for human players, we use a combined condition of IsHumanPlayer(g.player) && g.year == 10, which evaluates to true, if the active player is human and if the turn counter has reached the limit (10 in the example). In the code block that is executed by the trigger, we determine whether the player has won or lost the match and call the GameOver function with the second parameter either being one for a win or two for defeat. An arbitrary condition can be used to decide on victory or defeat. The example requires the player to be number one in the cities rankings for a victory. See the SLIC function reference for other possible candidates for the victory condition. Several conditions can be combined to one complex condition, of course.

      I hope that this (not so) small HOWTO can serve as a starting point for further explorations of the possibilities of scenarios. Don't forget to read the exhaustive explanations in the CtP modification section here at Apolyton.

      Comment


      • #18
        scenario problem still not solved

        I followed your derections but it didnt seem to work. after I made the slic file and scen_string txt, I went in the game and launched my scenario. the boxes didnt show and the game never ended in 50 turns. The 20 year per turn didnt work either. here is a attached file of my slic file that I made. I over looked it several times and couldnt see any errrors. perhaps the game didnt work properly becuase I typed in the wrong information into the slic file and/or the scen_str.txt file. please take a look at my slic file so that you can tell me what is wrong with it.
        Attached Files

        Comment


        • #19
          Well, there are several problems with your SLIC file. I'll mark them and describe them below.

          trigger 'T_welcome' when (IsHumanPlayer(g.player)) {
            if (messageFlag < g.player) {
              message(g.player, 'M_welcome');
              messageFlag = g.player;
            }
            else {
              DisableTrigger('T_welcome');
            }
          }
          messagebox 'm_welcome' {
            MessageType("CIVALIZATION");
            Title(ID_SCENARIO_TITLE);
            text(ID_WELCOME_TEXT);
            DisableClose();
            CantEndTurn(1);
            Button(ID_BUTTON_CLOSE) {
              kill();
              Message(g.player, 'M_Welcome2');
              // You cannot reference 'M_Welcome2' here, as you did not define that message box
            }
            Show();
          }
          // The following lines must be inside the definition of the last message box
            OnClose {
              CantEndTurn(0);
            }

          trigger 'T_GameOver' when (IsHumanPlayer(g.player) && G.player == 50) {
            // You must use g.year in the line above, not g.player
            if (CitiesRank(g.player) == 1) {
              GameOver(g.player, 1);
            }
            else {
              GameOver(g.player, 2);
            }
          }


          Here is the correct version. The additional && unit selected is needed for scenarios with a custom map (the explanation for this should be some postings above). As soon as you define the followup message 'M_Welcome2', you can delete the double slash from the line that calls the second message box (double slashes are used to mark the text from the double slash to the end of the line as a comment, so CtP won't interpret it as program code). And don't forget that only the last message box should have the OnClose { CantEndTurn(0); } section.


          trigger 'T_Welcome' when (IsHumanPlayer(g.player) && unit.selected) {
            if (messageFlag < g.player) {
              message(g.player, 'M_Welcome');
              messageFlag = g.player;
            }
            else {
              DisableTrigger('T_Welcome');
            }
          }
          messagebox 'M_Welcome' {
            MessageType("CIVALIZATION");
            Title(ID_SCENARIO_TITLE);
            Text(ID_WELCOME_TEXT);
            DisableClose();
            CantEndTurn(1);
            Button(ID_BUTTON_CLOSE) {
              Kill();
          //    Message(g.player, 'M_Welcome2');
            }
            OnClose {
              CantEndTurn(0);
            }

            Show();
          }
          trigger 'T_GameOver' when (IsHumanPlayer(g.player) && g.year == 50) {
            if (CitiesRank(g.player) == 1) {
              GameOver(g.player, 1);
            }
            else {
              GameOver(g.player, 2);
            }
          }

          Comment


          • #20
            As allways, experts from within our comunity step up

            Now please when the plate for contributions is passed, dig deep
            Hi, I'm RAH and I'm a Benaholic.-rah

            Comment


            • #21
              slic file

              here is my new slic file
              Attached Files

              Comment


              • #22
                Here's a zipped scenario that includes the corrected version of your 'scenario.slc' file. If you have problems with your 'scen_str.txt' file, please use the file contained in the attached scenario as a starting point (copy your message texts to that file). If you still can't get it to work, please zip your complete scenario and post the zipped file in this thread.
                Attached Files

                Comment

                Working...
                X