Jump to content
🛡️FORUMS ARE IN READ-ONLY MODE Read more... ×
Sign in to follow this  
IndeedPete

Concept Question - Saving / Changing / Using Variables throughout Campaign

Recommended Posts

Hello there,

I'm just thinking about ways on how to pass and change variables within a campaign structure. My current experiment relies on a central mission hub (HQ like in the official campaign) connecting to different missions based on the player's selection. This project is not that far developed that we could talk about the structure and BIS-like campaign description.FSMs yet. (But I will surely have to open some threads as soon as it comes to connecting the missions.) I have more basic troubles right now. At this point I want to pass the following values to later mission(s):

  • Player's Loadout - Including Weapons, Magazines, Items (Attachments, First Aid Kids, etc.), Vest, Helmet, Goggles, Backpack and Uniform
  • Player's Weapon-, Magazine-, Item-, Uniform-Pool (Player can buy all this stuff in a shop system.)
  • Player's Team - Basically a couple of classnames.
  • Player's Account Balance (Money)
  • Name of the Last Mission
  • Finishing Date + Time of the Last Mission
  • Weather Data of the Last Mission

As you might guess my goal is a smooth mission flow offering a lot of opportunities and choices to the player. In the central hub he can buy weapons and stuff, change clothes, talk to people (hence the Conv-System-Spin-Off you maybe stumbled across), playing sorts of mini-games like gambling or dueling other guys or he can simply go roaming the island for valuable stuff in order to increase his deposit. Also the player is free to pick missions (from a pre-defined set) and gear in the hub; he can also rest for a while and by that influence the starting time of the following mission. I'm nearly done with the hub building, programming and ambient stuff. What I'm missing is a way to transfer all this generated data to following missions of the campaign, i.e. if the player picks a certain gear in the hub he should actually wear it when going on the mission in question.

At the moment I can only think of using profileNameSpace and spam it with my data but that would be - let's say - not nice. There must be a better way. I also know about saveVar and saveStatus but I don't know how I should apply these commands while testing in the editor. Or if they work at all in Arma 3. And speaking about saving stuff into campaign space: Does anybody know how I can properly setup and TEST config files in a campaign environment? The whole shop system, mission selection and parameters rely on config files that I have to copy from one mission to another which is not only annoying but also very fault-prone. I'd truly love a "campaign editor" that would provide such environment where all this stuff works from the editor. Anyway, If you have any ideas on this whole matter please don't hesitate to share them with me and thank you very much for reading through all these chaotic thoughts. :)

Share this post


Link to post
Share on other sites

If you still have A2 on your PC you could check the PMC campaign, all the stuff you put in the SUV was consistent throughout the entire campaign.

Maybe this will show you a solution.

Something like a campaignNameSpace would definitely come handy though...

Share this post


Link to post
Share on other sites

Hi IndeedPete,

I was thinking about this as well here: http://forums.bistudio.com/showthread.php?173017-Vote-Rigging/page3

Out of interest, why does saving data to the profileNameSpace not appeal to you? It seems like an ideal solution to me - as long as you set up the global vars ok, then you can pass the information on to the next mission and there shouldn't be a problem as far as I can see. (Unless I'm missing something).

I haven't played with saveVar, but I would imagine it would be pretty similar/interchangeable. Nice ideas in your campaign as well - I like the gambling mini game idea - I tried to do that last year for MP, but I couldn't get the interface working well enough. If you need any "deck of cards" .paa's let me know and I'll send over what I have on my hard drive.

Share this post


Link to post
Share on other sites

As Das says whats wrong with using profileNamespace? You say spamming but if you pack all the info you want to save into an array that you know the format of then saving and loading the information wont be a problem and its easy to delete as you just Nil the array.

Share this post


Link to post
Share on other sites
If you still have A2 on your PC you could check the PMC campaign, all the stuff you put in the SUV was consistent throughout the entire campaign.

Maybe this will show you a solution.

Something like a campaignNameSpace would definitely come handy though...

