Hypoxic125/Sandbox – User

From Bohemia Interactive Community
Jump to navigation Jump to search
No edit summary
No edit summary
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{GVI|arma3|2.10}}
{{TOC|side}}
== Creating A Multiplayer Campaign ==
Creating a custom loading bar involves utilizing two images. A background image (typically desaturated) and a foreground image (full color).


A multiplayer campaign is a series of interconnected missions that follow a sequential order, creating a storyline that groups of players can enjoy together.
Key things to establish before you develop your own loading bar:
* Where will your control be defined
* In what direction will the loading bar flow in


Key things that a multiplayer campaign will include:
== Required Images ==
*Interconnected sequential missions
*Centralized location of common mission files to save on storage space
*Utilizes {{Link|createMPCampaignDisplay|MPCampaignDisplay}}
*Missions can be selected in the hosted server mission selection menu


== Creating the Missions ==
[[File:arma3 decal-rifle-gray.png|300px|frameless|right|Background Image - Desaturated]][[File:arma3 decal-rifle-pink.png|300px|frameless|right|Foreground Image - Full Color]]


If new to creating missions, it is advised that you ignore concerns about disk space and make each mission independent of the campaign mod. When you get more comfortable with how the file structure works, and have more confidence in your code, you can then move on to centralizing common files. Debugging missions within the mod structure is much more annoying, especially if your code is more prone to bugs/errors.
You will need to have two images:
* Background Image: Desaturated
* Foreground Image: Full Color


