Author Topic: Advanced Development Tutorial for FOnline  (Read 36881 times)

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
« Last Edit: September 18, 2023, 01:45:17 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
1. Making a location spawn (for a daily/weekly quest) repeatable with timer.
« Reply #1 on: December 18, 2015, 11:38:32 am »
1. Making a location spawn (for a daily/weekly quest) repeatable with timer.

There will be no Step by Step for this one, as all the elements have been shown previously, I will just explain and link the script. You need to add the source to the same script file as the one we used previously, because it uses some of it's functions. Remove the lines starting with player.Say.. when you put this to production code, they were just used for debug, and for you to see what is happening.

  • r_GetQuest(..)
    • This function should be called from the dialog, when the NPC gives the quest.
    • If the timed even is available, then it will summon the location, but this is a precation only, the dialog branching should decide this.
    • Try and test this, if the timer is not up, it should say in system window that the quest is not available yet.
  • e_ResetSpawnLocTimer(..)
    • This is an even function which will be called from r_getQuest(..) and is responsible for reseting the timer.
    • All this function does, is to call the setTimedEventAvailable(..) function to allow the retaking of the quest.
  • setTimedEventAvailable(..)
    • Is used to set the Unique variable for this quest timer.
  • isTimedEventAvailable(..)
    • Check the value of the timer variable.

There are many ways to do this, this is only one presentation that works, for experimentations.

Code: [Select]
// Demo for Timed Event used for repeatable quests.
void r_GetQuest(Critter& player, Critter@ npc)
player.Say(SAY_NETMSG, "r_GetQuest() called");
if (isTimedEventAvailable(player, npc))
uint[] values = {player.Id, npc.Id};
setTimedEventAvailable(player, npc, false);
CreateTimeEvent(AFTER(REAL_SECOND(10)), "e_ResetSpawnLocTimer", values, false);
r_SpawnLoc(player, npc);
player.Say(SAY_NETMSG, "r_GetQuest() - Quest not available yet.");

// S
uint e_ResetSpawnLocTimer(array<uint>@ values)
Critter@ player = GetCritter(values[0]);
player.Say(SAY_NETMSG, "e_ResetSpawnLocTimer()");
Critter@ npc = GetCritter(values[1]);
setTimedEventAvailable(player, npc, true);
return 0;

bool setTimedEventAvailable(Critter& player, Critter@ npc, bool isReady)
player.Say(SAY_NETMSG, "setTimedEventAvailable()");
if(!valid(player) || !valid(npc))
return false;
GameVar@ var = GetUnicumVar(UVAR_q_timedEventAvailable, npc.Id, player.Id);
if (!valid(var))
return false;
if (isReady)
var = 1;
player.Say(SAY_NETMSG, "setTimedEventAvailable() - 1");
player.Say(SAY_NETMSG, "setTimedEventAvailable() - 0");
var = 0;
return true;

bool isTimedEventAvailable(Critter& player, Critter@ npc)
player.Say(SAY_NETMSG, "isTimedEventAvailable()");
        if(!valid(player) || !valid(npc))
                return false;
GameVar@ var = GetUnicumVar(UVAR_q_timedEventAvailable, npc.Id, player.Id);
if (!valid(var))
return false;
if (var == 0)
player.Say(SAY_NETMSG, "isTimedEventAvailable() == 0");
return false;
player.Say(SAY_NETMSG, "isTimedEventAvailable() == 1");
return true;
« Last Edit: December 18, 2015, 02:15:15 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
2. Floating heal text above the head.
« Reply #2 on: December 18, 2015, 11:40:54 am »
2. Floating heal text above the head.


In this tutorial we will use the Reloaded SDK version 2, and will change some RP elements into RNG or whatever it's called. Instead of the usual ***patches wounds***, ***injects stimpack*** healing message a green positive number will show the amount healed by using First Aid or healing drugs.
To specify our task, only First Aid, Super Stimpacks, Stimpacks, Hype, Healing Powder and Weak Healing Powder usage will change it's floating text. Also, if the FA is a critical failure the color of the text will be teal, while if it's  a critical success, the healing number will be the brightest green possible.

Understanding the code changes:

  • To start, need to search for the text "patches wounds" to find any related code to this text. Fortunately for us, this is not hidden too many layers, we will find it "skills.fos", which we will transform a bit, as shown in the code sections.
  • To do that, first we will write a tool function, which will handle the floating texts. This will be added to the "utils.fos" script file. The definitions it requires will be added to "utils_h.fos" header file, also we will import the function there, for easier access. Also a few color definitions will be added to "_colors.fos" script file.
  • When this is done, we will search for "injects stimpack" and find a few references in "drugs.fos" script file. This will appear mainly in two functions, one that handles when the critter uses drugs on itself and one that handle when the critter uses drugs on others.
  • Remove all floating message related to healing drugs in both functions, but do not replace with anything, as at this point the healing value is not knows. Healing drugs have a random interval, and we need to use the floating text only after that value has been determined.
  • The place where we will put in the floating text calls, will be the drug processing function named "ProcessDrug". This function will be a bit fuzzy at first sight, but it's not hard to find the right place to put the code in. To not make a huge mess, a new util function will be implemented for this, which will just call the other util function with the right reasons depending on the drug pid used.
  • We test it and basically that is all.


