Add specific tips for multiplayer sessions

A multi player loading screen will have possibility of showing single
and multi player tips while multi player tips are in favor.

Tips are now separated by categories. During loading those category
have an occurrence probability, where we are choosing a random category
based on chance and not by complete randomness. From there we just
picking a random tip from that category.
This commit is contained in:
ramtzok1 2025-01-13 11:14:56 +02:00 committed by Dunedan
parent 8482f25800
commit 1b797ce0a0
No known key found for this signature in database
GPG key ID: 885B16854284E0B2
15 changed files with 502 additions and 372 deletions

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c31454c04d360988e8f9cf9ee68268b092d79f700614e5f638611667be4b536
size 436952

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bd865f3ccb3f7314a3c5a8de7066e29130eab94ad0bf06071ba83d09a84cea29
size 320521

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:900e2fb80362d082fec16ed50b557234efcb681749983e05d6162e92edb6c1e1
size 286637

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9dcb0ce2371947ba961058804f190f2f4e09673f7ba2e3ff17118bfd7a42d437
size 376607

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c4d765ae7c73fcfff41f2f211d71a1dc83588bf49d0c498339e16794f5ec6a05
size 367320

View file

@ -6,7 +6,7 @@ function init(data)
"initData": data,
"progressBar": new ProgressBar(),
"quoteDisplay": new QuoteDisplay(),
"tipDisplay": new TipDisplay({ "tipScrolling": false }),
"tipDisplay": new TipDisplay({ "tipScrolling": false, "isOnLoadingScreen": true }),
"titleDisplay": new TitleDisplay(data)
};

View file