Hm, I still have it on Steam, maybe I'll download it and take a look, thanks. Well, saveVar and loadVar as well as saveStatus seem to actually work with some kind of campaignNamespace. My problem is always how to test stuff in the editor without creating a campaign folder every time and switch to campaigns to test it. Or thinking about it, maybe I should focus on buidling a test campaign with a description.fsm first and see if my concept works at all. I'm just a little bit afraid of taking the Splendid one apart. I did already and I think I'm able to reconstruct some parts but I don't understand everything regarding BIS' hub system yet. It's sad that there's so little documentation on the new campaign creating features as they seem to offer great possibilities.

Out of interest, why does saving data to the profileNameSpace not appeal to you? It seems like an ideal solution to me - as long as you set up the global vars ok, then you can pass the information on to the next mission and there shouldn't be a problem as far as I can see. (Unless I'm missing something).

I haven't played with saveVar, but I would imagine it would be pretty similar/interchangeable. Nice ideas in your campaign as well - I like the gambling mini game idea - I tried to do that last year for MP, but I couldn't get the interface working well enough. If you need any "deck of cards" .paa's let me know and I'll send over what I have on my hard drive.

My pain with profileNameSpace origins in the fact that the variable is persistent and accessible in basically EVERY mission. Let's say the player played like five missions already. He made some cash, has good gear and this fancy Gucci leather jacket. :D It's all saved within the profileNameSpace. But what happens when he replays/reverts to a prior mission? The system would load is gear from the variables and he would be looking like the Master-Chief himself just to take out some low level insurgents meant to be used as - well "easy tutorial enemies".

I realise that this would just be a minor issue but it also works the other way round. Player replays first mission, values will be reset, switches to actual mission -> bam, gear and cash gone. It's just a minor issue as well as keeping the date and time consistent while the player replays prior missions but that's why I asked. If there was another way I'd gratefully take it. Maybe I should also work with some kind of stage system but that would require more values to save.

As for the gambling part, I already have a prototypic duel system where the player has to put in some cash and then gets transported to a random position within the "duel area". An AI will be spawned to hunt him down, first hit wins. I liked the first test runs as you never know from which side this f*cker is coming and without other AI in my own squad I really had to rely on my own eyes for spotting my opponent. Got nailed pretty good a couple of times, one hit wins can be tough against AI.

Anyway, second minigame idea was a card or dice game like blackjack / 17+4. So if you have some card pictures I'd be grateful to take them. I actually wanted to implement that somoehow using my conv system but maybe I'll make up an extra dialog for blackjack. The whole aim of this project is a "light" RPG experience but there's still a lot to do.^^

As Das says whats wrong with using profileNamespace? You say spamming but if you pack all the info you want to save into an array that you know the format of then saving and loading the information wont be a problem and its easy to delete as you just Nil the array.

True, but as stated above I'm not sure how to sort out replays/reverts. Or maybe I make one var (array) for every category and add sub-arrays after every mission and implement -as said- some kind of stage system? We'll see. If you have any other thoughts on this one please speak your mind.

Edited by IndeedPete

Share this post


Link to post
Share on other sites
My pain with profileNameSpace origins in the fact that the variable is persistent and accessible in basically EVERY mission. Let's say the player played like five missions already. He made some cash, has good gear and this fancy Gucci leather jacket
just make sure the values are reset if the player restarts the campaign - or at least at mission 1.

Maybe like you said have a value for mission 1,2,3, etc then copy the last values to the new one and update as needed, so if you replay mission 2 then you get the end values from mission 1 at the start of 2. then with the branches you have different values assigned as required based on decisions made through that play through.

Share this post


Link to post
Share on other sites
just make sure the values are reset if the player restarts the campaign - or at least at mission 1.

Maybe like you said have a value for mission 1,2,3, etc then copy the last values to the new one and update as needed, so if you replay mission 2 then you get the end values from mission 1 at the start of 2. then with the branches you have different values assigned as required based on decisions made through that play through.

Yes, something like that. I'm using values from a config in the prologue mission before the first hub and thus overwrite / create the persistent variables after.

Share this post


Link to post
Share on other sites