Be sure you structure your missions with multiplayer {{Link|Multiplayer_Scripting#Locality|locality}} in mind from the start. It is much more time-consuming to convert a single-player mission into a multiplayer mission.
These images will need to be converted from .png to .paa using TexView2


== File Structure ==


Now that you have your missions created, we can move on to the mod's file structure.


<span style="color: blue;">'''myModName'''</span>
== Building The Config ==
|--<span style="color: red;">addons</span>
    |--<span style="color: red;">myCampaignAddon</span>
      |--<span style="color: red;">campaign</span>
      |  |--<span style="color: red;">missions</span>
      |  |  |--myMission01.worldName
      |  |  |--myMission02.worldName
      |  |  |--myMission03.worldName
      |  |--<span style="color: red;">description.ext</span>
      |--<span style="color: green;">data</span>
      |--<span style="color: green;">functions</span>
      |--<span style="color: red;">$PBOPREFIX$</span>
      |--<span style="color: red;">config.cpp</span>
 
<span style="color: red;">Red</span> highlights indicate required files/folders
 
<span style="color: green;">Green</span> highlights indicate optional organization files/folders for shared campaign files
 
== Campaign Description.ext ==
 
Location: "\myModName\addons\myCampaignAddon\campaign\description.ext"
 
The campaign description file will dictate how the missions are structured within the campaign menus. Unlike a single-player campaign, we are going to be ignoring the mission flow aspect of the campaign description file so that the multiplayer campaign menu functions correctly.


'''Define Pixel Grid Macros'''
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
/* --------------------------------------------------
#define pixelScale          0.5
    Defining Templates for Inheriting Later
#define GRID_X              safezoneX
-------------------------------------------------- */
#define GRID_Y              safezoneY
 
#define GRID_W              (pixelW * pixelGridNoUIScale * pixelScale)
// Setting up no endings, cutscenes, or rewards (stuff for single-player campaigns).
#define GRID_H              (pixelH * pixelGridNoUIScale * pixelScale)
 
#define CENTER_X            ((getResolution select 2) * 0.5 * pixelW)
class NoEndings                    // For use in chapter class and class MissionDefault.
#define CENTER_Y            ((getResolution select 3) * 0.5 * pixelH)
{
    endDefault = "";
};
 
class MissionDefault : NoEndings    // For use in individual mission classes.
{
    lives = -1;                    // Not important with/without "Tickets" respawn template.
    noAward = 1;
    cutscene = "";
};
 
/* --------------------------------------------------
    Actual Campaign Class
-------------------------------------------------- */
 
class Campaign                                  // Contained inside CfgMissions - Holds other campaign classes such as "Apex", "Bootcamp", "EastWind".
{
    firstBattle = "Missions";                  // This will point to class Missions below which contains no information on purpose
                                                // so that the mp campaign menu will load all missions.
                                                // If info is given, no MPCampaignDisplay will be created.
    name = "$STR_CAMPAIGN_TITLE";
    briefingName = "$STR_CAMPAIGN_TITLE";
    author = "Hypoxic";
    overviewPicture = "myOverViewPicture.jpg";
    overviewText = "$STR_CAMPAIGN_DESCRIPTION";
    disableMP = 0;
 
    class MyCampaign : NoEndings                // Chapter class - Typically only use one chapter when dealing with MP Campaigns.
    {
        firstMission = "myMission01";
        name = "$STR_CAMPAIGN_TITLE";
        cutscene = "";
        end1 = "";
 
        class myMission01 : MissionDefault      // Mission class - Inherits default settings from class MissionDefault above.
        {
            end1 = "myMission02";              // Default Ending - "end1" call BIS_fnc_endMission will use this mission as next mission.
            myCustomEnd = "myMission01";        // Custom Ending - Defined in mission's class CfgDebriefing - Can be whatever you want.
            lost = "myMission01";              // You can send the lobby back to current mission on loss using this. Can also be custom.
            template = "myMission01.worldName";
        };
 
        class MyMission02 : MissionDefault
        {
            end1 = "MyMission03";
            lost = "MyMission02";
            template = "MyMission02.worldName";
        };
 
        class MyMission03 : MissionDefault
        {
            end1 = "";
            lost = "MyMission03";
            template = "MyMission03.worldName";
        };
    };
 
    class Missions                      // This is essentially a class with empty values. Used to invoke MPCampaignDisplay - See firstBattle above.
    {
        name = "$STR_CAMPAIGN_TITLE";
        cutscene = "";
        firstMission = "";
        end1 = "";
        end2 = "";
        end3 = "";
        end4 = "";
        end5 = "";
        end6 = "";
        lost = "";
    };
};
</syntaxhighlight>
</syntaxhighlight>


{{Feature|warning|An error in Description.ext WILL crash your game!}}
'''Define Image Positions'''
 
== Config.cpp ==
 
Config.cpp will contain all of our top-level classes we want our mod to modify in-game. In our campaign's case, this will mainly be CfgPatches and CfgMissions
 
 
'''CfgPatches'''
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
class CfgPatches
#define IMAGE_X    0
{
#define IMAGE_Y    0
    class MyCampaign
// IMAGE_W and IMAGE_H need to follow the aspect ratio of your image. This is for a 2:1 image.
    {
#define IMAGE_W    50
        name = "MyCampaign - A Campaign That Campaigns";
#define IMAGE_H    25
        author = "Hypoxic";
</syntaxhighlight>
        url = "https://arepublixchickentendersubsonsale.com/";


        requiredVersion = 2.10;
'''Create Config'''
        requiredAddons[] = { // Insert addons that your mod/campaign requires
            "A3_Functions_F"
        };
        units[] = {};
        weapons[] = {};
    };
};
</syntaxhighlight>
If your campaign addon contains units/weapons/etc, add them to units[] and weapons[], just like you would with a normal mod.


Import Base Classes
* [[GUI_Tutorial#Import_Classes_Via_import_Keyword_(Mission_Only)|Mission]]
* [[GUI_Tutorial#Declare_Classes_(Addon_Only)|Addon]]


'''CfgMissions'''
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
class CfgMissions
#define pixelScale          0.5
{
#define GRID_X              safezoneX
    class Campaigns
#define GRID_Y              safezoneY
    {
#define GRID_W              (pixelW * pixelGridNoUIScale * pixelScale)
        class MyCampaign
#define GRID_H              (pixelH * pixelGridNoUIScale * pixelScale)
        {
#define CENTER_X            ((getResolution select 2) * 0.5 * pixelW)
            directory = "\myModName\myCampaignAddon\campaign";
#define CENTER_Y            ((getResolution select 3) * 0.5 * pixelH)
        };
    };
    class MPMissions
    {
        class MyCampaign    // Campaign class from above
        {
            briefingName = "$STR_CAMPAIGN_TITLE";


            class MyMission01
#define IMAGE_X    0
            {
#define IMAGE_Y    0
                briefingName = "$STR_M01_MISSION_TITLE";
// IMAGE_W and IMAGE_H need to follow the aspect ratio of your image. This is for a 2:1 image.
                directory = "\myModName\myCampaignAddon\campaign\missions\myMission01.worldName";
#define IMAGE_W    50
            };
#define IMAGE_H    25


            class MyMission02
class TAG_MyDisplay {
            {
idd = -1;
                briefingName = "$STR_M02_MISSION_TITLE";
onLoad = "uiNamespace setVariable ['TAG_MyDisplay', _this select 0]";
                directory = "\myModName\myCampaignAddon\campaign\missions\myMission02.worldName";
onUnload = "uiNamespace setVariable ['TAG_MyDisplay', nil]";
            };


            class MyMission03
class Controls {
            {
class BackgroundCtrl: RscPicture {
                briefingName = "$STR_M03_MISSION_TITLE";
idc = -1;
                directory = "\myModName\myCampaignAddon\campaign\missions\myMission03.worldName";
x = IMAGE_X * GRID_W;
            };
y = IMAGE_Y * GRID_H;
        };
w = IMAGE_W * GRID_W;
    };
h = IMAGE_H * GRID_H;
onLoad = "uiNamespace setVariable ['TAG_BackgroundCtrl', _this select 0]";
onUnload = "uiNamespace setVariable ['TAG_BackgroundCtrl', nil]";
text = "pathTo\BackgroundImg.paa";
};
class ForegroundCtrlGroup: RscControlsGroupNoScrollBars {
    idc = -1;
    x = IMAGE_X * GRID_W;
    y = IMAGE_Y * GRID_H;
    w = IMAGE_W * GRID_W;
    h = IMAGE_H * GRID_H;
onLoad = "uiNamespace setVariable ['TAG_ForegroundCtrlGroup', _this select 0]";
onUnload = "uiNamespace setVariable ['TAG_ForegroundCtrlGroup', nil]";
    class controls {
        class ForegroundCtrl: RscPicture {
            idc = -1;
            x = 0 * GRID_W;
            y = 0 * GRID_H;
            w = IMAGE_W * GRID_W;
            h = IMAGE_H * GRID_H;
            onLoad = "uiNamespace setVariable ['TAG_ForegroundCtrl', _this select 0]";
            text = "pathTo\ForegroundImg.paa";
        };
    };
};
};
};
};
</syntaxhighlight>
</syntaxhighlight>


== PBO Prefix ==
[[Category:Arma 3: Editing]]
$PBOPREFIX$ is a file that sits in the root folder of an addon. If your mod contains multiple addons, you will need multiple $PBOPREFIX$ files. $PBOPREFIX$ is a namespace definition that tells the game the file path to navigate to your addon.
 
Examples of possible $PBOPREFIX$:
myMod\myCampaignAddon
z\myMod\myCampaignAddon
 
Please refer to the documentation on the addon packer of your choice.
 
[https://github.com/BrettMayson/HEMTT HEMTT] (Recommended): For repository-based mods
 
[https://github.com/winseros/pboman3 PBOMan3]
 
{{Link|Addon_Builder|Arma 3 - Addon Builder}}
 
 
== The MPCampaign Display ==
 
[[File:mpcampaigndisplay example filled.png|frame|right|A filled out MPCampaignDisplay]]
 
==== Defining Values ====
 
# '''Campaign Name''' - Defined In Either:
## CfgMissions.MPMissions.MyCampaign.briefingName
## Campaign description.ext: Campaign.briefingName
# '''Mission Name''' - Defined In Either:
## CfgMissions.MPMissions.MyMission01.briefingName
## Mission description.ext: briefingName
# '''See #2'''
# '''Author''' - Defined In:
## Campaign description.ext: Campaign.author
# '''Mission Overview Picture''' - Defined In:
## Mission description.ext: overviewPicture
# '''Mission Overview Text''' - Defined In:
## Mission description.ext: overviewText
 
{{Feature|important|Important: Although child classes will precede their parents, its best to be consistent with your naming}}

Latest revision as of 03:31, 27 April 2024

Creating a custom loading bar involves utilizing two images. A background image (typically desaturated) and a foreground image (full color).

Key things to establish before you develop your own loading bar:

  • Where will your control be defined
  • In what direction will the loading bar flow in

Required Images

Background Image - Desaturated
Foreground Image - Full Color

You will need to have two images:

  • Background Image: Desaturated
  • Foreground Image: Full Color

These images will need to be converted from .png to .paa using TexView2


Building The Config

Define Pixel Grid Macros

#define pixelScale          0.5
#define GRID_X              safezoneX
#define GRID_Y              safezoneY
#define GRID_W              (pixelW * pixelGridNoUIScale * pixelScale)
#define GRID_H              (pixelH * pixelGridNoUIScale * pixelScale)
#define CENTER_X            ((getResolution select 2) * 0.5 * pixelW)
#define CENTER_Y            ((getResolution select 3) * 0.5 * pixelH)

Define Image Positions

#define IMAGE_X    0
#define IMAGE_Y    0
// IMAGE_W and IMAGE_H need to follow the aspect ratio of your image. This is for a 2:1 image.
#define IMAGE_W    50
#define IMAGE_H    25

Create Config

Import Base Classes

#define pixelScale          0.5
#define GRID_X              safezoneX
#define GRID_Y              safezoneY
#define GRID_W              (pixelW * pixelGridNoUIScale * pixelScale)
#define GRID_H              (pixelH * pixelGridNoUIScale * pixelScale)
#define CENTER_X            ((getResolution select 2) * 0.5 * pixelW)
#define CENTER_Y            ((getResolution select 3) * 0.5 * pixelH)

#define IMAGE_X    0
#define IMAGE_Y    0
// IMAGE_W and IMAGE_H need to follow the aspect ratio of your image. This is for a 2:1 image.
#define IMAGE_W    50
#define IMAGE_H    25

class TAG_MyDisplay {
	idd = -1;
	onLoad = "uiNamespace setVariable ['TAG_MyDisplay', _this select 0]";
	onUnload = "uiNamespace setVariable ['TAG_MyDisplay', nil]";

	class Controls {
		class BackgroundCtrl: RscPicture {
			idc = -1;
			x = IMAGE_X * GRID_W;
			y = IMAGE_Y * GRID_H;
			w = IMAGE_W * GRID_W;
			h = IMAGE_H * GRID_H;
			onLoad = "uiNamespace setVariable ['TAG_BackgroundCtrl', _this select 0]";
			onUnload = "uiNamespace setVariable ['TAG_BackgroundCtrl', nil]";
			text = "pathTo\BackgroundImg.paa";
		};
		class ForegroundCtrlGroup: RscControlsGroupNoScrollBars {
    		idc = -1;
    		x = IMAGE_X * GRID_W;
    		y = IMAGE_Y * GRID_H;
    		w = IMAGE_W * GRID_W;
    		h = IMAGE_H * GRID_H;
			onLoad = "uiNamespace setVariable ['TAG_ForegroundCtrlGroup', _this select 0]";
			onUnload = "uiNamespace setVariable ['TAG_ForegroundCtrlGroup', nil]";
    		class controls {
        		class ForegroundCtrl: RscPicture {
            		idc = -1;
            		x = 0 * GRID_W;
            		y = 0 * GRID_H;
            		w = IMAGE_W * GRID_W;
            		h = IMAGE_H * GRID_H;
            		onLoad = "uiNamespace setVariable ['TAG_ForegroundCtrl', _this select 0]";
            		text = "pathTo\ForegroundImg.paa";
        		};
    		};
		};
	};
};