@ -1,11 +1,12 @@
/**
* This class is concerned with chosing and displaying tips about how to play the game.
* This class is concerned with choosing and displaying tips about how to play the game.
* This includes a text and one or more images.
*/
class TipDisplay
{
/**
* @param {boolean} initData.tipScrolling - Whether or not to enable the player to scroll through the tips and the tip images.
* @param {boolean} initData.isOnLoadingScreen - Whether or not the tip display is initialized by the game loading screen.
* @param {Array|undefined} hotloadData.tipFilesData - Hotloaded value storing last time's tipFilesData.
* @param {number|undefined} hotloadData.tipIndex - Hotloaded value pointing to a specific tip.
* @param {number|undefined} hotloadData.tipImageIndex - Hotloaded value pointing to a specific tip image.
@ -31,14 +32,15 @@ class TipDisplay
this.previousImageButton.tooltip = this.TooltipPreviousImage;
this.nextImageButton.tooltip = this.TooltipNextImage;
this.tipFilesData =
hotloadData?.tipFilesData ||
shuffleArray(
Engine.ReadJSONFile(this.TipFilesDataFile)
).map(tip => {
tip.imageFiles = shuffleArray(tip.imageFiles);
return tip;
});
if (initData.isOnLoadingScreen)
this.tipFilesData = this.getLoadingScreenTip();
else
this.tipFilesData =
hotloadData?.tipFilesData ||
shuffleArray(Engine.ReadJSONFile(this.TipFilesDataFile).map(category => category.files).flat().map(tip => {
tip.imageFiles = shuffleArray(tip.imageFiles);
return tip;
}));
this.currentTip = {};
this.tipIndex = -1;
@ -59,6 +61,39 @@ class TipDisplay
this.onTipImageIndexChange(hotloadData.tipImageIndex + 1);
}
/**
* Returns a randomized tip from a category.
* Choosing a category is randomized based on it occurrence probability.
* @returns {Array} - An array with a single element containing a tip object.
*/
getLoadingScreenTip()
{
const tipFiles = Engine.ReadJSONFile(this.TipFilesDataFile);
const category = this.getRandomWeightedCategory(tipFiles, Engine.HasNetClient());
const randomTip = pickRandom(category.files);
randomTip.imageFiles = shuffleArray(randomTip.imageFiles);
return [randomTip];
}
/**
* Returns a randomized category from an array of categories based on the probability weight.
* @param {boolean} isMultiplayer - True if we want to include the multiplayer category.
* @param {Array} tipFiles - An array containing all categories from the TipFilesDataFile.
* @returns {Object} - A randomized category object.
*/
getRandomWeightedCategory(tipFiles, isMultiplayer)
{
const totalProbability = tipFiles.reduce((sum, category) => sum + (isMultiplayer ? category.loadingScreenOccurrence_MP : category.loadingScreenOccurrence_SP), 0);
const random = Math.random() * totalProbability;
let cumulative = 0;
for (const category of tipFiles) {
cumulative += (isMultiplayer ? category.loadingScreenOccurrence_MP : category.loadingScreenOccurrence_SP);
if (random <= cumulative)
return category;
}
}
getHotloadData()
{
return {
@ -153,7 +188,7 @@ TipDisplay.prototype.TooltipNextImage = translate("Switch to the next image.");
TipDisplay.prototype.TipFilesDataFile = "gui/reference/tips/tipfiles.json";
/**
* Directory storing .txt files containing the gameplay tips.
* Directory storing .txt files containing the multi and single player tips.
*/
TipDisplay.prototype.TextPath = "gui/reference/tips/texts/";

View file

@ -0,0 +1,2 @@
DON'T CHEAT
Cheating in multiplayer games ruins the experience for others and undermines your own accomplishments. Focus on improving your skills through practice rather than exploits.

View file

@ -0,0 +1,3 @@
PASSWORD SAFETY
Never share your password, even with friends or family. Be cautious about entering your password on public or shared devices.
Wildfire Games staff or moderators will never ask you for your password.

View file

@ -0,0 +1,2 @@
SUSPICIOUS LINKS AND PHISHING
Do not open unexpected or suspicious links, especially those asking for login credentials. Always verify the authenticity of a link.

View file

@ -0,0 +1,2 @@
REPORT VIOLATIONS OF THE TERMS OF USE
If you see someone breaking the rules, report it to one of the moderators.

View file

@ -0,0 +1,2 @@
STAY FRIENDLY
Treat others online as you would in real life. Empathy can prevent toxic behavior and foster a welcoming community.

View file

@ -0,0 +1,2 @@
UNAUTHORIZED SOFTWARE
Do not use bots, hacks, or unauthorized software when playing multiplayer games. Such tools can result in bans or other penalties.

View file

@ -1,370 +1,434 @@
[
{
"textFile": "army_camp.txt",
"imageFiles": [
"army_camp.png"
"name": "Beginner",
"loadingScreenOccurrence_SP": 0.33,
"loadingScreenOccurrence_MP": 0.0,
"files": [
{
"textFile": "autoqueue.txt",
"imageFiles": [
"autoqueue.png"
]
},
{
"textFile": "barracks.txt",
"imageFiles": [
"barracks.png"
]
},
{
"textFile": "barter.txt",
"imageFiles": [
"barter.png"
]
},
{
"textFile": "cavalry_stable.txt",
"imageFiles": [
"cavalry_stable.png"
]
},
{
"textFile": "civic_center.txt",
"imageFiles": [
"civic_center.png"
]
},
{
"textFile": "defense_tower.txt",
"imageFiles": [
"defense_tower.png"
]
},
{
"textFile": "dock.txt",
"imageFiles": [
"dock.png"
]
},
{
"textFile": "fishing.txt",
"imageFiles": [
"fishing.png"
]
},
{
"textFile": "forge.txt",
"imageFiles": [
"forge_iber.png",
"forge_maur.png",
"forge_rome.png"
]
},
{
"textFile": "fortress.txt",
"imageFiles": [
"fortress_han.png",
"fortress_iber.png",
"fortress_maur.png"
]
},
{
"textFile": "gathering.txt",
"imageFiles": [
"gathering.png"
]
},
{
"textFile": "outposts.txt",
"imageFiles": [
"outposts.png"
]
},
{
"textFile": "palisades.txt",
"imageFiles": [
"palisades.png"
]
},
{
"textFile": "resource_counter.txt",
"imageFiles": [
"resource_counter.png"
]
},
{
"textFile": "spearmen.txt",
"imageFiles": [
"spearmen.png"
]
},
{
"textFile": "storehouse.txt",
"imageFiles": [
"storehouse_1.png",
"storehouse_2.png"
]
},
{
"textFile": "temple.txt",
"imageFiles": [
"temple_gaul.png",
"temple_greek.png",
"temple_pers.png"
]
},
{
"textFile": "trading.txt",
"imageFiles": [
"trading.png"
]
},
{
"textFile": "treasure.txt",
"imageFiles": [
"treasure.png"
]
}
]
},
{
"textFile": "arrow_ship.txt",
"imageFiles": [
"arrow_ship.png"
"name": "Intermediate",
"loadingScreenOccurrence_SP": 0.33,
"loadingScreenOccurrence_MP": 0.1,
"files": [
{
"textFile": "arrow_ship.txt",
"imageFiles": [
"arrow_ship.png"
]
},
{
"textFile": "biomes.txt",
"imageFiles": [
"biomes.png"
]
},
{
"textFile": "briton_war_dog.txt",
"imageFiles": [
"briton_war_dog.png"
]
},
{
"textFile": "catapults.txt",
"imageFiles": [
"catapults.png"
]
},
{
"textFile": "city_walls.txt",
"imageFiles": [
"city_walls.png"
]
},
{
"textFile": "elephant_stable.txt",
"imageFiles": [
"elephant_stable.png"
]
},
{
"textFile": "embassies.txt",
"imageFiles": [
"embassies.png"
]
},
{
"textFile": "formations.txt",
"imageFiles": [
"formations.png"
]
},
{
"textFile": "heroes.txt",
"imageFiles": [
"heroes.png"
]
},
{
"textFile": "loot.txt",
"imageFiles": [
"loot.png"
]
},
{
"textFile": "map_flare.txt",
"imageFiles": [
"map_flare.png"
]
},
{
"textFile": "pikemen.txt",
"imageFiles": [
"pikemen.png"
]
},
{
"textFile": "queue_orders.txt",
"imageFiles": [
"queue_orders.png"
]
},
{
"textFile": "ramming_ship.txt",
"imageFiles": [
"ramming_ship.png"
]
},
{
"textFile": "savanna_biome.txt",
"imageFiles": [
"savanna_biome.png"
]
},
{
"textFile": "siege_ship.txt",
"imageFiles": [
"siege_ship.png"
]
},
{
"textFile": "snapping.txt",
"imageFiles": [
"snapping.png"
]
},
{
"textFile": "territory_decay.txt",
"imageFiles": [
"territory_decay.png"
]
},
{
"textFile": "theater.txt",
"imageFiles": [
"theater.png"
]
},
{
"textFile": "war_elephants.txt",
"imageFiles": [
"war_elephants.png"
]
},
{
"textFile": "wonder.txt",
"imageFiles": [
"wonder_gaul.png",
"wonder_han.png"
]
}
]
},
{
"textFile": "autoqueue.txt",
"imageFiles": [
"autoqueue.png"
"name": "Advanced",
"loadingScreenOccurrence_SP": 0.33,
"loadingScreenOccurrence_MP": 0.3,
"files": [
{
"textFile": "army_camp.txt",
"imageFiles": [
"army_camp.png"
]
},
{
"textFile": "building_control.txt",
"imageFiles": [
"building_control.png"
]
},
{
"textFile": "carth_sacred_band.txt",
"imageFiles": [
"carth_sacred_band.png"
]
},
{
"textFile": "carth_shipyard.txt",
"imageFiles": [
"carth_shipyard.png"
]
},
{
"textFile": "celtic_war_barge.txt",
"imageFiles": [
"celtic_war_barge.png"
]
},
{
"textFile": "control_groups.txt",
"imageFiles": [
"control_groups.png"
]
},
{
"textFile": "default_formation.txt",
"imageFiles": [
"default_formation.png"
]
},
{
"textFile": "fire_ship.txt",
"imageFiles": [
"fire_ship.png"
]
},
{
"textFile": "freehand_position.txt",
"imageFiles": [
"freehand_position.png"
]
},
{
"textFile": "lighthouse.txt",
"imageFiles": [
"lighthouse.png"
]
},
{
"textFile": "mauryan_worker_elephant.txt",
"imageFiles": [
"mauryan_worker_elephant.png"
]
},
{
"textFile": "meroe_pyramids.txt",
"imageFiles": [
"meroe_pyramids.png"
]
},
{
"textFile": "nomad_mode.txt",
"imageFiles": [
"nomad_mode.png"
]
},
{
"textFile": "order_one_unit.txt",
"imageFiles": [
"order_one_unit.png"
]
},
{
"textFile": "persian_architecture.txt",
"imageFiles": [
"persian_architecture.png"
]
},
{
"textFile": "select_wounded_units.txt",
"imageFiles": [
"select_wounded_units.png"
]
},
{
"textFile": "shrine.txt",
"imageFiles": [
"shrine.png"
]
},
{
"textFile": "spartan_hoplites.txt",
"imageFiles": [
"spartan_hoplites.png"
]
},
{
"textFile": "syntagma.txt",
"imageFiles": [
"syntagma.png"
]
},
{
"textFile": "whales.txt",
"imageFiles": [
"whales.png"
]
}
]
},
{
"textFile": "barracks.txt",
"imageFiles": [
"barracks.png"
]
},
{
"textFile": "barter.txt",
"imageFiles": [
"barter.png"
]
},
{
"textFile": "biomes.txt",
"imageFiles": [
"biomes.png"
]
},
{
"textFile": "briton_war_dog.txt",
"imageFiles": [
"briton_war_dog.png"
]
},
{
"textFile": "building_control.txt",
"imageFiles": [
"building_control.png"
]
},
{
"textFile": "carth_sacred_band.txt",
"imageFiles": [
"carth_sacred_band.png"
]
},
{
"textFile": "carth_shipyard.txt",
"imageFiles": [
"carth_shipyard.png"
]
},
{
"textFile": "catapults.txt",
"imageFiles": [
"catapults.png"
]
},
{
"textFile": "cavalry_stable.txt",
"imageFiles": [
"cavalry_stable.png"
]
},
{
"textFile": "celtic_war_barge.txt",
"imageFiles": [
"celtic_war_barge.png"
]
},
{
"textFile": "city_walls.txt",
"imageFiles": [
"city_walls.png"
]
},
{
"textFile": "civic_center.txt",
"imageFiles": [
"civic_center.png"
]
},
{
"textFile": "control_groups.txt",
"imageFiles": [
"control_groups.png"
]
},
{
"textFile": "default_formation.txt",
"imageFiles": [
"default_formation.png"
]
},
{
"textFile": "defense_tower.txt",
"imageFiles": [
"defense_tower.png"
]
},
{
"textFile": "dock.txt",
"imageFiles": [
"dock.png"
]
},
{
"textFile": "elephant_stable.txt",
"imageFiles": [
"elephant_stable.png"
]
},
{
"textFile": "embassies.txt",
"imageFiles": [
"embassies.png"
]
},
{
"textFile": "fire_ship.txt",
"imageFiles": [
"fire_ship.png"
]
},
{
"textFile": "fishing.txt",
"imageFiles": [
"fishing.png"
]
},
{
"textFile": "forge.txt",
"imageFiles": [
"forge_iber.png",
"forge_maur.png",
"forge_rome.png"
]
},
{
"textFile": "formations.txt",
"imageFiles": [
"formations.png"
]
},
{
"textFile": "fortress.txt",
"imageFiles": [
"fortress_han.png",
"fortress_iber.png",
"fortress_maur.png"
]
},
{
"textFile": "freehand_position.txt",
"imageFiles": [
"freehand_position.png"
]
},
{
"textFile": "gathering.txt",
"imageFiles": [
"gathering.png"
]
},
{
"textFile": "heroes.txt",
"imageFiles": [
"heroes.png"
]
},
{
"textFile": "lighthouse.txt",
"imageFiles": [
"lighthouse.png"
]
},
{
"textFile": "loot.txt",
"imageFiles": [
"loot.png"
]
},
{
"textFile": "map_flare.txt",
"imageFiles": [
"map_flare.png"
]
},
{
"textFile": "mauryan_worker_elephant.txt",
"imageFiles": [
"mauryan_worker_elephant.png"
]
},
{
"textFile": "meroe_pyramids.txt",
"imageFiles": [
"meroe_pyramids.png"
]
},
{
"textFile": "nomad_mode.txt",
"imageFiles": [
"nomad_mode.png"
]
},
{
"textFile": "order_one_unit.txt",
"imageFiles": [
"order_one_unit.png"
]
},
{
"textFile": "outposts.txt",
"imageFiles": [
"outposts.png"
]
},
{
"textFile": "palisades.txt",
"imageFiles": [
"palisades.png"
]
},
{
"textFile": "persian_architecture.txt",
"imageFiles": [
"persian_architecture.png"
]
},
{
"textFile": "pikemen.txt",
"imageFiles": [
"pikemen.png"
]
},
{
"textFile": "queue_orders.txt",
"imageFiles": [
"queue_orders.png"
]
},
{
"textFile": "ramming_ship.txt",
"imageFiles": [
"ramming_ship.png"
]
},
{
"textFile": "resource_counter.txt",
"imageFiles": [
"resource_counter.png"
]
},
{
"textFile": "savanna_biome.txt",
"imageFiles": [
"savanna_biome.png"
]
},
{
"textFile": "select_wounded_units.txt",
"imageFiles": [
"select_wounded_units.png"
]
},
{
"textFile": "shrine.txt",
"imageFiles": [
"shrine.png"
]
},
{
"textFile": "siege_ship.txt",
"imageFiles": [
"siege_ship.png"
]
},
{
"textFile": "snapping.txt",
"imageFiles": [
"snapping.png"
]
},
{
"textFile": "spartan_hoplites.txt",
"imageFiles": [
"spartan_hoplites.png"
]
},
{
"textFile": "spearmen.txt",
"imageFiles": [
"spearmen.png"
]
},
{
"textFile": "storehouse.txt",
"imageFiles": [
"storehouse_1.png",
"storehouse_2.png"
]
},
{
"textFile": "syntagma.txt",
"imageFiles": [
"syntagma.png"
]
},
{
"textFile": "temple.txt",
"imageFiles": [
"temple_gaul.png",
"temple_greek.png",
"temple_pers.png"
]
},
{
"textFile": "territory_decay.txt",
"imageFiles": [
"territory_decay.png"
]
},
{
"textFile": "theater.txt",
"imageFiles": [
"theater.png"
]
},
{
"textFile": "trading.txt",
"imageFiles": [
"trading.png"
]
},
{
"textFile": "treasure.txt",
"imageFiles": [
"treasure.png"
]
},
{
"textFile": "war_elephants.txt",
"imageFiles": [
"war_elephants.png"
]
},
{
"textFile": "whales.txt",
"imageFiles": [
"whales.png"
]
},
{
"textFile": "wonder.txt",
"imageFiles": [
"wonder_gaul.png",
"wonder_han.png"
"name": "Multiplayer",
"loadingScreenOccurrence_SP": 0.0,
"loadingScreenOccurrence_MP": 0.6,
"files": [
{
"textFile": "dont_cheat.txt",
"imageFiles": [
"go_climb_a_mountain.png"
]
},
{
"textFile": "password_safety.txt",
"imageFiles": [
"give_them_a_volley.png"
]
},
{
"textFile": "report_violations.txt",
"imageFiles": [
"meeting.png"
]
},
{
"textFile": "stay_friendly.txt",
"imageFiles": [
"on_the_line.png"
]
},
{
"textFile": "prevent_phishing.txt",
"imageFiles": [
"denial.png"
]
},
{
"textFile": "unauthorized_software.txt",
"imageFiles": [
"defense_tower.png"
]
}
]
}
]

View file

@ -829,11 +829,14 @@ class CheckRefs:
self.files.append(fp)
self.roots.append(fp)
with open(ffp, encoding="utf-8") as f:
tips = load(f)
for tip in tips:
self.deps.append((fp, Path(f"gui/reference/tips/texts/{tip['textFile']}")))
for image in tip.get("imageFiles", []):
self.deps.append((fp, Path(f"art/textures/ui/tips/{image}")))
categories = load(f)
for category in categories:
for tips_category in category["files"]:
self.deps.append(
(fp, Path(f"gui/reference/tips/texts/{tips_category['textFile']}"))
)
for image in tips_category.get("imageFiles", []):
self.deps.append((fp, Path(f"art/textures/ui/tips/{image}")))
def add_rms(self):
self.logger.info("Loading random maps...")