I've just had my first ugly run-in with profileNameSpace. I was wondering why the heck there were always simply wrong values used by my functions. For example, the date was first one and then two hours ahead of the start date from the config. Then the last mission entry was always filled with a mission I've never played. I've tried to set back everything by deleting and replacing the vars via "profileNameSpace setVariable ["MyVar", nil]. And they showed up empty in the debug console. However, my functions still used the wrong values. I've double checked everything, from function to config, turned my whole system upside down. I even tried to apply saveProfileNameSpace after "destroying" the variables. Still, no luck. The debug console would show empty vars while the scripts use wrong values. If I hinted them I could actually see those were wrong values I used for testing purposes days ago. So I restarted Arma 3 - no luck. Then I restarted my whole PC, thought maybe there were some leftovers cached or saved in RAM or whatever - no luck. Then, after literally hours of reworking, reviewing, setting, hinting, niling and killing it finally came to my mind to delete the <username>.vars.Arma3Profile. It seems to work properly - for now. So far, my experience with profileNameSpace... :bitch:

---------- Post added at 02:31 AM ---------- Previous post was at 02:12 AM ----------

Okay, please kill me. I've been using the wrong variables all along: For example, IP_MERCS_Mission to write into and IP_MERC_Mission to read from. Does anybody have a spare pair of eyes for me? Or the part of the brain that recognises letters and stuff? Mine's certainly broken.^^

Share this post


Link to post
Share on other sites

Pm me or post here I can take a look.

Don't mind bug hunting at all.

Share this post


Link to post
Share on other sites

Thank you but I think I've sorted these out. At least until I add more vars. For now I have four functions in total that access the profile namespace.

endMission executed in the end of each mission to save all my fancy vars:

_mainLoadout = [iP_Main] call IP_fnc_getLoadout;
_buddyLoadout = [iP_Buddy] call IP_fnc_getLoadout;

_money = IP_Main getVariable "IP_Money";
_team = IP_Main getVariable "IP_Team";
_clothes = IP_Main getVariable "IP_Clothes";
_mission = IP_Main getVariable ["IP_Mission", (getText(missionConfigFile >> "name"))];

profileNameSpace setVariable ["IP_MERCS_MainLoadout", _mainLoadout];
profileNameSpace setVariable ["IP_MERCS_BuddyLoadout", _buddyLoadout];

profileNameSpace setVariable ["IP_MERCS_Money", _money];
profileNameSpace setVariable ["IP_MERCS_Team", _team];
profileNameSpace setVariable ["IP_MERCS_Clothes", _clothes];
profileNameSpace setVariable ["IP_MERCS_Mission", _mission];

profileNameSpace setVariable ["IP_MERCS_Date", date];

saveProfileNamespace;
_this call BIS_fnc_endMission;

missionInit that runs preInit to set the date and time. (And later maybe also weather data and other stuff.)

_fixedDate = getNumber(missionConfigFile >> "fixedDate");

if (_fixedDate != 1) then {
_date = profileNameSpace getVariable ["IP_MERCS_Date", (getArray(missionConfigFile >> "MainValues" >> "startDate"))];
setDate _date;
};

mainInit (player init) that will be run on mission start (after first mission only):

_unit = [_this, 0, IP_Main, [objNull]] call BIS_fnc_param;

_mainLoadout = profileNameSpace getVariable ["IP_MERCS_MainLoadout", []];
_money = profileNamespace getVariable ["IP_MERCS_Money", getNumber(missionConfigFile >> "MainValues" >> "startMoney")]; 
_debts = profileNamespace getVariable ["IP_MERCS_Debts", getNumber(missionConfigFile >> "MainValues" >> "startDebts")]; 
_team = profileNamespace getVariable ["IP_MERCS_Team", []]; 
_clothes = profileNamespace getVariable ["IP_MERCS_Clothes", [getText(missionConfigFile >> "MainValues" >> "startUniform")]];