When linking the code from pastebin, I will leave a few lines for context, so you can see what to cut out and what to replace with.

  • drugs.fos - follow instruction in code where to cut and replace, also, you will need to remove the old healing powder floating text.
  • _colors.fos - add these lines anywhere.
  • utils_h.fos - add these lines anywhere.
  • utils.fos - add these lines anywhere, I put them near VerboseAction, since that is the functionality we "replace".
  • skills.fos - replace these lines as instructed in the code.

Test it, if it does not work, report back on feedback please.

« Last Edit: January 08, 2016, 10:47:04 am by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
3. Writing a gambling game: Roulette.
« Reply #3 on: December 18, 2015, 11:41:33 am »
3. Writing a gambling game: Roulette.

We will write what the name suggest. At first, it's sounds like an easy and fast task, but once you get into details, you will see it's quite long. The good side of it is, that it helps us understand a lot about dialogues. Almost everything. And gives a lot of practice also.

First, I will explain the mechanic of how our roulette will work, then you should copy/paste the codes and use it to try it out on your development environment. I will give step by step instructions to make it seamless. After that I will explain most of the functions, the structure and highlight some specifics that can be useful later on. The code will be attached at the end.

Our simplified roulette:
  • Numbers range from 0 to 36, no double zero.
  • Player can bet only one bet at a time, and only one player can play with the host.
  • The following bets are available:
    • Straight bet - a chosen number is the bet. Chance to win is 2.7% (1/37), win multiplier 35.
    • Color bet - red or black. Chance to win is around 48% (18/37), win multiplier is 2.
    • Parity bet - even or odd. Chance to win like color bet.
    • Mangue bet - numbers from 1 - 18 win. Chance to win like color bet.
    • Passe bet - numbers from 19-36 win. Chance to win like color bet.
  • Player places a bet on one of the bets, then pays, then the table will roll the winning number and it's color, then this is compared to the players bet and the results are decided.
  • Player plays against the host/table difficulty. The NPC Gambling skill is compared to the Players Gambling skill, in order to achieve negative effects or not. If the player's skill is equal or higher than the host's skill, there are no negative effects concerning the roll. If the player's skill is lower, then there is a chance that if the roll matches the winning pattern, a re-roll is made. If that is a win again, then the player still can win. This is how the gambling skill is simulated, table's altering effect to different odds and the players ability to detect, thus counter it, or whatever reasons to justify the role-play :)

