diff --git a/src/game/gameFlow.ts b/src/game/gameFlow.ts index 3ba8b40..b0d0c05 100644 --- a/src/game/gameFlow.ts +++ b/src/game/gameFlow.ts @@ -3,224 +3,88 @@ import { MessageService, MessageFileName } from '../utils/MessageService' import { CommentPoster } from '../rdrama/services/CommentPoster'; import { RidersPhase } from '../phases/riders'; import { HuntPhase } from '../phases/hunt'; -import { HandleSetup } from '../phases/setup'; +import { HandleSetup as SetupPhase } from '../phases/setup'; +import { travelPhase as TravelPhase } from '../phases/travel'; +import { ActionPhase } from '../phases/action'; class GameFlow { - gameState: GameState; - constructor(gameState: GameState) { - this.gameState = gameState; - } + static async executeCurrentPhase(gameState: GameState, userInput?: string) { + GameFlow.cleanupGameState(gameState); - async executeCurrentPhase(userInput?: string) { - this.cleanupGameState(); - - switch (this.gameState.phase) { + switch (gameState.phase) { case PHASE_ENUM.SETUP: // Handle the setup phase, e.g., initial purchases - await HandleSetup.handleSetupPhase(this.gameState, this, userInput); + await SetupPhase.handleSetupPhase(gameState, userInput); break; case PHASE_ENUM.START_TURN: - await this.startTurn(); + await GameFlow.startTurn(gameState); break; case PHASE_ENUM.ACTION_CHOICE: - await this.actionChoice(userInput) + await ActionPhase.actionChoice(gameState, userInput) break; case PHASE_ENUM.TRAVEL: // Handle travel logic - await this.handleTravel(); + await TravelPhase.handleTravel(gameState, userInput); break; case PHASE_ENUM.FORT: // Handle interactions at the fort - await HandleSetup.handleSetupPhase(this.gameState, this, userInput); + await SetupPhase.handleSetupPhase(gameState, userInput); break; case PHASE_ENUM.HUNT: // Handle hunting logic - await HuntPhase.handleHunt(this.gameState, this, userInput); + await HuntPhase.handleHunt(gameState, userInput); break; case PHASE_ENUM.RIDERS_ATTACK: // Handle a riders attack phase - await RidersPhase.handleRidersAttack(this.gameState, this, userInput); + await RidersPhase.handleRidersAttack(gameState, userInput); break; case PHASE_ENUM.EVENT: // Handle random events that can occur - await this.handleRandomEvent(); break; case PHASE_ENUM.MOUNTAIN: // Handle mountain traversal challenges - await this.handleMountain(); break; case PHASE_ENUM.DEATH: // Check if conditions leading to the player's death have been met break; default: - console.error("Unknown game phase:", this.gameState.phase); + console.error("Unknown game phase:", gameState.phase); break; } } - private cleanupGameState(): void { + static cleanupGameState(gameState: GameState): void { // Ensure all expenditures are non-negative - this.gameState.amountSpentOnFood = Math.max(0, this.gameState.amountSpentOnFood); - this.gameState.amountSpentOnAmmunition = Math.max(0, this.gameState.amountSpentOnAmmunition); - this.gameState.amountSpentOnClothing = Math.max(0, this.gameState.amountSpentOnClothing); - this.gameState.amountSpentOnMiscellaneousSupplies = Math.max(0, this.gameState.amountSpentOnMiscellaneousSupplies); + gameState.amountSpentOnFood = Math.max(0, gameState.amountSpentOnFood); + gameState.amountSpentOnAmmunition = Math.max(0, gameState.amountSpentOnAmmunition); + gameState.amountSpentOnClothing = Math.max(0, gameState.amountSpentOnClothing); + gameState.amountSpentOnMiscellaneousSupplies = Math.max(0, gameState.amountSpentOnMiscellaneousSupplies); // Round expenditures and cash to integers - this.gameState.amountSpentOnFood = Math.floor(this.gameState.amountSpentOnFood); - this.gameState.amountSpentOnAmmunition = Math.floor(this.gameState.amountSpentOnAmmunition); - this.gameState.amountSpentOnClothing = Math.floor(this.gameState.amountSpentOnClothing); - this.gameState.amountSpentOnMiscellaneousSupplies = Math.floor(this.gameState.amountSpentOnMiscellaneousSupplies); - this.gameState.totalMileageWholeTrip = Math.floor(this.gameState.totalMileageWholeTrip); + gameState.amountSpentOnFood = Math.floor(gameState.amountSpentOnFood); + gameState.amountSpentOnAmmunition = Math.floor(gameState.amountSpentOnAmmunition); + gameState.amountSpentOnClothing = Math.floor(gameState.amountSpentOnClothing); + gameState.amountSpentOnMiscellaneousSupplies = Math.floor(gameState.amountSpentOnMiscellaneousSupplies); + gameState.totalMileageWholeTrip = Math.floor(gameState.totalMileageWholeTrip); //Round Cash to two digits - this.gameState.cashLeftAfterInitialPurchases = Math.floor(this.gameState.cashLeftAfterInitialPurchases * 100) / 100; + gameState.cashLeftAfterInitialPurchases = Math.floor(gameState.cashLeftAfterInitialPurchases * 100) / 100; } - private async startTurn(): Promise { + static async startTurn(gameState: GameState): Promise { // Update total mileage up through the previous turn - this.gameState.totalMileageUpThroughPreviousTurn = this.gameState.totalMileageWholeTrip; + gameState.totalMileageUpThroughPreviousTurn = gameState.totalMileageWholeTrip; // Toggle fort option flag - this.gameState.fortOptionFlag = !this.gameState.fortOptionFlag; + gameState.fortOptionFlag = !gameState.fortOptionFlag; - this.gameState.phase = PHASE_ENUM.ACTION_CHOICE; - await this.gameState.save() + gameState.phase = PHASE_ENUM.ACTION_CHOICE; + await gameState.save() - this.executeCurrentPhase() - } - - private async actionChoice(userInput?: string): Promise { - let responseMessage = ""; - userInput = userInput?.toLowerCase() - console.log("userInput", userInput); - switch (userInput) { - case "1": // Hunt - if (this.gameState.amountSpentOnAmmunition < 40) { - responseMessage = `You do not have enough ammunition to hunt. Purchase more ammunition first.\n\n`; - if (this.gameState.fortOptionFlag) { - responseMessage += `Do you want to:\n2. Continue\n3. Stop at the Next Fort\n\n` - } else { - responseMessage += `Do you want to:\n2. Continue\n\n` - } - await MessageService.statusUpdate(this.gameState, responseMessage) - } else { - this.gameState.phase = PHASE_ENUM.HUNT; - this.gameState.totalMileageWholeTrip -= 45; - await this.gameState.save() - this.executeCurrentPhase() - } - - return; - break; - case "2": // Continue - this.gameState.phase = PHASE_ENUM.TRAVEL; - await this.gameState.save() - this.executeCurrentPhase() - return; - break; - case "3": // Stop at the Next Fort (if applicable) - if (this.gameState.fortOptionFlag) { - this.gameState.subPhase = 2 - this.gameState.totalMileageWholeTrip -= 45; - this.gameState.phase = PHASE_ENUM.FORT; - await this.gameState.save() - this.executeCurrentPhase() - return; - } else { - responseMessage += "⚠️ There is no fort option available at this time.\n\n" - responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n\n` - await MessageService.statusUpdate(this.gameState, responseMessage) - return; - } - break; - default: - console.log("Starting turn..."); - if (userInput !== undefined || userInput === "" || userInput === "start") { - responseMessage += "⚠️ Invalid Selection.\n\n" - } - //check for illness or injury - if (this.gameState.illnessFlag || this.gameState.injuryFlag) { - responseMessage += this.handleDoctor(); - if (this.gameState.phase === PHASE_ENUM.DEATH) { - this.executeCurrentPhase() - return; - } - } - - // Warn the player if food is low - if (this.gameState.amountSpentOnFood < 13) { - responseMessage += `You only have ${this.gameState.amountSpentOnFood} pounds of food.\n\n YOU'D BETTER DO SOME HUNTING OR BUY FOOD AND SOON!!!!\n\n`; - } - - if (this.gameState.fortOptionFlag) { - responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n3. Stop at the Next Fort\n\n` - } else { - responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n\n` - } - await MessageService.statusUpdate(this.gameState, this.gameState.lastPrompt + responseMessage) - this.gameState.lastPrompt = responseMessage; - break; - } - - return; - } - - private async handleTravel(userInput?: string | number): Promise { - let responseMessage = ""; - - if (!userInput || userInput?.toString().toLowerCase() === "start") { - responseMessage = "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; - await MessageService.statusUpdate(this.gameState, responseMessage); - return; - } - - // Check if userInput is a number or can be converted to a valid number - if (isNaN(Number(userInput))) { - responseMessage = "Invalid input. Please enter a number.\n\n" - responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; - await MessageService.statusUpdate(this.gameState, responseMessage); - return; // Exit if input is not a valid number - } - - let eatingChoice: number = parseInt(userInput.toString(), 10); - - // Validate eating choice - if (eatingChoice < 1 || eatingChoice > 3) { - responseMessage = "Invalid choice.\n\n" - responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; - await MessageService.statusUpdate(this.gameState, responseMessage); - return; - } - - // Calculate potential food consumption without updating the game state yet - let potentialAmountSpentOnFood = this.gameState.amountSpentOnFood - (8 + 5 * eatingChoice); - - // Check if the potential amount spent on food is negative - if (potentialAmountSpentOnFood < 0) { - // If it would result in a negative value, inform the user they can't eat that well - responseMessage = "YOU CAN'T EAT THAT WELL\n\n"; - responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; - await MessageService.statusUpdate(this.gameState, responseMessage); - return; // Exit the method to prevent further execution - } else { - // If the amount is sufficient, update the game state with the new amount - this.gameState.amountSpentOnFood = potentialAmountSpentOnFood; - } - - // Calculate total mileage - this.gameState.totalMileageWholeTrip += 200 + (this.gameState.amountSpentOnAnimals - 220) / 5 + 10 * Math.random(); - this.gameState.blizzardFlag = this.gameState.insufficientClothingFlag = false; - - this.gameState.phase = PHASE_ENUM.RIDERS_ATTACK; - - // Save the game state after making changes - await this.gameState.save(); - - // Continue with the game flow - this.executeCurrentPhase(); + GameFlow.executeCurrentPhase(gameState) } private async handleEncounter(): Promise { @@ -236,29 +100,29 @@ class GameFlow { } - private handleDoctor(): string { + static handleDoctor(gameState: GameState): string { let responseMessage: string = "" // Handle illness and injury - if (this.gameState.illnessFlag && this.gameState.injuryFlag) { + if (gameState.illnessFlag && gameState.injuryFlag) { responseMessage += `You were sick and and injured ` - } else if (this.gameState.illnessFlag) { + } else if (gameState.illnessFlag) { responseMessage += `You were sick and ` } else { responseMessage += `You were injured and ` } - this.gameState.cashLeftAfterInitialPurchases -= 20; - if (this.gameState.cashLeftAfterInitialPurchases < 0) { - if (this.gameState.illnessFlag) this.gameState.death = DEATH_REASON_ENUM.ILLNESS - if (this.gameState.injuryFlag) this.gameState.death = DEATH_REASON_ENUM.INJURY - this.gameState.phase = PHASE_ENUM.DEATH + gameState.cashLeftAfterInitialPurchases -= 20; + if (gameState.cashLeftAfterInitialPurchases < 0) { + if (gameState.illnessFlag) gameState.death = DEATH_REASON_ENUM.ILLNESS + if (gameState.injuryFlag) gameState.death = DEATH_REASON_ENUM.INJURY + gameState.phase = PHASE_ENUM.DEATH return ""; } else { responseMessage += `The Doctors bill was $20\n\n` } - this.gameState.injuryFlag = false; - this.gameState.illnessFlag = false; + gameState.injuryFlag = false; + gameState.illnessFlag = false; return responseMessage; diff --git a/src/phases/action.ts b/src/phases/action.ts new file mode 100644 index 0000000..aa8df0d --- /dev/null +++ b/src/phases/action.ts @@ -0,0 +1,81 @@ +import GameState, { PHASE_ENUM } from '../game/gameState'; +import GameFlow from '../game/gameFlow'; +import { MessageService } from '../utils/MessageService'; + +export class ActionPhase { + static async actionChoice(gameState: GameState, userInput?: string): Promise { + let responseMessage = ""; + userInput = userInput?.toLowerCase() + console.log("userInput", userInput); + switch (userInput) { + case "1": // Hunt + if (gameState.amountSpentOnAmmunition < 40) { + responseMessage = `You do not have enough ammunition to hunt. Purchase more ammunition first.\n\n`; + if (gameState.fortOptionFlag) { + responseMessage += `Do you want to:\n2. Continue\n3. Stop at the Next Fort\n\n` + } else { + responseMessage += `Do you want to:\n2. Continue\n\n` + } + await MessageService.statusUpdate(gameState, responseMessage) + } else { + gameState.phase = PHASE_ENUM.HUNT; + gameState.totalMileageWholeTrip -= 45; + await gameState.save() + GameFlow.executeCurrentPhase(gameState) + } + + return; + break; + case "2": // Continue + gameState.phase = PHASE_ENUM.TRAVEL; + await gameState.save() + GameFlow.executeCurrentPhase(gameState) + return; + break; + case "3": // Stop at the Next Fort (if applicable) + if (gameState.fortOptionFlag) { + gameState.subPhase = 2 + gameState.totalMileageWholeTrip -= 45; + gameState.phase = PHASE_ENUM.FORT; + await gameState.save() + GameFlow.executeCurrentPhase(gameState) + return; + } else { + responseMessage += "⚠️ There is no fort option available at this time.\n\n" + responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n\n` + await MessageService.statusUpdate(gameState, responseMessage) + return; + } + break; + default: + console.log("Starting turn..."); + if (userInput !== undefined || userInput === "" || userInput === "start") { + responseMessage += "⚠️ Invalid Selection.\n\n" + } + //check for illness or injury + if (gameState.illnessFlag || gameState.injuryFlag) { + responseMessage += GameFlow.handleDoctor(gameState); + if (gameState.phase === PHASE_ENUM.DEATH) { + GameFlow.executeCurrentPhase(gameState) + return; + } + } + + // Warn the player if food is low + if (gameState.amountSpentOnFood < 13) { + responseMessage += `You only have ${gameState.amountSpentOnFood} pounds of food.\n\n YOU'D BETTER DO SOME HUNTING OR BUY FOOD AND SOON!!!!\n\n`; + } + + if (gameState.fortOptionFlag) { + responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n3. Stop at the Next Fort\n\n` + } else { + responseMessage += `Do you want to:\n1. Hunt\n2. Continue\n\n` + } + await MessageService.statusUpdate(gameState, gameState.lastPrompt + responseMessage) + gameState.lastPrompt = responseMessage; + break; + } + + return; + } +} \ No newline at end of file diff --git a/src/phases/hunt.ts b/src/phases/hunt.ts index 99a3e24..726e2be 100644 --- a/src/phases/hunt.ts +++ b/src/phases/hunt.ts @@ -4,16 +4,16 @@ import { HandleShooting } from './shooting'; import { MessageService } from '../utils/MessageService'; export class HuntPhase { - static async handleHunt(gameState: GameState, gameFlow: GameFlow, userInput?: string): Promise { + static async handleHunt(gameState: GameState, userInput?: string): Promise { switch (gameState.subPhase) { case 0: // Initial Logic - await HuntPhase.initialLogic(gameState, gameFlow); + await HuntPhase.initialLogic(gameState); break; case 1: // Shooting Logic - await HuntPhase.shootingLogic(gameState, gameFlow, userInput); + await HuntPhase.shootingLogic(gameState, userInput); break; case 2: // Outcome Logic - await HuntPhase.outcomeLogic(gameState, gameFlow); + await HuntPhase.outcomeLogic(gameState); break; default: console.error("Unknown subphase in HuntPhase"); @@ -22,7 +22,7 @@ export class HuntPhase { } - static async initialLogic(gameState: GameState, gameFlow: GameFlow,): Promise { + static async initialLogic(gameState: GameState): Promise { let responseMessage = ''; responseMessage += HandleShooting.handleShooting(gameState); gameState.subPhase = 1; @@ -31,7 +31,7 @@ export class HuntPhase { await gameState.save(); } - static async shootingLogic(gameState: GameState, gameFlow: GameFlow, userInput?: string): Promise { + static async shootingLogic(gameState: GameState, userInput?: string): Promise { let responseMessage = ''; if (!userInput) { responseMessage = "Invalid input.\n\n"; @@ -48,11 +48,11 @@ export class HuntPhase { gameState.lastPrompt = responseMessage; gameState.subPhase = 2; await gameState.save(); - await gameFlow.executeCurrentPhase(); + await GameFlow.executeCurrentPhase(gameState); return; } - static async outcomeLogic(gameState: GameState, gameFlow: GameFlow): Promise { + static async outcomeLogic(gameState: GameState): Promise { let responseMessage = gameState.lastPrompt; if (gameState.shootResponseTime <= 1) { responseMessage += `RIGHT BETWEEN THE EYES---YOU GOT A BIG ONE!!!!\n\n`; @@ -71,7 +71,7 @@ export class HuntPhase { gameState.phase = PHASE_ENUM.ACTION_CHOICE; gameState.subPhase = 0; await gameState.save(); - await gameFlow.executeCurrentPhase(); + await GameFlow.executeCurrentPhase(gameState); return; } } diff --git a/src/phases/riders.ts b/src/phases/riders.ts index 87cd1bb..059f095 100644 --- a/src/phases/riders.ts +++ b/src/phases/riders.ts @@ -4,15 +4,15 @@ import { HandleShooting } from './shooting'; import { MessageService } from '../utils/MessageService'; export class RidersPhase { - static async handleRidersAttack(gameState: GameState, gameFlow: GameFlow, userInput?: string): Promise { + static async handleRidersAttack(gameState: GameState, userInput?: string): Promise { let responseMessage = ''; gameState.lastPrompt = responseMessage; switch (gameState.subPhase) { case 0: // Initial Logic - await RidersPhase.initialLogic(gameState, gameFlow); + await RidersPhase.initialLogic(gameState); break; case 1: // Choice Logic - await RidersPhase.choiceLogic(gameState, gameFlow, userInput); + await RidersPhase.choiceLogic(gameState, userInput); break; case 2: //Fight Logic responseMessage = gameState.lastPrompt @@ -43,7 +43,7 @@ export class RidersPhase { gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0 await gameState.save(); - await gameFlow.executeCurrentPhase(); + await GameFlow.executeCurrentPhase(gameState); return; case 4: // wagon fight logic responseMessage = gameState.lastPrompt @@ -67,12 +67,12 @@ export class RidersPhase { gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0 await gameState.save(); - await gameFlow.executeCurrentPhase(); + await GameFlow.executeCurrentPhase(gameState); return; } } - static async initialLogic(gameState: GameState, gameFlow: GameFlow): Promise { + static async initialLogic(gameState: GameState): Promise { let responseMessage = ''; gameState.lastPrompt = responseMessage; // Check for random encounter @@ -90,7 +90,7 @@ export class RidersPhase { gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0 gameState.save(); - return gameFlow.executeCurrentPhase(); + return GameFlow.executeCurrentPhase(gameState); } // If encounter occurs gameState.hostileRiders = false; @@ -107,7 +107,7 @@ export class RidersPhase { await MessageService.statusUpdate(gameState, responseMessage); } - static async choiceLogic(gameState: GameState, gameFlow: GameFlow, userInput?: string): Promise { + static async choiceLogic(gameState: GameState, userInput?: string): Promise { let responseMessage = ''; if (!userInput || isNaN(Number(userInput)) || +userInput < 1 && +userInput > 4) { @@ -121,12 +121,12 @@ export class RidersPhase { // Random chance to flip hostility if (Math.random() > 0.2) gameState.hostileRiders = !gameState.hostileRiders; - if (gameState.hostileRiders) RidersPhase.hostileRidersLogic(gameState, gameFlow) - else RidersPhase.friendlyRidersLogic(gameState, gameFlow); + if (gameState.hostileRiders) RidersPhase.hostileRidersLogic(gameState) + else RidersPhase.friendlyRidersLogic(gameState); } - static async hostileRidersLogic(gameState: GameState, gameFlow: GameFlow): Promise { + static async hostileRidersLogic(gameState: GameState): Promise { gameState.lastPrompt = ""; switch (gameState.tacticsChoiceWhenAttacked) { case 1: // RUN away @@ -139,12 +139,12 @@ export class RidersPhase { gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0; gameState.save(); - return gameFlow.executeCurrentPhase(); + return GameFlow.executeCurrentPhase(gameState); case 2: // ATTACK gameState.lastPrompt = "You decide to attack the hostile riders.\n\n"; gameState.subPhase = 2; gameState.save() - return gameFlow.executeCurrentPhase() + return GameFlow.executeCurrentPhase(gameState) case 3: // CONTINUE //Penalize lost initiative if riders are hostile gameState.lastPrompt = "You continue on cautiously, keeping your guard up. THE RIDERS ATTACK!\n\n"; @@ -152,12 +152,12 @@ export class RidersPhase { gameState.amountSpentOnAmmunition -= 100; gameState.subPhase = 2; gameState.save() - return gameFlow.executeCurrentPhase() + return GameFlow.executeCurrentPhase(gameState) case 4: // CIRCLE WAGONS gameState.subPhase = 4; gameState.lastPrompt = "You formed a defensive circle with your wagons.THE RIDERS ATTACK!\n\n" gameState.save() - return gameFlow.executeCurrentPhase() + return GameFlow.executeCurrentPhase(gameState) default: // Handle unexpected input (should be unreachable due to prior validation) console.log("Unexpected tactics choice."); @@ -165,7 +165,7 @@ export class RidersPhase { } } - static async friendlyRidersLogic(gameState: GameState, gameFlow: GameFlow): Promise { + static async friendlyRidersLogic(gameState: GameState): Promise { gameState.lastPrompt = ""; switch (gameState.tacticsChoiceWhenAttacked) { case 1: // RUN Away @@ -178,25 +178,25 @@ export class RidersPhase { gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0; gameState.save(); - return gameFlow.executeCurrentPhase(); + return GameFlow.executeCurrentPhase(gameState); case 2: // ATTACK gameState.lastPrompt = "You decide to attack the friendly riders. They flee in confusion\n\n"; gameState.subPhase = 2; gameState.save() - return gameFlow.executeCurrentPhase() + return GameFlow.executeCurrentPhase(gameState) case 3: // CONTINUE gameState.lastPrompt = "The riders share news from up ahead and wish you safe travels. Your party continues on.\n\n"; gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0; gameState.save(); - return gameFlow.executeCurrentPhase(); + return GameFlow.executeCurrentPhase(gameState); case 4: // CIRCLE WAGONS gameState.totalMileageWholeTrip -= 20; gameState.lastPrompt = "You formed a defensive circle with your wagons. The riders continue on their way without incident.\n\n"; gameState.phase = PHASE_ENUM.EVENT; gameState.subPhase = 0; gameState.save(); - return gameFlow.executeCurrentPhase() + return GameFlow.executeCurrentPhase(gameState) default: // Handle unexpected input (should be unreachable due to prior validation) diff --git a/src/phases/setup.ts b/src/phases/setup.ts index a191e23..fe1d64c 100644 --- a/src/phases/setup.ts +++ b/src/phases/setup.ts @@ -3,7 +3,7 @@ import GameFlow from '../game/gameFlow'; import { MessageService, MessageFileName } from '../utils/MessageService' export class HandleSetup { - static async handleSetupPhase(gameState: GameState, gameFlow: GameFlow, userInput?: string): Promise { + static async handleSetupPhase(gameState: GameState, userInput?: string): Promise { userInput = userInput?.toLowerCase() let responseMessage = ""; // Logic to handle initial setup @@ -23,7 +23,7 @@ export class HandleSetup { if (purchaseResult.success) { // If the purchase was successful, advance to the next subphase and recursively call handleSetupPhase without userInput to get the next set of instructions gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); + return HandleSetup.handleSetupPhase(gameState); } else { // If there was an error, include the error message in responseMessage responseMessage = `${purchaseResult.errorMessage}`; @@ -46,7 +46,7 @@ export class HandleSetup { const purchaseResult = HandleSetup.handleGenericPurchase(gameState, PurchaseOption.OXEN, userInput, 200, 300); if (purchaseResult.success) { gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); // Call setup phase again for next subphase + return HandleSetup.handleSetupPhase(gameState); // Call setup phase again for next subphase } else { responseMessage = purchaseResult.errorMessage || ''; responseMessage += `\n\n${MessageService.getRandomMessage( @@ -67,7 +67,7 @@ export class HandleSetup { const purchaseResult = HandleSetup.handleGenericPurchase(gameState, PurchaseOption.FOOD, userInput); if (purchaseResult.success) { gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); // Call setup phase again for next subphase + return HandleSetup.handleSetupPhase(gameState); // Call setup phase again for next subphase } else { responseMessage = purchaseResult.errorMessage || ''; responseMessage += `\n\n${MessageService.getRandomMessage( @@ -88,7 +88,7 @@ export class HandleSetup { const purchaseResult = HandleSetup.handleGenericPurchase(gameState, PurchaseOption.AMMO, userInput); if (purchaseResult.success) { gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); // Call setup phase again for next subphase + return HandleSetup.handleSetupPhase(gameState); // Call setup phase again for next subphase } else { responseMessage = purchaseResult.errorMessage || ''; responseMessage += `\n\n${MessageService.getRandomMessage( @@ -109,7 +109,7 @@ export class HandleSetup { const purchaseResult = HandleSetup.handleGenericPurchase(gameState, PurchaseOption.CLOTHING, userInput); if (purchaseResult.success) { gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); // Call setup phase again for next subphase + return HandleSetup.handleSetupPhase(gameState); // Call setup phase again for next subphase } else { responseMessage = purchaseResult.errorMessage || ''; responseMessage += `\n\n${MessageService.getRandomMessage( @@ -130,7 +130,7 @@ export class HandleSetup { const purchaseResult = HandleSetup.handleGenericPurchase(gameState, PurchaseOption.MISC, userInput); if (purchaseResult.success) { gameState.subPhase++; - return HandleSetup.handleSetupPhase(gameState, gameFlow); // Call setup phase again for next subphase + return HandleSetup.handleSetupPhase(gameState); // Call setup phase again for next subphase } else { responseMessage = purchaseResult.errorMessage || ''; responseMessage += `\n\n${MessageService.getRandomMessage( @@ -145,7 +145,7 @@ export class HandleSetup { gameState.subPhase = 0; gameState.phase === PHASE_ENUM.SETUP ? gameState.phase = PHASE_ENUM.START_TURN : gameState.phase = PHASE_ENUM.ACTION_CHOICE; await gameState.save() - gameFlow.executeCurrentPhase() + GameFlow.executeCurrentPhase(gameState) break; default: responseMessage = `@J something went wrong come and fix it.\n\n ${JSON.stringify(gameState, null, 4)}` diff --git a/src/phases/travel.ts b/src/phases/travel.ts new file mode 100644 index 0000000..20d1b97 --- /dev/null +++ b/src/phases/travel.ts @@ -0,0 +1,61 @@ +import GameState, { PHASE_ENUM } from '../game/gameState'; +import GameFlow from '../game/gameFlow'; +import { MessageService } from '../utils/MessageService'; + +export class travelPhase { + static async handleTravel(gameState: GameState, userInput?: string | number): Promise { + let responseMessage = ""; + + if (!userInput || userInput?.toString().toLowerCase() === "start") { + responseMessage = "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; + await MessageService.statusUpdate(gameState, responseMessage); + return; + } + + // Check if userInput is a number or can be converted to a valid number + if (isNaN(Number(userInput))) { + responseMessage = "Invalid input. Please enter a number.\n\n" + responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; + await MessageService.statusUpdate(gameState, responseMessage); + return; // Exit if input is not a valid number + } + + let eatingChoice: number = parseInt(userInput.toString(), 10); + + // Validate eating choice + if (eatingChoice < 1 || eatingChoice > 3) { + responseMessage = "Invalid choice.\n\n" + responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; + await MessageService.statusUpdate(gameState, responseMessage); + return; + } + + // Calculate potential food consumption without updating the game state yet + let potentialAmountSpentOnFood = gameState.amountSpentOnFood - (8 + 5 * eatingChoice); + + // Check if the potential amount spent on food is negative + if (potentialAmountSpentOnFood < 0) { + // If it would result in a negative value, inform the user they can't eat that well + responseMessage = "YOU CAN'T EAT THAT WELL\n\n"; + responseMessage += "DO YOU WANT TO EAT\n(1) POORLY\n(2) MODERATELY\n(3) WELL: "; + await MessageService.statusUpdate(gameState, responseMessage); + return; // Exit the method to prevent further execution + } else { + // If the amount is sufficient, update the game state with the new amount + gameState.amountSpentOnFood = potentialAmountSpentOnFood; + } + + // Calculate total mileage + gameState.totalMileageWholeTrip += 200 + (gameState.amountSpentOnAnimals - 220) / 5 + 10 * Math.random(); + gameState.blizzardFlag = gameState.insufficientClothingFlag = false; + + gameState.phase = PHASE_ENUM.RIDERS_ATTACK; + + // Save the game state after making changes + await gameState.save(); + + // Continue with the game flow + GameFlow.executeCurrentPhase(gameState); + } +} + diff --git a/src/workflows/WorkflowOrchestrator.ts b/src/workflows/WorkflowOrchestrator.ts index 7149533..397e9c2 100644 --- a/src/workflows/WorkflowOrchestrator.ts +++ b/src/workflows/WorkflowOrchestrator.ts @@ -18,8 +18,7 @@ class WorkflowOrchestrator { let gameState = await GameState.load(comment) if (parsedComment.command === 'restart') gameState = await gameState.reset(); - const gameFlow = new GameFlow(gameState) - await gameFlow.executeCurrentPhase(parsedComment.command) + await GameFlow.executeCurrentPhase(gameState, parsedComment.command) await gameState.save() } catch (error) {