_unit setIdentity "main";
_unit setVariable ["IP_Money", _money];
_unit setVariable ["IP_Debts", _debts];
_unit setVariable ["IP_Team", _team];
_unit setVariable ["IP_Clothes", _clothes];
_unit setVariable ["IP_Picture", "Campaigns\IP_CMP_MERCS\img\main.jpg"];
_unit setVariable ["IP_Avatar", "Campaigns\IP_CMP_MERCS\img\mainAvatar.jpg"];
_unit setVariable ["IP_LiveFeed", true];
_unit setVariable ["IP_Faction", "MercsPlayer"];
_unit setVariable ["IP_BasicTCR", (call IP_fnc_calculateBasicCostRate)];

if (count _mainLoadout > 0) then {
[_unit, _mainLoadout] call IP_fnc_setLoadout;
} else {
removeAllWeapons _unit;
removeUniform _unit;
removeVest _unit;
removeGoggles _unit;
removeHeadgear _unit;
_unit addUniform (_clothes select 0);
};

_unit createDiarySubject ["Money", "Account"];
_unit createDiaryRecord ["Money", [(name _unit), "Account Balance: +" + str(_money) + "€"]];

buddyInit - A function to set-up the player's best bro who's helping to get started and offers support and advise through missions:

_unit = [_this, 0, IP_Buddy, [objNull]] call BIS_fnc_param;
_buddyLoadout = profileNameSpace getVariable ["IP_MERCS_BuddyLoadout", []];

_unit setIdentity "buddy";
_unit setVariable ["IP_LiveFeed", true];
_unit setVariable ["IP_Avatar", "Campaigns\IP_CMP_MERCS\img\buddyAvatar.jpg"];

if (count _buddyLoadout > 0) then {
[_unit, _buddyLoadout] call IP_fnc_setLoadout;
} else {
[_unit, ""] call IP_fnc_buddyEquipment;
};

It's working so far as I finally use the correct var names and didn't forget that damn little "S". :) I'm just struggeling to find a way to realisticly transfer the weather from one mission to another. I know how to save the data now; my problem is a script that at somewhat guesses a possible weather change with increasing spreading depending on the time passed. So, it shouldn't change within 10 minutes completely but within a few hours (in-game time) it would be okay. Also it's set in the middle of summer so extreme rain should be less probable than hot sunshine. Well, I have to work out something.^^

Lastly, if anybody wondered the same: You can actually access files in your Arma 3 Root\Campaigns folder which is simply awesome because now I don't have to copy my configs or functions lib every time I change something or make a new mission. It strangely even supports double #include statements which always caused CTDs in my stuff before.

Now I have a description.hpp stored in my Campaign dir together with all my configs and functions:

#define SET_MISSION_META(_stage, _name, _briefingName, _onLoadMission, _overviewText, _loadScreen, _overviewPicture, _briefing, _debriefing, _fixedDate) \
stage = _stage; \
name = _name; \
briefingName = _briefingName; \
onLoadName = _briefingName; \
onLoadMission = _onLoadMission; \
overviewText = _overviewText; \
loadScreen = _loadScreen; \
overviewPicture = _overviewPicture; \
briefing = _briefing; \
debriefing = _debriefing; \
fixedDate = _fixedDate;

#include "\Campaigns\IP_CMP_MERCS\cfg\defines.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\factions.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\functions.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\identities.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\mainValues.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\notifications.hpp"

#include "\Campaigns\IP_CMP_MERCS\cfg\conv\dialogs.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\rest\dialogs.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\dialogs.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\missions.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\personnel.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\weapons.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\magazines.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\items.hpp"
#include "\Campaigns\IP_CMP_MERCS\cfg\shop\clothes.hpp"

author = "IndeedPete";
allowSubordinatesTakeWeapons = 1;
enableCampaignSystems = 1;

All I have to do in my missions' descriptions.exts is now:

#include "\Campaigns\IP_CMP_MERCS\missions\description.hpp"
#include "missionConversations.hpp"

SET_MISSION_META(A, "Hub01", "Home Sweet Home", "", "", "Campaigns\IP_CMP_MERCS\img\Hub01_load.jpg", "Campaigns\IP_CMP_MERCS\img\Hub01_overview.jpg", 0, 0, 0)

// Mission Data
DuelStake = 1000;

It's funny though as the #includes require an additional "\" before the path while if you access files from scripts within the mission don't need that.

Share this post


Link to post
Share on other sites

