From a890608fcf138e36db8dc779db72c24f4702d71a Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:09:39 -0700 Subject: [PATCH 1/8] Fixing a bug where looters could walk away from lootable building when ordered to drop an item --- wurst/Lootables/LootOperationComponent.wurst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wurst/Lootables/LootOperationComponent.wurst b/wurst/Lootables/LootOperationComponent.wurst index a52b5875..8d6aeec5 100644 --- a/wurst/Lootables/LootOperationComponent.wurst +++ b/wurst/Lootables/LootOperationComponent.wurst @@ -28,6 +28,7 @@ constant int PROGRESS_BAR_LENGTH = 20 constant colorA PROGRESS_BAR_FOREGROUND = colorA(0, 170, 0, 255) constant colorA PROGRESS_BAR_BACKGROUND = colorA(0, 64, 0, 255) constant real PROGRESS_BAR_UPDATE_PERIOD = 0.1 +constant real LOOTER_STANDING_POS_THRESHOLD_SQ = 64.0 * 64.0 LinkedList g_activeOperations HashMap g_looterToOperationMap = new HashMap() @@ -46,6 +47,7 @@ public class LootOperationComponent extends RealtimeUnitComponent private int m_secondsElapsed private real m_manaCost private bool m_isRunning + private vec2 m_looterPos // -------------------------------------------------------------------------- construct(IUnitMetadata owner) @@ -106,6 +108,11 @@ public class LootOperationComponent extends RealtimeUnitComponent if (getIsRunning() == false) return + + // Catch any edge-case order that would cause the looter to move while still looting + if (m_lootingUnit.getPos().distanceToSq(m_looterPos) > LOOTER_STANDING_POS_THRESHOLD_SQ) + cancel() + return let percentage01 = parameterize01(m_duration, 0.0, m_timer.getRemaining()) m_progress.report(percentage01) @@ -134,6 +141,8 @@ public class LootOperationComponent extends RealtimeUnitComponent let lootingPlayer = looter.getOwner() let cameraPos = getOwnerUnit().getPos() + m_looterPos = looter.getPos() + // Avoid implicit capture of 'this' by caching the result of m_lootableUnit let lootableUnitCached = getOwnerUnit() m_timer.doManual(duration, true, () -> onOperationFinished(lootableUnitCached)) From 77789b3082fa9bf1462febc500164c4564cf85ec Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:10:43 -0700 Subject: [PATCH 2/8] Reimplementing tips and... Fixed quest dialog crash in 1.33 patch --- .../PlayerSaveData_System_config.wurst | 0 wurst/Game/GameSetup.wurst | 4 +- wurst/Players/HumanPlayerComponent.wurst | 4 +- wurst/Players/PlayerCommands.wurst | 26 ++- wurst/Players/PlayerSetup.wurst | 5 +- wurst/Quests/Quests.wurst | 20 ++- wurst/Survivors/BuilderBuildMenus.wurst | 6 +- wurst/Tips/Tips.wurst | 166 ++++++++++-------- wurst/UI/HelpMenu.wurst | 6 +- 9 files changed, 146 insertions(+), 91 deletions(-) rename wurst/{ => Config}/PlayerSaveData_System_config.wurst (100%) diff --git a/wurst/PlayerSaveData_System_config.wurst b/wurst/Config/PlayerSaveData_System_config.wurst similarity index 100% rename from wurst/PlayerSaveData_System_config.wurst rename to wurst/Config/PlayerSaveData_System_config.wurst diff --git a/wurst/Game/GameSetup.wurst b/wurst/Game/GameSetup.wurst index d5199ed0..c6bae25c 100644 --- a/wurst/Game/GameSetup.wurst +++ b/wurst/Game/GameSetup.wurst @@ -158,7 +158,7 @@ public class GameSetup // -------------------------------------------------------------------------- private function showDifficultySelectionDialogToPlayer(player _player) - let playerSaveData = PlayerSaveData.getPlayerSaveData(_player) castTo PlayerSaveData_v801 + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(_player) if (playerSaveData == null) Log.debug("GameSetup", "showDifficultySelectionDialogToPlayer", _player.getId().toString(), " Player save data is null") return @@ -197,7 +197,7 @@ public class GameSetup let vm = difficultySelectDialog.getDataContext() let selectedDifficulty = vm.getSelectedDifficulty() - let playerSaveData = PlayerSaveData.getPlayerSaveData(_player) castTo PlayerSaveData_v801 + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(_player) if (playerSaveData != null) playerSaveData.selectedDifficulty = selectedDifficulty diff --git a/wurst/Players/HumanPlayerComponent.wurst b/wurst/Players/HumanPlayerComponent.wurst index 7e10adda..999ff880 100644 --- a/wurst/Players/HumanPlayerComponent.wurst +++ b/wurst/Players/HumanPlayerComponent.wurst @@ -211,12 +211,12 @@ public class HumanPlayerComponent extends PlayerComponent // -------------------------------------------------------------------------- function load(IPlayerSaveData saveData) - let saveDataVersioned = saveData castTo PlayerSaveData_v801 + let saveDataVersioned = saveData castTo PlayerSaveData_v800 setCameraDistance(saveDataVersioned.cameraDistance) // -------------------------------------------------------------------------- function save(IPlayerSaveData saveData) - let saveDataVersioned = saveData castTo PlayerSaveData_v801 + let saveDataVersioned = saveData castTo PlayerSaveData_v800 saveDataVersioned.cameraDistance = getCameraDistance() // -------------------------------------------------------------------------- diff --git a/wurst/Players/PlayerCommands.wurst b/wurst/Players/PlayerCommands.wurst index c9cc0118..41b7bb54 100644 --- a/wurst/Players/PlayerCommands.wurst +++ b/wurst/Players/PlayerCommands.wurst @@ -12,6 +12,8 @@ import ItemType // import VoteKick import PlayerUtility import Notifications +import PlayerSaveData +import Tips constant string COMMAND_BASE = "base" constant string COMMAND_BASES = "bases" @@ -27,6 +29,7 @@ constant string COMMAND_GIVELUMB = "givelumber" constant string COMMAND_GIVELUMB_ALIAS = "givel" constant string COMMAND_GIVELUMB_ALIAS2 = "gl" constant string COMMAND_SAVE = "save" +constant string COMMAND_TIPS = "tips" // constant string COMMAND_VOTEKICK = "votekick" public quest g_playerCommandsQuest @@ -163,6 +166,23 @@ function giveLumber() function savePlayerData() getChatCommandPlayer().getHumanPlayerComponentRequired().save(true) +// ============================================================================ +function toggleTips() + + let commandPlayer = getChatCommandPlayer() + + let saveData = PlayerSaveDataVersioned.getPlayerSaveData(commandPlayer) + if (saveData == null) + Log.error("Player save data is null") + return + + saveData.showTipsOnInterval = not saveData.showTipsOnInterval + Tips.showTipsForPlayer(commandPlayer, saveData.showTipsOnInterval) + + chatCommandPrintToPlayer(commandPlayer, "Turned tips " + (saveData.showTipsOnInterval ? "on" : "off")) + + PlayerSaveData.save(commandPlayer, false) + // // ============================================================================ // function startVoteKick() // let command = getChatCommand() @@ -184,8 +204,9 @@ function savePlayerData() function setupPlayerCommandsQuest() g_playerCommandsQuest = CreateQuest() QuestSetIconPath(g_playerCommandsQuest, "ReplaceableTextures\\WorldEditUI\\DoodadPlaceholder.blp") - QuestSetTitle(g_playerCommandsQuest, "Player Commands") + QuestSetTitle(g_playerCommandsQuest, "Chat Commands") QuestSetRequired(g_playerCommandsQuest, false) + QuestSetDescription(g_playerCommandsQuest, "A list of chat commands and how to use them") // ============================================================================ function registerDebugCommands() @@ -229,6 +250,9 @@ function registerDebugCommands() g_playerChatCommandHandler.registerCommandDefinition(COMMAND_SAVE, function savePlayerData) ..setDescription("Saves data for the player to a file on the disk") + g_playerChatCommandHandler.registerCommandDefinition(COMMAND_TIPS, function toggleTips) + ..setDescription("Toggles the displaying of tips every 30 seconds") + // g_playerChatCommandHandler.registerCommandDefinition(COMMAND_VOTEKICK, function startVoteKick) // ..setDescription("Start a vote to kick a player") // ..addStringArgument("PLAYER_NAME_PARTIAL_OR_ID", false) diff --git a/wurst/Players/PlayerSetup.wurst b/wurst/Players/PlayerSetup.wurst index 146f5246..03435594 100644 --- a/wurst/Players/PlayerSetup.wurst +++ b/wurst/Players/PlayerSetup.wurst @@ -7,6 +7,7 @@ import PlayerProperties import Difficulties import PlayerSaveData import HelpMenu +import Tips PlayerSetup array g_playerSetups @@ -51,7 +52,7 @@ public class PlayerSetup if (itemFindQualityProp != null) itemFindQualityProp.setBase(DifficultyScaling.getItemQualityScalar01(m_difficulty)) - let playerSaveData = PlayerSaveData.getPlayerSaveData(_player) castTo PlayerSaveData_v801 + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(_player) if (playerSaveData == null) Log.error("Player save data is null") return @@ -59,6 +60,8 @@ public class PlayerSetup if (playerSaveData.showTipsOnStartup) HelpMenu.show(_player) + Tips.showTipsForPlayer(_player, playerSaveData.showTipsOnInterval) + // -------------------------------------------------------------------------- function setHeroAbilityId(HeroAbilityGroup heroAbilityGroup, int abilId) let existingGroupAbilId = getHeroAbilityId(heroAbilityGroup) diff --git a/wurst/Quests/Quests.wurst b/wurst/Quests/Quests.wurst index e7a09c17..39931803 100644 --- a/wurst/Quests/Quests.wurst +++ b/wurst/Quests/Quests.wurst @@ -9,13 +9,14 @@ function setupQuests() QuestSetIconPath(discordQuest, "ReplaceableTextures\\CommandButtons\\BTNDiscord.tga") QuestSetTitle(discordQuest, "Discord") QuestSetRequired(discordQuest, false) - let discordQuestItem = QuestCreateItem(discordQuest) - QuestItemSetDescription(discordQuestItem, "|nJoin the Last Stand Discord server for the latest updates|n|n|cFFFFCC00{0}|r".format(DISCORD_LINK)) + QuestSetDescription(discordQuest, "Displays a link to the Last Stand Discord server.") + QuestItemSetDescription(QuestCreateItem(discordQuest), "|nJoin the Last Stand Discord server for the latest updates|n|n|cFFFFCC00{0}|r".format(DISCORD_LINK)) let survivorQuest = CreateQuest() QuestSetIconPath(survivorQuest, Icons.bTNVillagerMan) QuestSetTitle(survivorQuest, "Survivor (Jobless)") QuestSetRequired(survivorQuest, true) + QuestSetDescription(survivorQuest, "A description of a Survivor without an assigned job") QuestItemSetDescription(QuestCreateItem(survivorQuest), "The basic worker unit.") QuestItemSetDescription(QuestCreateItem(survivorQuest), "Give the Survivor a |cFFFFCC00Job Item|r to assign them a job.") QuestItemSetDescription(QuestCreateItem(survivorQuest), "Builds basic camp structures") @@ -26,6 +27,7 @@ function setupQuests() QuestSetIconPath(builderQuest, Icons.bTNPeasant) QuestSetTitle(builderQuest, "Survivor - |cFFFFCC00Builder|r") QuestSetRequired(builderQuest, true) + QuestSetDescription(builderQuest, "A description of the Builder survivor job") QuestItemSetDescription(QuestCreateItem(builderQuest), "The Builder can build more advanced structures for your camp.") QuestItemSetDescription(QuestCreateItem(builderQuest), "Give a Survivor the |cFFFFCC00Builders Tools|r item to assign them the Builder job.") QuestItemSetDescription(QuestCreateItem(builderQuest), "Build the |cFFFFCC00Builders Tools|r item in the |cFFFFCC00Workbench|r.") @@ -36,6 +38,7 @@ function setupQuests() QuestSetIconPath(militiaQuest, Icons.bTNMilitia) QuestSetTitle(militiaQuest, "Survivor - |cFFFFCC00Militia|r") QuestSetRequired(militiaQuest, true) + QuestSetDescription(militiaQuest, "A description of the Militia survivor job") QuestItemSetDescription(QuestCreateItem(militiaQuest), "The Militia is a hybrid unit that deals extra damage to non-elites.") QuestItemSetDescription(QuestCreateItem(militiaQuest), "Give a Survivor the |cFFFFCC00Rusty Sword|r item to assign them the Militia job.") QuestItemSetDescription(QuestCreateItem(militiaQuest), "Build the |cFFFFCC00Rusty Sword|r item in the |cFFFFCC00Armory|r.") @@ -49,6 +52,7 @@ function setupQuests() QuestSetIconPath(spearmanQuest, "ReplaceableTextures\\CommandButtons\\BTNBrigand.blp") QuestSetTitle(spearmanQuest, "Survivor - |cFFFFCC00Spearman|r") QuestSetRequired(spearmanQuest, true) + QuestSetDescription(spearmanQuest, "A description of the Spearman survivor job") QuestItemSetDescription(QuestCreateItem(spearmanQuest), "The Spearman is a ranged unit that deals extra damage to elites and air.") QuestItemSetDescription(QuestCreateItem(spearmanQuest), "Give a Survivor the |cFFFFCC00Spears|r item to assign them the Spearman job.") QuestItemSetDescription(QuestCreateItem(spearmanQuest), "Build the |cFFFFCC00Spears|r item in the |cFFFFCC00Spearman's Tent|r.") @@ -60,6 +64,7 @@ function setupQuests() QuestSetIconPath(marksmanQuest, Icons.bTNRifleman) QuestSetTitle(marksmanQuest, "Survivor - |cFFFFCC00Marksman|r") QuestSetRequired(marksmanQuest, true) + QuestSetDescription(marksmanQuest, "A description of the Marksman survivor job") QuestItemSetDescription(QuestCreateItem(marksmanQuest), "The Marksman is a ranged unit that deals extra damage to elites and bosses.") QuestItemSetDescription(QuestCreateItem(marksmanQuest), "Give a Survivor the |cFFFFCC00Hunting Rifle|r item to assign them the Marksman job.") QuestItemSetDescription(QuestCreateItem(marksmanQuest), "Build the |cFFFFCC00Hunting Rifle|r item in the |cFFFFCC00Armory|r.") @@ -72,9 +77,18 @@ function setupQuests() QuestSetIconPath(priestQuest, Icons.bTNPriest) QuestSetTitle(priestQuest, "Survivor - |cFFFFCC00Priest|r") QuestSetRequired(priestQuest, true) + QuestSetDescription(priestQuest, "A description of the Priest survivor job") QuestItemSetDescription(QuestCreateItem(priestQuest), "The Priest can heal friendly units.") QuestItemSetDescription(QuestCreateItem(priestQuest), "Give a Survivor the |cFFFFCC00Holy Book|r item to assign them the Priest job.") - QuestItemSetDescription(QuestCreateItem(marksmanQuest), "Build the |cFFFFCC00Holy Book|r item in the |cFFFFCC00Chapel|r.") + QuestItemSetDescription(QuestCreateItem(priestQuest), "Build the |cFFFFCC00Holy Book|r item in the |cFFFFCC00Chapel|r.") + + let acolyteQuest = CreateQuest() + QuestSetIconPath(acolyteQuest, Icons.bTNAcolyte) + QuestSetTitle(acolyteQuest, "Survivor - |cFFFFCC00Acolyte|r") + QuestSetRequired(acolyteQuest, true) + QuestSetDescription(acolyteQuest, "A description of the Acolyte survivor job") + QuestItemSetDescription(QuestCreateItem(acolyteQuest), "The Acolyte can build an Altar to revive dead heroes.") + QuestItemSetDescription(QuestCreateItem(acolyteQuest), "Give a Survivor the |cFFFFCC00Ceremonial Dagger|r item to assign them the Acolyte job.") // let engineerQuest = CreateQuest() // QuestSetIconPath(engineerQuest, Icons.bTNBloodElfPeasant) diff --git a/wurst/Survivors/BuilderBuildMenus.wurst b/wurst/Survivors/BuilderBuildMenus.wurst index 5902bde2..775bd4a1 100644 --- a/wurst/Survivors/BuilderBuildMenus.wurst +++ b/wurst/Survivors/BuilderBuildMenus.wurst @@ -99,7 +99,7 @@ class BuildingPageManager decrementPageIndex() setHighlightVisible(false) - let playerSaveData = (PlayerSaveData.getPlayerSaveData(m_player) castTo PlayerSaveData_v801) + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(m_player) if (playerSaveData == null) Log.debug("BBM", "onPrevPageButtonClicked", m_player.getId().toString(), " Player save data is null") return @@ -114,7 +114,7 @@ class BuildingPageManager incrementPageIndex() setHighlightVisible(false) - let playerSaveData = (PlayerSaveData.getPlayerSaveData(m_player) castTo PlayerSaveData_v801) + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(m_player) if (playerSaveData == null) Log.debug("BBM", "onNextPageButtonClicked", m_player.getId().toString(), " Player save data is null") return @@ -159,5 +159,5 @@ init PlayerSaveData.onLoadComplete().register() -> for i = 0 to bj_MAX_PLAYER_SLOTS - 1 if (g_pageManagers[i] != null and players[i].isIngame()) - let saveData = PlayerSaveData.getPlayerSaveData(players[i]) castTo PlayerSaveData_v801 + let saveData = PlayerSaveDataVersioned.getPlayerSaveData(players[i]) g_pageManagers[i].setHighlightVisible(saveData.showBuildMenuHighlight) \ No newline at end of file diff --git a/wurst/Tips/Tips.wurst b/wurst/Tips/Tips.wurst index 6afd689c..7e626a33 100644 --- a/wurst/Tips/Tips.wurst +++ b/wurst/Tips/Tips.wurst @@ -1,82 +1,96 @@ -// package Tips -// import HumanPlayers -// import DisplayTextToPlayer -// import WeightedSet -// import Icons -// import ProjectConstants -// import ColorUtility +package Tips +import HumanPlayers +import WeightedSet +import Icons +import ColorUtility +import ClosureTimers -// string array g_tips -// int g_tipIndex -// timer g_timer -// constant real SHOW_TIP_INTERVAL = 30.0 -// WeightedSet g_currentTipSet +string array g_tips +int g_tipIndex +constant real SHOW_TIP_INTERVAL = 60.0 +WeightedSet g_currentTipSet +force g_tipsForce = CreateForce() +quest g_tipsQuest -// quest g_tipsQuest -// questitem array g_tipsQuestItems +// ============================================================================ +public class Tips -// // ============================================================================ -// function showTipsToPlayers() + // -------------------------------------------------------------------------- + static function showTipsForPlayer(player p, bool showTips) + if (showTips) + g_tipsForce.addPlayer(p) + else + g_tipsForce.removePlayer(p) -// if (g_currentTipSet.isEmpty()) -// updateCurrentSet() +// ============================================================================ +function showTipsToPlayers() + if (g_currentTipSet.isEmpty()) + updateCurrentSet() -// let tip = g_currentTipSet.getRandom() - -// for p in g_PlayingHumanPlayers -// displayMessageToPlayer(p, tip) + DisplayTextToForce(g_tipsForce, g_currentTipSet.getRandom()) -// // ============================================================================ -// function updateCurrentSet() -// g_currentTipSet.clear() -// for i = 0 to g_tipIndex - 1 -// g_currentTipSet.add(g_tips[i], 1.0) - -// // ============================================================================ -// function registerTip(string tip) -// let fullTipString = ("Tip #" + (g_tipIndex + 1).toString() + ": ").colorize(Colors.gold) + tip - -// let questItem = QuestCreateItem(g_tipsQuest) -// QuestItemSetDescription(questItem, fullTipString) -// g_tipsQuestItems[g_tipIndex] = questItem - -// g_tips[g_tipIndex] = fullTipString - -// g_tipIndex++ - -// // ============================================================================ -// init -// g_timer = CreateTimer() -// g_timer.startPeriodic(SHOW_TIP_INTERVAL, function showTipsToPlayers) - -// g_tipsQuest = CreateQuest() -// QuestSetTitle(g_tipsQuest, "Tips") -// QuestSetRequired(g_tipsQuest, false) -// QuestSetIconPath(g_tipsQuest, Icons.bTNMagicalSentry) - -// g_currentTipSet = new WeightedSet() - -// initializeGeneralTips() - -// // ============================================================================ -// function initializeGeneralTips() -// registerTip("Type '-bases' to see easy, medium and hard bases. Type '-bases easy' to see only easy bases.") -// registerTip("Prepare during the day; fight during the night") -// registerTip("Some items can be given to Survivors to assign them a job") -// registerTip("Give the |cFFFFCC00Builder Tools|r item to a Survivor to assign them the |cFFFFCC00Builder|r job") -// registerTip("Give the |cFFFFCC00Sturdy Spears|r item to a Survivor to assign them the |cFFFFCC00Spearman|r job") -// registerTip("Give the |cFFFFCC00Holy Book|r item to a Survivor to assign them the |cFFFFCC00Priest|r job") -// registerTip("Give the |cFFFFCC00Hunting Rifle|r item to a Survivor to assign them the |cFFFFCC00Marksman|r job") -// registerTip("Upgrade your Camp Tent to a Camp House to be able to build Walls and Gates") -// registerTip("Search abandoned lootable structures to find |cFFFFCC00Materials|r, |cFFFFCC00Gold|r, |cFFFFCC00Items|r and |cFFFFCC00Survivors|r") -// registerTip("Zombies can spawn anywhere there is fog of war - even in your camp! Build |cFFFFCC00Lamp Posts|r to ensure that your camp is completely visible.") -// registerTip("The Last Stand is still being actively developed! Please report any bugs to our Discord server: |cFFFFCC00{0}|r".format(DISCORD_LINK)) -// registerTip("Join our |cFFFFCC00Discord|r server! |cFFFFCC00{0}|r".format(DISCORD_LINK)) -// registerTip("Change your alliances with other players by pressing |cFFFFCC00F1|r") -// registerTip("Survivors with the |cFFFFCC00Builder|r job can cut down trees") -// registerTip("Survivors with no job can harvest materials from trees without cutting them down") -// registerTip("|cFFFFCC00Spikes|r slow and damage nearby enemies") -// registerTip("Constructing a |cFFFFCC00Tent|r will make room for another Survivor in your camp") -// registerTip("Store extra items in a |cFFFFCC00Chest|r") -// registerTip("A |cFFFFCC00Camp Fire|r will slowly regenerate stamina for nearby Survivors") -// registerTip("Try to build Walls as soon as possible") \ No newline at end of file +// ============================================================================ +function updateCurrentSet() + g_currentTipSet.clear() + for i = 0 to g_tipIndex - 1 + g_currentTipSet.add(g_tips[i], 1.0) + +// ============================================================================ +function registerTip(string tip) + let fullTipString = ("Tip #" + (g_tipIndex + 1).toString() + ": ").colorize(Colors.gold) + tip + + QuestItemSetDescription(QuestCreateItem(g_tipsQuest), fullTipString) + + g_tips[g_tipIndex] = fullTipString + + g_tipIndex++ + +// ============================================================================ +function initializeGeneralTips() + registerTip("Type '-tips' to toggle the displaying of these tips") + registerTip("Type '-bases' to see easy, medium and hard bases. Type '-bases easy' to see only easy bases.") + registerTip("Use |cffffcc00Ctrl+R|r to rotate Wooden Fences and Gates |cffffcc00before building them|r") + registerTip("Give the |cFFFFCC00Builder Tools|r item to a Survivor to assign them the |cFFFFCC00Builder|r job") + registerTip("Give the |cFFFFCC00Sturdy Spears|r item to a Survivor to assign them the |cFFFFCC00Spearman|r job") + registerTip("Give the |cFFFFCC00Holy Book|r item to a Survivor to assign them the |cFFFFCC00Priest|r job") + registerTip("Give the |cFFFFCC00Hunting Rifle|r item to a Survivor to assign them the |cFFFFCC00Marksman|r job") + registerTip("Give the |cFFFFCC00Ceremonial Dagger|r item to a Survivor to assign them the |cFFFFCC00Acolyte|r job") + registerTip("|cffffcc00Builders|r can build more advanced structures and repair 2x as fast as regular Survivors") + registerTip("|cffffcc00Spearmen|r are medium range soldiers that deal extra damage to elites") + registerTip("|cffffcc00Militia|r are tanky melee units that are effective at killing Zombies") + registerTip("|cffffcc00Priests|r can heal friendly units and deal magic damage") + registerTip("|cffffcc00Marksmen|r attack slowly but have high chance to deal critical damage") + registerTip("|cffffcc00Acolytes|r can revive dead heroes") + registerTip("Search abandoned lootable buildings to find |cFFFFCC00gold|r, |cFFFFCC00lumber|r, |cFFFFCC00items|r and |cFFFFCC00survivors|r") + registerTip("Lootable buildings can be seen clearly even in fog of war") + registerTip("Use the 4 Waygates located in each quadrant of the map to travel long distances quickly") + registerTip("Who knows what you may discover when operating the |cffffcc00Scout Tower|r during the day...") + registerTip("Enemies can spawn anywhere there is fog of war - even in your camp! Build |cFFFFCC00Lamp Posts|r to ensure that your camp is completely revealed.") + registerTip("|cFFFFCC00Builders|r can cut down trees with the |cFFFFCC00Fell Trees|r research") + registerTip("Survivors and Builders can harvest lumber from trees without cutting them down") + registerTip("|cFFFFCC00Spikes|r slow and damage nearby enemies but do not block movement") + registerTip("Constructing a |cFFFFCC00Shelter|r will spawn additional Survivors") + registerTip("Each |cFFFFCC00Shelter|r grants bonus max HP to survivors") + registerTip("Store extra items in a |cFFFFCC00Chest|r") + registerTip("A |cFFFFCC00Camp Fire|r will slowly regenerate health stamina for nearby Survivors and can cook Raw Meat for bonus regen for a limited time") + registerTip("Looting large buildings grants better rewards but takes more time") + registerTip("Type '-split X' to split a stack of items in your inventory (0 is top left, 5 is bottom right)") + registerTip("If your HQ tent is destroyed you lose! If your hero dies he can be resurrected by an Acolyte.") + +// ============================================================================ +init + + for p in g_PlayingHumanPlayers + Tips.showTipsForPlayer(p, true) + + doPeriodically(SHOW_TIP_INTERVAL, (cb) -> showTipsToPlayers()) + + g_tipsQuest = CreateQuest() + QuestSetTitle(g_tipsQuest, "Tips") + QuestSetRequired(g_tipsQuest, false) + QuestSetIconPath(g_tipsQuest, Icons.bTNMagicalSentry) + QuestSetDescription(g_tipsQuest, "Shows a list of useful gameplay tips") + + g_currentTipSet = new WeightedSet() + + initializeGeneralTips() \ No newline at end of file diff --git a/wurst/UI/HelpMenu.wurst b/wurst/UI/HelpMenu.wurst index b4d62666..120306fc 100644 --- a/wurst/UI/HelpMenu.wurst +++ b/wurst/UI/HelpMenu.wurst @@ -62,7 +62,7 @@ class HelpMenuWindow extends Window newPlayersPageTextArea.setText("|cFFFFCC00Overview|r") newPlayersPageTextArea.addText("|nThe Last Stand is a game about surviving in a post apocalyptic world where undead rule the night. In order to survive you will need to build strong defenses and loot the abandoned civilization around you. Your base will only be as strong as the survivors defending it.") newPlayersPageTextArea.addText("|n|cFFFFCC00The First Day|r") - newPlayersPageTextArea.addText("|n· Find a green base using the \"-bases\" chat command and build your HQ Tent (item in hero inventory)") + newPlayersPageTextArea.addText("|n· Find a green base using the \"-bases\" chat command and build your HQ Tent (item in hero inventory). |cFFFFCC00If your HQ tent is destroyed you lose!|r") newPlayersPageTextArea.addText("|n· Once your HQ Tent is finished being constructed a Survivor will join your camp. Have him build 3 Shelters to make room for 3 more Survivors (they will spawn automatically). Once you have 4 Survivors order them to harvest lumber.") newPlayersPageTextArea.addText("|n· Barricade the entrance to your camp with a gate and as many walls as necessary. All entrances have been designed to fit 1 or 2 walls/gates neatly. You must rotate walls and gates BEFORE building them using Ctrl+R.") newPlayersPageTextArea.addText("|n· Spikes are effective at dealing with zombies but have a very short range. Build them next to your walls on the outside of your camp. They are invulnerable but with each attack they deal damage to themselves. Once they reach 1 hp they are disabled until they are repaired again.") @@ -98,7 +98,7 @@ class HelpMenuWindow extends Window ..setText("Show tips on startup") // Load state for show tips on startup checkbox - let playerSaveData = PlayerSaveData.getPlayerSaveData(m_player) castTo PlayerSaveData_v801 + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(m_player) if (playerSaveData == null) error("Player save data is null") @@ -128,7 +128,7 @@ class HelpMenuWindow extends Window private function setShowTipsOnStartupInternal(bool value) m_showTipsOnStartup = value - let playerSaveData = PlayerSaveData.getPlayerSaveData(m_player) castTo PlayerSaveData_v801 + let playerSaveData = PlayerSaveDataVersioned.getPlayerSaveData(m_player) if (playerSaveData == null) error("Player save data is null") playerSaveData.showTipsOnStartup = m_showTipsOnStartup From 0d5ecae1d6a7bcb42f3de1a21624d2ca0d31cc79 Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:35:00 -0700 Subject: [PATCH 3/8] Changing the toggle survivor job key from Z to Tab --- _build/dependencies/WurstCore | 2 +- _build/dependencies/wurstStdlib2 | 2 +- wurst/Tips/Tips.wurst | 2 ++ wurst/UI/SurvivorJobFrame.wurst | 2 +- wurst/UI/SurvivorJobPanel.wurst | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/_build/dependencies/WurstCore b/_build/dependencies/WurstCore index 33f1cae4..d028e69b 160000 --- a/_build/dependencies/WurstCore +++ b/_build/dependencies/WurstCore @@ -1 +1 @@ -Subproject commit 33f1cae45d7d73e0889122c05e87d5c02c9a226f +Subproject commit d028e69b40659c7b7b9c426a52dce7fad0bb12db diff --git a/_build/dependencies/wurstStdlib2 b/_build/dependencies/wurstStdlib2 index e4f39370..462fb217 160000 --- a/_build/dependencies/wurstStdlib2 +++ b/_build/dependencies/wurstStdlib2 @@ -1 +1 @@ -Subproject commit e4f393705ceb9d8911f59396927199e88350b716 +Subproject commit 462fb217ba82742640cb6b2965f0a0b17812b8d5 diff --git a/wurst/Tips/Tips.wurst b/wurst/Tips/Tips.wurst index 7e626a33..ecc7ff79 100644 --- a/wurst/Tips/Tips.wurst +++ b/wurst/Tips/Tips.wurst @@ -76,6 +76,8 @@ function initializeGeneralTips() registerTip("Looting large buildings grants better rewards but takes more time") registerTip("Type '-split X' to split a stack of items in your inventory (0 is top left, 5 is bottom right)") registerTip("If your HQ tent is destroyed you lose! If your hero dies he can be resurrected by an Acolyte.") + registerTip("Press 'TAB' to quickly toggle a selected Survivor's assigned job") + registerTip("Force a Survivor to |cffffcc00unlearn a job|r by ctrl+clicking the job in the Survivor job UI panel") // ============================================================================ init diff --git a/wurst/UI/SurvivorJobFrame.wurst b/wurst/UI/SurvivorJobFrame.wurst index ecd54dc2..92fbb0c7 100644 --- a/wurst/UI/SurvivorJobFrame.wurst +++ b/wurst/UI/SurvivorJobFrame.wurst @@ -189,7 +189,7 @@ public class SurvivorJobFrame extends Frame title = "{0} - {1}".format(m_jobTitle, "Requires {0}".format(m_itemName).colorize(Colors.gold)) if (m_job == SurvivorJobType.None) - title += " (|cffffcc00Z|r)" + title += " (|cffffcc00TAB|r)" if (m_enabledState == ENABLED) if (m_job != SurvivorJobType.None) diff --git a/wurst/UI/SurvivorJobPanel.wurst b/wurst/UI/SurvivorJobPanel.wurst index 6f607699..b15efba6 100644 --- a/wurst/UI/SurvivorJobPanel.wurst +++ b/wurst/UI/SurvivorJobPanel.wurst @@ -258,4 +258,4 @@ init ..showOnly(_player) g_playerSurvivorJobPanels.put(_player, survivorJobPanel) - onKeyPress(OSKEY_Z, () -> onToggleJobKeyPressed_ASYNC()) + onKeyPress(OSKEY_TAB, () -> onToggleJobKeyPressed_ASYNC()) From 039f6f02e1662fdd848b55650964d28300fd3b92 Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:48:30 -0700 Subject: [PATCH 4/8] Nvm ctrl+z instead of tab --- wurst/Tips/Tips.wurst | 2 +- wurst/UI/SurvivorJobFrame.wurst | 2 +- wurst/UI/SurvivorJobPanel.wurst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wurst/Tips/Tips.wurst b/wurst/Tips/Tips.wurst index ecc7ff79..cd1543a0 100644 --- a/wurst/Tips/Tips.wurst +++ b/wurst/Tips/Tips.wurst @@ -76,7 +76,7 @@ function initializeGeneralTips() registerTip("Looting large buildings grants better rewards but takes more time") registerTip("Type '-split X' to split a stack of items in your inventory (0 is top left, 5 is bottom right)") registerTip("If your HQ tent is destroyed you lose! If your hero dies he can be resurrected by an Acolyte.") - registerTip("Press 'TAB' to quickly toggle a selected Survivor's assigned job") + registerTip("Press 'Ctrl+Z' to quickly toggle a selected Survivor's assigned job") registerTip("Force a Survivor to |cffffcc00unlearn a job|r by ctrl+clicking the job in the Survivor job UI panel") // ============================================================================ diff --git a/wurst/UI/SurvivorJobFrame.wurst b/wurst/UI/SurvivorJobFrame.wurst index 92fbb0c7..47125999 100644 --- a/wurst/UI/SurvivorJobFrame.wurst +++ b/wurst/UI/SurvivorJobFrame.wurst @@ -189,7 +189,7 @@ public class SurvivorJobFrame extends Frame title = "{0} - {1}".format(m_jobTitle, "Requires {0}".format(m_itemName).colorize(Colors.gold)) if (m_job == SurvivorJobType.None) - title += " (|cffffcc00TAB|r)" + title += " (|cffffcc00Ctrl+Z|r)" if (m_enabledState == ENABLED) if (m_job != SurvivorJobType.None) diff --git a/wurst/UI/SurvivorJobPanel.wurst b/wurst/UI/SurvivorJobPanel.wurst index b15efba6..f9440431 100644 --- a/wurst/UI/SurvivorJobPanel.wurst +++ b/wurst/UI/SurvivorJobPanel.wurst @@ -258,4 +258,4 @@ init ..showOnly(_player) g_playerSurvivorJobPanels.put(_player, survivorJobPanel) - onKeyPress(OSKEY_TAB, () -> onToggleJobKeyPressed_ASYNC()) + onKeyPress(OSKEY_Z, OSKEY_META.CTRL, () -> onToggleJobKeyPressed_ASYNC()) From 62ccb09eac6f9f42e030397738b455c7c403b8b6 Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:48:45 -0700 Subject: [PATCH 5/8] Dagger does not sell for any resources --- wurst/Compile/Items/JobItems/Item_Dagger.wurst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wurst/Compile/Items/JobItems/Item_Dagger.wurst b/wurst/Compile/Items/JobItems/Item_Dagger.wurst index 401c59f8..d344fee4 100644 --- a/wurst/Compile/Items/JobItems/Item_Dagger.wurst +++ b/wurst/Compile/Items/JobItems/Item_Dagger.wurst @@ -32,7 +32,7 @@ public JobItemDefinition g_daggerDefinition ..setTooltipExtended(builder.getTooltipExtended()) ..setInterfaceIcon("ReplaceableTextures\\CommandButtons\\BTNSacrificialDagger.blp") ..setGoldCost(0) - ..setLumberCost(600) + ..setLumberCost(0) ..setStockInitial(1) ..setStockMaximum(3) ..setStockStartDelay(0) @@ -49,7 +49,7 @@ public JobItemDefinition g_daggerDefinition ..setTooltipExtended(g_daggerDefinition.getTooltipExtended()) ..setDescription(g_daggerDefinition.getDescription()) ..setGoldCost(0) - ..setLumberCost(600) + ..setLumberCost(0) ..setIconGameInterface(g_daggerDefinition.getInterfaceIcon()) ..setBuildTime(15) ..setButtonPositionX(0) From 6b44de0dfd2ff119878db4565bfe07477c043728 Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 22:51:16 -0700 Subject: [PATCH 6/8] Update Tips.wurst --- wurst/Tips/Tips.wurst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wurst/Tips/Tips.wurst b/wurst/Tips/Tips.wurst index cd1543a0..5a437e17 100644 --- a/wurst/Tips/Tips.wurst +++ b/wurst/Tips/Tips.wurst @@ -50,6 +50,8 @@ function initializeGeneralTips() registerTip("Type '-tips' to toggle the displaying of these tips") registerTip("Type '-bases' to see easy, medium and hard bases. Type '-bases easy' to see only easy bases.") registerTip("Use |cffffcc00Ctrl+R|r to rotate Wooden Fences and Gates |cffffcc00before building them|r") + registerTip("All base entrances have been designed to fit 1, 2 or 3 walls/gates exactly") + registerTip("Gates are weaker than walls but can be opened and closed") registerTip("Give the |cFFFFCC00Builder Tools|r item to a Survivor to assign them the |cFFFFCC00Builder|r job") registerTip("Give the |cFFFFCC00Sturdy Spears|r item to a Survivor to assign them the |cFFFFCC00Spearman|r job") registerTip("Give the |cFFFFCC00Holy Book|r item to a Survivor to assign them the |cFFFFCC00Priest|r job") From 83ff3626fe105e343c6c8daf7657765562b343d2 Mon Sep 17 00:00:00 2001 From: James Farris Date: Mon, 22 Aug 2022 23:35:49 -0700 Subject: [PATCH 7/8] UI polish --- imports/TLSFrames.fdf | 4 ++-- imports/war3map.wts | 4 ++-- wurst/UI/SurvivorJobFrame.wurst | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imports/TLSFrames.fdf b/imports/TLSFrames.fdf index f26d2ac5..2a518488 100644 --- a/imports/TLSFrames.fdf +++ b/imports/TLSFrames.fdf @@ -232,9 +232,9 @@ Frame "FRAME" "SurvivorJobFrame" { Frame "TEXT" "UnassignJobText" INHERITS "EscMenuLabelTextTemplate" { UseActiveContext, - Width 0.035, + Width 0.045, Height 0.008, - SetPoint BOTTOMLEFT, "SurvivorJobFrame", TOPLEFT, 0.0, 0.01 + SetPoint BOTTOM, "SurvivorJobFrame", TOP, 0.0, 0.01 FrameFont "MasterFont", 0.004,"", FontJustificationH JUSTIFYCENTER, } diff --git a/imports/war3map.wts b/imports/war3map.wts index 438b3662..2d482457 100644 --- a/imports/war3map.wts +++ b/imports/war3map.wts @@ -128,7 +128,7 @@ The Last Stand STRING 1326 { -Build more Shelters to continue unit production.,Build more Burrows to continue unit production.,Summon more Ziggurats to continue unit production.,Create more Moon Wells to continue unit production. +Upgrade your HQ Tent to be able to build more Shelters.,Build more Burrows to continue unit production.,Summon more Ziggurats to continue unit production.,Create more Moon Wells to continue unit production. } STRING 1327 @@ -1044,5 +1044,5 @@ Wall Low (Decoration) (No Pitch) STRING 3829 { -The number of Survivors your camp has room for over the total amount that your camp can sustain. Each Shelter provides room for 1 Survivor. Survivors will automatically spawn as long as you have more Shelters than Survivors alive. +The number of Survivors your camp has room for over the total amount that your camp can sustain. Each Shelter provides room for 1/2/3 Survivor(s). Survivors will automatically spawn as long as you have more Shelters than Survivors alive. } diff --git a/wurst/UI/SurvivorJobFrame.wurst b/wurst/UI/SurvivorJobFrame.wurst index 47125999..7b85707e 100644 --- a/wurst/UI/SurvivorJobFrame.wurst +++ b/wurst/UI/SurvivorJobFrame.wurst @@ -59,9 +59,9 @@ public class SurvivorJobFrame extends Frame m_hoverActionText = getFrame("UnassignJobText", 0) ..setParent(frameHandle) - ..setSize(0.035, 0.008) + ..setSize(0.045, 0.008) ..setLevel(10) - ..setPoint(FRAMEPOINT_BOTTOMLEFT, frameHandle, FRAMEPOINT_TOPLEFT, 0.0, 0.001) + ..setPoint(FRAMEPOINT_BOTTOM, frameHandle, FRAMEPOINT_TOP, 0.0, 0.001) ..setText("Unlearn") ..hide() From 08e5a80769b5161eeee330acb86010e3a050517f Mon Sep 17 00:00:00 2001 From: James Farris Date: Wed, 24 Aug 2022 20:46:54 -0700 Subject: [PATCH 8/8] Addressing a bug where survivors would spawn very far away when players build their HQ tent too quickly --- wurst/Survivors/Survivors.wurst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/wurst/Survivors/Survivors.wurst b/wurst/Survivors/Survivors.wurst index 919c51aa..db93a13d 100644 --- a/wurst/Survivors/Survivors.wurst +++ b/wurst/Survivors/Survivors.wurst @@ -22,6 +22,8 @@ import GameInstance import Spawning import Notifications +constant real SURVIVOR_SPAWN_TELEPORT_THRESHOLD_SQ = 4000.0*4000.0 + group g_tempGroup = CreateGroup() WeightedSet g_weightedSurvivorJobSet @@ -155,13 +157,19 @@ public class SurvivorUtility return null let spawnPointResult = getSpawnPoint(_player) - if (not spawnPointResult.succeeded) - Log.debug("[spawnSurvivorUnitForPlayer] Failed to find spawn point for survivor, trying again") - // try again - doAfter(1.0, () -> spawnSurvivorUnitForPlayer(_player)) - return null - let survivor = spawnSurvivorWithRandomJob(_player, spawnPointResult.spawnPoint, g_weightedSurvivorJobSet) + let campCenter = playerHumanComp.getCampCenter() + + var spawnPoint = spawnPointResult.spawnPoint + + // If a player builds their HQ tent before the grid-based spawn system is ready then the spawn + // point request will fail or it will succeed and return a spawn point in the subset of grid + // cells that have completed initialization which may be very far away from the camp center. + // In those cases just teleport the survivor to the camp center. + if (not spawnPointResult.succeeded or spawnPoint.distanceToSq(campCenter) > SURVIVOR_SPAWN_TELEPORT_THRESHOLD_SQ) + spawnPoint = campCenter + + let survivor = spawnSurvivorWithRandomJob(_player, spawnPoint, g_weightedSurvivorJobSet) survivor.issuePointOrderById(OrderIds.move, playerHumanComp.getCampCenter())