Points of interest that we will cover:
  • How to use scripts in dialogue answers.
  • How to use "lexems" (dynamic text) in dialogues.
  • How to use the "Say" textbox in a dialogue.
  • Function prefixes for dialogues.
  • Clean code.

  • How to use scripts in dialogue answers:
    • Add a demand or a result to the answer.
    • On the demand/answer select the script radio box.
    • Write the script file name, a "@" and the script function name to specify the function that shall be called when the answer is selected by player. (for example: gambling_roulette@r_SetBetValue)
    • Select the parameters required, the Critter and the NPC parameters are set by default, you don't need to set those.(for example: 100)
    • If you don't have parameters set it to NA.
    • For this, there has to be a script file by the name (gambling_roulette.fos) and a function inside it with the required parameters (Critter& player, Critter@ npc, int betValue)
    • The used prefix for functions that are called from dialogues is "d_" for demand calls and "r_" for result calls.
    • Whenever you find in the scripts a function starting with "d_", that means that function is called in a dialog as a demand somewhere. Check dialog.fos for examples.
  • How to use "lexems" (dynamic text) in dialogues:
    • When you write the dialogue you need to link a script to it with similar formula how you add script to demands/results. (module_name@function_name)
    • By default you can select None or Attack, but just write in the module@function it will work.
    • You also need a script with the specified name in the specified script file and an extra parameter of type string. (example: "void dlg_ShowBetInfo(Critter& player, Critter@ npc, string@ text)").
    • To use the lexems, use the following formula: "@lex variableName@"
    • In the script, add the following line to set the varialbe name: text += "$variableName" + "enter value here"; (example: text += "$betValue" + 250;).
    • The prefix used for scripts that are accessed from dialogs is "dlg_" (ex: dlg_ShowBetInfo).
  • How to use the "Say" textbox in a dialogue:
    • You need to link a script to the dialog as described previously.
    • The signature of the function should be like this: "uint dlg_SetBetNumberFromDialogue(Critter& player, Critter@ npc, string@ say)". It has to return a uint type, that will say where to return after the player pressed the "Ok" on the say dialogue.
      • If the return value is 0, then the dialogue will result in the same dialogue step. You can use "player.Say(SAY_DIALOG, "message");" to change the current dialogue message. This will look like you have a new one, but as of structure it's the same with different text, meaning the same function is called when u used the "Say" option again.
      • If the return value is other than 0, then the dialogue will jump to the specified number in the dialogue structure.
  • Function prefixes for dialogues:
    • "d_" - demand prefix, added to function names which are called from an answer demand.
    • "r_" - result prefix, added to function names which are called from an answer result.
    • "dlg_" - dialogue prefix, added to function names which are called from dialogues.
  • Clean code:
    • This topic is a bit advanced here, but definitely needed. The reason for that is, that most developers, especially those used to C or other lower level languages tend to over optimize stuff or just express themselves in ways that other coders don't understand easy. While this sound cool, the drawback is that at larger projects it will back stab. Always. You can find a lot on this topic on the net, searching around, but here we will only talk about some basic ideas, how to keep your code clean (easily readable for everyone, including yourself later). At first, as for a rookie, the code in this tutorial seems too large and hard to understand because of this. You will need a good IDE, and you will get used to this very soon, after that it will make much more sense and you will agree that this is much better this way.
    • A code (in our case considering that our tools and language is nowhere comparable to high level programming languages like Java, C# etc) is clean when:
      • There are no needs for comments, because the names of variables and functions describe very well their behavior and the logic is easy to follow. (I made a lot of comments, but that was for the purpose of the tutorial, barely any of those is needed, as you probably can see already.)
      • Interfaces are separated from main logic code. (For example see how the functions that are used by dialogues are written.)
      • Follows the same naming conventions and rules through the whole project. (example: the dialogue prefixes mentioned above)
      • Higher level logic and lower level logic are separated, and not in the same function.(example: r_SpinTheRoulette)
      • Add anything to the list which you can find appliable here by the Clean Code standards, what I mentioned above are the minimum.
    • Clean code should always be used when the performance of the module, function is not critical. In that case, performance optimization overrides this, however that is usually less than 5% of the whole projects code base and I don't think that here is different, but it's for you to find it out.
    • Our casino game is obviously not a performance critical scenario, so the worst thing one could to is to fill it with left shifts to moving around flag values, etc.
    • Also, our casino game is designed to be extendable in the future. The sign for this is the modularity. The interface can be replaced to a GUI later on if needed, without changing too much of the actual code. If we had classes I would advise to make your programs open for extension but closed for modification, but that is another story.

Full dialogue in editor:

Full source code: (click on the files, they are a pastebin link)
  • Header file used for gambling - gambling_h.fos
  • Main script file for roulette operations - gambling_roulette.fos
  • Dialog file for casino roulette host - all_casino_roulette_host.dlg
  • Dialog list modifications inside the dialogues list file, add this line to dialogs.lst: "$   2110   all_casino_roulette_host"
  • Variable list modification - _vars.fos
  • All that is left, that you make a new NPC near a casino table (or edit one) and set it's dialogue number to 2110.

Code review:
  • obj& does not need valid() check - Fixed
  • lines 471-479 could be just return( Random(1,100) <= gamblingblabla );
  • 488+ is slow. wait, slow and ugly
  • if( red.find(number) >= 0 ) return GAMB_CRAP; - Fixed
  • getBetTypeAsString() begs for switch() - Fixed (did not become better)

Ideas to enhance the gambling script:
  • Make the roulette offer advantages as well if the gambling skill is raised, not just the diminishing of penalties.
    • Add script that actually helps (has a chance to help) the player in case he has higher gambling than the host NPC.
    • Limit exploitableness by cool down timers if a player has won too much.
    • Add a random factor to host NPC gambling skill. This means that whenever a session starts, the host NPC's gambling skill is modified to a different value, depending on the base gambling value. So there is no sure way to know if someone spams the tables, he eventually comes out with a net win.
  • Add some special quest/encounter where the casino lord sends some bounty hunters after the player.
  • Additionally, if the player won a huge amount, some thugs NPC's will follow him and try to ambush him. Maybe these assassin would be able follow the player even to his tent, kill him and loot random stuff from there!
  • Items or quests that temporarily affect gambling.

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
4. Dialogues vs Scripts: Russian Roulette.
« Reply #4 on: December 18, 2015, 11:48:55 am »
4. Dialogues vs Scripts: Russian Roulette.

In this tutorial I will present two ways to write a Russian roulette game. The mechanic of the game is simple, the player can play Russian roulette with an NPC: A player puts a bet, a revolver has only 1 (in our example 2) bullet inside, the cylinder is rolled and the player pulls the trigger. If the player survives, he wins double, if not then... re-spawn time.

This example is used to illustrate how to solve the task in two different ways, one being without writing scripts (will use only pre-written scripts from dialogue.fos) the other with our own scripts.

Using only dialogues and the pre-written scripts from "dialogs.fos":

  • Save this dialogue file: russian_roulette_onlydiag.fodlg to "Server\dialogs"
  • Add the following line to "Server\dialogs\dialogs.lst": "$   2250   russian_roulette_onlydiag"
  • Add the dialogue number (2050) to an NPC in a map or on your usual test map.

Here is how it looks:

  • Kilgore: In both cases the caps get removed, there is no reward. (Yes, that is a mistake, when you install, make sure u fix that.)
« Last Edit: January 23, 2016, 10:04:04 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
5. Writing a simple quest: Kill all monsters on a specific location.
« Reply #5 on: December 18, 2015, 11:49:27 am »
5. Writing a simple quest: Kill all monsters on a specific location.

As suggested/asked for, here is a simple quest. The player needs to go to a location, where he needs to kill all mobs. The location is private, so others can't interrupt him. When the mobs are killed (RP: for some reason the NPC will know) the player gets some reward.

Step by step:
  • Creating the map:
    • Use the previous tutorials to make a new map (I copied a random desert encounter) and name it as you like. ("q_tut_killmobs.fomap")
    • Design your map as you wish and add some monsters to it.
      • Set ScriptName to the filename of the script you will make later, without the extension. ("quest_mob_kill")
      • Set FuncName to the function you will use to initialize the behavior of the monsters. ("critter_init")
      • Set ST_TEAM_ID to the same number at each mob. ("10")
      • Set ST_NPC_ROLE to the same number at each mob. ("66")
    • Add some Entires with EntireNumber set to 0 so the player can enter the map. The player will appear at one of these Entires randomly.
  • Setting up the map in WorldEditor:
    • Using the info from previous tutorials, create a new map data and a location for your map. Make sure you remember the location ID you gave. (mine was 91)
  • Creating a new dialogue.
    • Add 2 new local game variables to be used in the quest:
      • The LVAR_q_tut_killmobs_loc will be used to store the location ID for later, so we can delete it when quest finished.
      • The LVAR_q_tut_killmobs_prog will be used to keep track of the progress of the quest.
      • In "Server/scripts/_vars.fos" add the following lines to the header section:
        • #define LVAR_q_tut_killmobs_loc (701)
        • #define LVAR_q_tut_killmobs_prog (702)
      • In "Server/scripts/_vars.fos" add the following lines to the body section:
        •    $   701   1   q_tut_killmobs_loc   0   0   0   4
        • **********
        •    Stores the location ID generated by the tutorial quest, so it can be deleted later.
        • **********
        •    $   702   1   q_tut_killmobs_prog   0   0   0   4
        • **********
        •    Follows the progress of the tutorial quest.
        • **********
    • Create a new dialog that suits you quests needs, I will present only an example here of the core mechanics in a picture.
      • The dialog has to keep track of the quest progress using the LVAR_q_tut_killmobs_prog  variable.
      • When the quest is taken, a script shall be called that creates the location uniquely for the player, visible on the world map.
      • When the quest is finished, a script shall be called that deletes the location.
      • Reproduce the dialogue shown on the picture, as everything you need to know is visible.
      • Add the new dialogue to the dialogues list ("Server\dialogs\dialogs.lst") by adding the following line:
        • $   2201   quest_tut_killmobs
  • Create the script to spawn the location, set the behavior of the monsters and delete the location when the quest is finished:
    • Create a new script file ("Server\scripts\quest_mob_kill.fos").
    • Add it to the script list:
      • Edit the scripts list file ("Server\scripts\scripts.cfg") and add the following line to the quests section:
        • @ server module quest_mob_kill
  • At this point all should work fine, try and test it.

Understanding the script:
  • The script is written in a way, so you have easier time to know which parts to change when making your own quest.
  • void r_SpawnLoc(..)
    • Responsible to spawn the quest location/map.
    • Should be called from dialogue result.
    • Parameters besides the two Critter types (default for dialogues) are two zone coordinates to form a rectangle (top left corner, bottom right corner) in which the quest location will be randomized.
    • You can give an exact spot by entering the same values for the corners.
    • This function relies on two variables that are not controllable from the dialog, as maximum only 5 parameters could be given.
      • LVAR_q_tut_killmobs_loc - this game variable stores the location ID generated, so later it can be deleted.
      • LOCATION_quest_killmobs - this is not a game variable, but only a define, it stores the value of the location prototype created before (91)
      • (Relies means that you have to modify it in the script, and you can't set it through parameters, but later we might cover a way to solve this.)
  • void r_DeleteLoc(..)
    • Responsible for deleting the map, when the quest is finished.
    • Relies on the LVAR_q_tut_killmobs_loc variable as well, it will delete the location that is stored in this variable.
  • void spawnQuestLocationWithCoords(..)
    • This is the main logic for the location spawn, and the only variable you might need to change when you make more quests, is at the call to SetQuestGarbager(..), the LVAR_q_tut_killmobs_loc should be changed to your own variable name.



Pastebin link.

"Server/scripts/_vars.fos" - Header part

Code: [Select]
#define LVAR_q_tut_killmobs_loc (701)
#define LVAR_q_tut_killmobs_prog (702)

"Server/scripts/_vars.fos" - Body part

Code: [Select]
   $ 701 1 q_tut_killmobs_loc 0 0 0 4
   Stores the location ID generated by the tutorial quest, so it can be deleted later.

   $ 702 1 q_tut_killmobs_prog 0 0 0 4
   Follows the progress of the tutorial quest.

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
5.1 The location is given, but the position of mobs random.
« Reply #6 on: December 18, 2015, 11:54:03 am »
Explanation and code refinement in progress, until I do that, here is an example that works. (Need to add a dialogue, and a few variables which should be self explanatory if the code is understood.)

What the code does is, that it will try to put the critters on random positions surrounding a spot.

Main code - unrefined yet.

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
6. Perk: Mysterious Stranger
« Reply #7 on: December 24, 2015, 07:58:02 am »
6. Perk: Mysterious Stranger


If you have this perk, from time to time, a mysterious stranger appears out of the blue and tries to help you. This stranger might be there when you encounter difficulties in your travels, or sometimes even in remote zones, caves, hidden vaults, when you feel ill or are crippled. In the future he might even open locked doors for you, if you fail to do so.

Purpose:(One step toward RP.)

The reason for this perk, besides coolness, is to introduce the stat Charisma back into the game. (for servers who abandon it totally PvP wise) The perk should help people who want to role-play with higher Charisma than 1. The perk should be takeable with lower Charisma as well, but Charisma shall have a great effect on strength of the perk, this is why most of the timers depend on Charisma. Ofc, RP logic can surface as well, I leave to everyone's imagination why someone would help a charismatic person more often or for longer period of time. Even if the perk is reduced to a minimum of only random encounter appearance, or support perk, I suggest that Charisma dependency shall be dominant. The code is free for everyone to use it as they wish, gl, hf and may the stranger be with you.


From time to time, a mysterious stranger will help the player, regarding the rules below.

  • The Mysterious Stranger will spawn and act accordingly if the player has the perk and when:
    • The player enters a random encounter, will stay for a duration and help the player.
    • The player is attacked while being crippled, will try to doctor the player and then join the fight.
    • The player is below half health points and is attacked, will try to heal the player and then join the fight.
    • The player fails to open a lock, will try to open the lock and stay for a duration. - not implemented (yet?) -
  • The Cooldown of the Mysterious Stranger spawn shall be dependent on the player's Charisma, with the suggested formulas:
    • Chance for MS to spawn at random encounter: X + Y * CH + U * LK (Min V, Max Z)
    • Chance for MS to spawn for FA in non Town Control maps: X + CH * LK * U (Min V, Max Z)
    • Chance for MS to spawn for Doctor: X + CH * LK * U (Min V, Max Z)
    • FA and Doctor spawn block mechanic cooldown: X / CHA); (This is mechanic is explained in detail below)
    • Death time of Mysterious Stranger cooldown: X /CHA -  and shall be much higher than encounter cooldown.
    • Encounter spawn cooldown shall share the timer with with special spawns.
  • The Duration of the Mysterious Stranger aid shall be also dependent on the player's Charisma, with suggested formulas:
    • Duration of aid for Encounter shall last: X + Y * CH seconds in RT combat.
    • Duration of aid for Encounter shall last: X + Y * CH turns in TB combat. - unavailable due to SDK bugs regarding TB events -
  • The Strenght of the Mysterious Stranger shall depend on the Level and the Charisma of the player:
    • Level of the MS shall be the Level of the player + 3.
    • The Level cap of the Mysterious Stranger shall be dependent on the players Charisma.
    • The Perk, Stat and Inventory composition of the Mysterious Stranger shall better with the higher Charisma the player has.
    • A Random factor can be introduced when determining the Strength of the Mysterious Stranger. - not implemented -
    • If the player's luck is very low, the Mysterious Stranger can be Jinxed. Good Luck!
  • AI - The Mysterious Stranger shall behave as:
    • If the player is attacked, the attacker shall be added to the Mysterious Strangers target list, with medium priority.
    • If the player is crippled, the Mysterious Stranger will try to doctor, with high priority, but only once per spawn session.
    • If the player is below half health points, the Mysterious Stranger will try to First Aid, with high priority, but only once per spawn session.
    • If another player is attacking, the Mysterious Stranger shall change target to it. - not implemented -
  • Integration into projects/servers:
    • All of the parameters of the Mysterious Stranger mechanic shall be configurable.
    • Special triggers shall be disableable with macros from header.
    • Solutions shall be chosen, to conflict minimally with optimized code parts, like combat.fos
    • Integration shall be documented in the tutorials as well, just like the mechanics.
  • Testing:
    • Test file shall be supplied with a few scripts written to ease testing.
    • There shall be a use case testing document to follow for testers, or developers after modifications.

Known bugs:

Code review:
  • Wipe:  what's the point of checking if object is valid() when it's passed by reference?
  • Wipe: lot of unneded stuff at least from 2238/reloaded pov - own MS_LOG when you could use debug@WLog(), own get/set lvar instead of utils@Get/SetetLvar(),
  • Wipe: perkeditor and reloaded - hahahahahhaha
  • Wipe:  or better yet, return( chance >= Random(0,100) ); !
« Last Edit: January 01, 2016, 05:37:48 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
6.1 Perk - Mysterious Stranger - Installation
« Reply #8 on: December 31, 2015, 10:06:14 pm »
6.1 Perk - Mysterious Stranger - Installation

How to install:

  • Installing the module:
    • Copy the source from the pastebin links.
    • Add the source files to the script list ("Server\scripts\scripts.cfg"):
      • @ server module perk_ms   # Mysterious Stranger perk
      • @ server module perk_ms_test # Mysterious Stranger perk testing
    • Add the game variables to the variable list ("Server\scripts\_vars.fos"):
    • Edit the "main.fos" and add following codes:
    • Edit the "perks.fos" and add the following code:
    • You also need to use the perk editor to enable the Mysterious Stranger perk:
      • Start the PerkEditor found at tools.
      • Press "Load" and find the file named "Tools/PerkEditor/perks.xml"
      • Find the perk named "Mysterious Stranger" on the left side, and double click it.
      • Change "Disabled" to "Available on level" and press Apply.
      • You can optionally save it as well, but not necessary, if you save, save it in a new file.
    • Edit the "npc_ai.fos" file, chance the line defining the Mysterious Stranger AI to this one line (without the quotes):
      • " /* 125 Mysterious Stranger                   */ 100,  50,      0,    50,    1,  A_BeCareful, AW_Whomever,    BW_RangedOvMelee, CU_StimsHurtLo, D_None,       D_Stay,      0, 0,                    RA_None,             2000,       200,          80,   2 /* Tough Person                          */,   2 /* Tough Person                          */,  PID_STIMPAK, 0, 0, "
    • Add the following two lines to dialogue declarations:
      • $   2200   perk_ms_test
      • $   2201   perk_ms
    • Create the following dialogue files to "Server\dialogues\" and copy paste the content:
    • Add the following 2 lines to "Server\scripts\_dialogs.fos":
      • #define DIALOG_perk_ms_test                     (2200)
      • #define DIALOG_perk_ms_description              (2201)
  • Installing testing map:
    • Using the previous (basic) tutorials, create a map near new players spawn location, add an NPC to it, and add it to worldmap.
    • Add the test dialogue to the NPC, this NPC can be used to check variables, test a few functions later on.

Setting up the module:

Every variable that is used to configure the module, can be find at the "ms_perk_h.fos" header file. To use the MS perk in production code, simply leave the variables as they are, or change some of them as your sense of balance dictates.

Setting up the module for testing:

To test the module, with or without the test module, it is advised to set the configuration variables to the following:
  • __MS_ALLOW_DEBUG_LOG__ - if this variable is defined, it will allow testing logs, these can be checked at server interface.
  • The following parameters relate to Cooldowns, time is measured in real time seconds:
    • MS_BASE_RESPAWN_CD - change this value, to a shorter one, for faster encounter re-spawn: 30
    • MS_BASE_MEDICAL_SPAWN_CD - change this value, to a shorter one, for faster medical re-spawn: 20
    • MS_BASE_DEATH_CD - change this value to a shorter one, for faster rebirth of MS: 60
    • MS_BASE_RT_DURATION - change this to a higher value, so MS lasts longer per spawn: 3600
    • MS_RT_DURATION_FACTOR -  no need to change this, if you changed the base value for RT mode duration.
  • The rest of the parameters relate to the Encoutner and Medical spawn chances. Just change base and max values above 100 and you will have an automatic true roll, else keep them as they are and raise your chars charisma.
  • The last variable is "disabledMsMaps" is an array of maps, where the MS may not spawn for Medical emergencies. The TC town maps (only first map) are disabled by default, add more maps to disabled them, if you want to.

« Last Edit: January 01, 2016, 05:38:55 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
7. Blackjack card game - Specification
« Reply #9 on: January 09, 2016, 06:33:46 pm »
7. Blackjack card game.

Introducing a Blackjack card game into the RP of FOnline.

What would be the most reasonable way that gambling skill would affect the course of the game? (It shall be true to gambling in rl, shall be fun, and shall not be exploitable or afk farmed easily (or at all?).)

  • Dialogue based with possibility to attach a new GUI for it.
  • The pile of cards shall be pre-generated at each shuffle and not randomized at each draw.
  • Gambling skill difference between host and player is checked, against a  roll, as usual.
  • Game basic features:
    • Hit - Can hit, unless at 21 or higher, which is a bust.
    • Stand - Can stand down from 16.
    • Double down - Can be taken after getting the first 2 cards, doubles the bet, but only 1 card is given.
    • Split pairs (only once per deal) - Can split paris in two, doubling the bet, and playing them against dealer.
    • Insurance - Can be taken if dealer has an Ace revealed.
    • Even money - You have blackjack and dealer has an Ace revealed.
    • Surrender - When you have 2 cards, must be taken as first option.
  • The advantage of higher gambling skill:
    • Info over the the number of card packs used (which would be random 4 - 8 after each session).
    • Frequency of shuffling would be lower with better gambling + speech skill checks.
    • Card counting: available as long as gambling skill is higher than of host and the intellect of player is above X, as this is the easiest ways to get advantage over host.
    • Shuffle tracks: Occasionally on a critical or very hard roll on gambling + perception shuffling check, the player will be notified if there are way more high or low cards in the next X cards, if that is the case. ( 1/2 for low, or 3/4 high, have to make an estimation)
  • Disadvantage of lower gambling skill:
    • Basically missing out on the benefits, like: the character does not pay attention when the shuffling of cards happens, since he doesn't know that is important, so you miss that info.
  • Other possibilities:
    • Cheating 1: where the odds of high (7,8,9) or low cards (2,3,4) is reduced/raised, maybe the later could be added to some mini/repeatable quest or the host could be sweet talked /payed into changing the packs or whatever.. (would only create the possibility for it, but not the quest itself) In this case the host would give a hint for the player, until the cards are replaced.
    • Cheating 2: where the player will be notified if the hole card is an Ace or 10.
    • Cheating 3: Casino could cheat as well, cutting down some cards for player session, this should be able to be find out via mini quest/tip drunk gambler/speech etc. or simply by gambling check rolls.
  • Different casinos could have different rules and special offers to promote themselves:
    • Rule changes:
      • Double after split. (default enabled)
      • "Hit soft 17" - dealer has to draw a card if on soft 17.
      • "Dealer wins ties" - dealer will win ties.
      • "No Hole card" - dealer does not consult hole card until player finished his turns. (can't cheat to find out dealer's hole card)
      • "No Black Jack after splitting Aces" - no bonus on Black Jack after splitting Aces.
    • Side bets:
      • "Royal Match" - Pays for suit matches.
      • "Perfect Pair" - is an extra bet option before drawing cards, the player can bet if he gets pairs (Perfect, Colored, Mixed, No pairs)
      • "Lucky Ladies" - pays for initial cards value of 20. (Pair of Queen of Hearts, Suit Pair, etc)
    • Promotions:
      • "Real" Blackjack pays higher than regular Blackjack. (11 to 2 instead of 3 to 2). (Real mean Ace of spades with a Blackjack card.)

What to keep in sight:
  • It shall be configurable, so that mini quests or altering affects can differ from player to player and from session to session.
  • Shall be expandable later on to a graphical design.
  • Casino rules could be configurable, so that each session (or say,week) could be different, (or per player different odds) so that it can be tied to side quests to gather that info. (e.g.: Tip some wasted beggar or gambler to know the current situation / Or just the need to read the rules from dialogue so that botting is made harder.)
« Last Edit: January 19, 2016, 07:06:49 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
7. Black Jack card game - Installation
« Reply #10 on: January 09, 2016, 06:39:41 pm »
First things first. This, as well as the Mysterious Stranger is more like a module, rather than a tutorial, as it's complexity is too high to be of any proper use to teach stuff. Sorry about that.

7. Black Jack card game - Installation

Copy the following files to the "Server/scripts" folder:
Copy the following files to the "Server/dialogs" folder:

To complete the install, you also need to link stuff together, discussed several times in basic tutorial, like add "blackjack_dialogues.fos" to the script list, so the dialogue file can reference to it's scripts, you need to define a dialogue number to use the dialogue with and you need to create a map with an NPC or just add the dialogue to an NPC in a public map to try it out.


- To help testing of rare cases, you can find some use cases on the bottom of the blackjack class. I left their calls commented out, so you can see where to put them, but it's basically at the end of init.

Current situation:

- Some features are not implemented and I will not implement them myself, that remains to the player. The split, basic function of Blackjack is cut out, because it produces a lot of complexity and I did not bother to implement it. Other than this, every function works, but it is not as configurable as promised, someone wanting to assign quests to this module, will have to work him/her self on scripting.


- Fixed a a bug where when shoe ended there was no reshuffling.
- Added a few RP elements, shoe size can be seen, dealer's hole card can be seen and when shuffling happens, can be seen, depending on gambling and random check.
« Last Edit: January 20, 2016, 07:30:34 pm by Slowhand »

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
8. Adding or modifying sound effects.
« Reply #11 on: January 22, 2016, 06:43:36 pm »
8. Adding or modifying sound effects.

Modifying a sound effect - drinking nuka cola:
  • Download and convert a sound to .ogg format.
    • Search youtube for a sound effect that suits you. (Example: "_" - Opening bottle sound effect - Blopp )
    • Go to an online youtube downloader to download the sound in .mp3 format.  (Example: video grabby )
    • Use an audio converter to convert from .mp3 to .ogg format. (Example: I used VLC, you can follow "_" this tutorial for it.)
  • Once you got the .ogg file, test it with Winamp or VLC, and copy it into the "client/Data/" folder. (note: I used TotalCommander to copy files into .zip archives, it's easy with it, just browse the .zip file and copy the stuff into it, just like you would to a normal folder.)
  • Edit the file "drugs.fos", change the line 91 from "cr.PlaySound("nukacola.ogg", true);" to "cr.PlaySound("blopp.ogg", true);"
  • Test.

Testing it:
  • Once you logged in with your admin character, type the command: ~getaccess admin admin (In case you changed the admin password, use different password, if in doubt check the GM abuse tutorial at questions and answer section)
  • You should get a message on top of the screen stating: "Mercenaries don't die - they just go to hell to regroup."
  • Type "`give PID_NUKA_COLA 5 -p AdminCharName -legit" - this will give you 5 nuka colas. (Make sure you replace AdminCharName with your character's name)
  • Drink a nuka cola and listen. The new blopping sound should be in effect.

Offline Slowhand

  • Go for the eyes, Boo! Go for the eyes!
9. Adding or modifying graphical assets.
« Reply #12 on: September 18, 2023, 07:48:41 am »
9. Adding or modifying graphical assets.

Client side:
  • Creating a custom animation frame file (.fofrm), for the item to show on map:
    • Navigate to ..\Client\data\\art\items\ folder, and look up the structure of a fofrm file.
    • Create the fofrm file as described below, but to a temporary location of your choosing, copy the image to it as described later.
    • fps=10 what fps will the animation of the item run, if there is animation, this is default 10, or sometimes 8.
    • count=1 how many frames are the for the animation, if it's 1 then the item has no animation.
    • offs_x=-23 move the middle of the image 23 pixels to the left, if positive then to the right. If this is 0, then it's centered on the X axis.
    • offs_y=50 move the whole image 50 pixels up, so if an image is 100 pixels tall, it would be centered on the Y axis.
    • [dir_0] this will tell the engine that frames will come for direction 0, which is how the item would look facing North-East on the map.
    • frm_0=fish_circling1_01.png this is the image file for the first frame in given direction. If your item uses animations, there will be more of these with the suffix increasing
  • Create image file:
    • Download random image from web or create the one with your favorite paint tool, use .png file type when you save it.
    • Custom images can contain all colors in 32 bit range, you can use transparency as well, thus .png files work best, as size not an issue. Side note: Original fallout 1/2 image files contained only up to 240 different colors and color blue was used for transparent color, but you don't need to worry about that.
  • Create inventory image - repeat this process for the image that will be shown in inventory, if the item is picked up.
  • Copy the .fofrm files and their images to the respective folder structure:
    • ..\Client\data\\art\items\ for items on the map
    • ..\Client\data\\art\inven\ for items in the inventory
  • Alternatively, use a new zip file (example: to store the data, you need to copy the .fofrm files to:
    • ..\Client\data\\art\items\ for items on the map
    • ..\Client\data\\art\inven\ for items in the inventory
    • Add the new zip file ( to the config file to be loaded:
      • Edit ..\Client\DataFiles.cfg and add this new line data\ after data\

Server side:
  • Adding the new item to the server
    • Open the file ..\Server\proto\items\misc.foproto
    • Find an item you wish to copy the attributes from and copy paste lines starting with [Proto] and ending with an empty line. Example: ProtoId=539 -which is the Meat
    • Make sure to keep the empty line between items.
    • There are various parameters you can change, but for simplicity we just copy flags, weight etc. from well working items.
    • You will need to change the following parameters to:
      • To change the image when the fish is dropped on the ground on a map, change this: PicMap=art\items\fishing\freshmeat.fofrm
      • To change the image when the fish is in inventory, change this: PicInv=art\inven\fishing\fish_1.fofrm
      • Give a unique ProtoID number, for example 26760, should look like this: ProtoId=26760
  • Name and description to the new item
    • Edit the file at location: ..\Server\text\engl\FOOBJ.MSG and add the following line accordingly keeping the sorted nature of the numbers in front of lines.
    • {2676000}{}{Fish} for the name of the item
    • {2676001}{}{Could be a derivative of Salmon and radiation.} for the description (or info) of the item.
    • Notice that the number 2,676,000 is 100 times 26,760, and the two last digits will have a special meaning, denoting name or info, hence I colored them differently above.

Testing it:
  • Once you logged in with your admin character, type the command: ~getaccess admin admin (In case you changed the admin password, use different password, if in doubt check the GM abuse tutorial at questions and answer section)
  • You should get a message on top of the screen stating: "Mercenaries don't die - they just go to hell to regroup."
  • Type `give 26760 2 - this will give you 2 Fishes.
  • Hover over the Fish you got in inventory, click with default mouse cursor to show description info, and check if it's the same you have added.


« Last Edit: September 18, 2023, 02:17:44 pm by Slowhand »