I have found a simple way to preserve and pass weather data from mission to mission by using Meatball's weather templates. First, I've categorized his templates in "CLEAR", "RAINY" and "FOGGY". Once a mission ends the current category will be passed on via profileNameSpace. In the following mission, a function determines the weather outcome based on the passed category. With a probability of 50% the category will be changed, means that the former category has a higher chance to come up than the other two. Thus extreme weather changes in a short amount of time are not as likely but still possible. It's just a very raw prototype and I need to play around with the probability settings more but it's adding some diversity already, so I'm looking forward to develop it further.

setWeather:

_weatherTemplates = [
["CLEAR",
	["SUNNY",[0,1,5],[0.30,0,0,1,1]],
	["OVERCAST",[0,1,2],[0.50,0,0,2,2]]
],

["RAINY",
	["LIGHTRAIN",[1,2,3,5],[0.60,0.3,0.05,3,3]],
	["MEDIUMRAIN",[2,3,4],[0.70,0.5,0.05,4,4]],
	["RAINSTORM",[3],[0.80,0.9,0.1,5,5]]
],

["FOGGY",
	["LIGHTFOG",[0,2,5,6],[0.4,0,[0.2,0.01,10],0,0]],
	["MEDIUMFOG",[5,6,7],[0.4,0,[0.4,0.005,20],0,0]],
	["DENSEFOG",[6],[0.5,0,[0.4,0.0025,30],0,0]]
]
];

_getCategoryIndex = {
_index = switch (_this) do {
	case "CLEAR": {0};
	case "RAINY": {1};
	case "FOGGY": {2};
	default {0};
};

_index
};

_getDataIndex = {
_index = switch (_this) do {
	case "SUNNY": {1};
	case "OVERCAST": {2};
	case "LIGHTRAIN": {1};
	case "MEDIUMRAIN": {2};
	case "RAINSTORM": {3};
	case "LIGHTFOG": {1};
	case "MEDIUMFOG": {2};
	case "DENSEFOG": {3};
	default {1};
};

_index
};

private ["_categoryIndex", "_dataIndex"];

_lastWeatherCategory = toUpper([_this, 0, "CLEAR", [""]] call BIS_fnc_param);
_newWeather = [_this, 1, [], [[]]] call BIS_fnc_param;

if (count _newWeather > 0) then {
_categoryIndex = (_newWeather select 0) call _getCategoryIndex;
if (count _newWeather > 1) then {
	_dataIndex = (_newWeather select 1) call _getDataIndex;
} else {
	_dataIndex = 1 + round(random(count(_weatherTemplates select _categoryIndex) - 2));
};
} else {
_lastCategoryIndex = _lastWeatherCategory call _getCategoryIndex;
_categoryArr = switch (_lastCategoryIndex) do {
	case 0:	{[0, 0, 1, 2]};
	case 1: {[0, 1, 1, 2]};
	case 2: {[0, 1, 2, 2]};
};
_categoryIndex = _categoryArr call BIS_fnc_selectRandom;
_dataIndex = 1 + round(random(count(_weatherTemplates select _categoryIndex) - 2));
};

_weatherInitialArray = (_weatherTemplates select _categoryIndex) select _dataIndex;
_weatherInitialSettings = _weatherInitialArray select 2;

_weatherInitialOvercast = _weatherInitialSettings select 0;
_weatherInitialRainSnow = _weatherInitialSettings select 1;
_weatherInitialFog = _weatherInitialSettings select 2;
_weatherInitialWindEW = _weatherInitialSettings select 3;
_weatherInitialWindNS = _weatherInitialSettings select 4;	

skipTime -24;
86400 setOvercast _weatherInitialOvercast;
0 setRain _weatherInitialRainSnow;
86400 setFog _weatherInitialFog;
setWind [_weatherInitialWindEW, _weatherInitialWindNS, true];
skipTime 24;
sleep 1;
simulWeatherSync;

_category = (_weatherTemplates select _categoryIndex) select 0;
_data = ((_weatherTemplates select _categoryIndex) select _dataIndex) select 0;
[_category, _data]

Share this post


Link to post
Share on other sites
Sign in to follow this  

×