Compare commits

...

3 Commits

3 changed files with 187 additions and 162 deletions

View File

@ -1,185 +1,125 @@
import GameState from "./gameState"; import GameFlow from "./gameFlow";
import GameState, { PHASE_ENUM } from "./gameState";
class GameEvents { export class EventPhase {
private randomEvents: OregonEvent[]; private static randomEvents: OregonEvent[] = [
private totalThreshold: number; {
constructor() { name: "Wagon Breakdown",
// Initialize the events and their thresholds. threshold: 10, // Probability weight
this.randomEvents = [ action: (gameState) => {
{ gameState.totalMileageWholeTrip -= 15;
name: "Wagon Breakdown", gameState.amountSpentOnMiscellaneousSupplies -= 8;
threshold: 10, // Probability weight return "Wagon breaks down. Lose time and supplies fixing it.";
action: (gameState) => {
gameState.totalMileageWholeTrip -= 15;
gameState.amountSpentOnMiscellaneousSupplies -= 8;
return "Wagon breaks down. Lose time and supplies fixing it.";
},
}, },
{ },
name: "Ox Injures Leg", {
threshold: 15, name: "Ox Injures Leg",
action: (gameState) => { threshold: 15,
gameState.totalMileageWholeTrip -= 25; action: (gameState) => {
gameState.amountSpentOnAnimals -= 20; gameState.totalMileageWholeTrip -= 25;
return "Ox injures leg. Slows you down rest of the trip."; gameState.amountSpentOnAnimals -= 20;
}, return "Ox injures leg. Slows you down rest of the trip.";
}, },
{ },
name: "Daughter Breaks Arm", {
threshold: 20, name: "Daughter Breaks Arm",
action: (gameState) => { threshold: 20,
gameState.totalMileageWholeTrip -= 5 + Math.floor(Math.random() * 4); action: (gameState) => {
gameState.amountSpentOnMiscellaneousSupplies -= 2 + Math.floor(Math.random() * 3); gameState.totalMileageWholeTrip -= 5 + Math.floor(Math.random() * 4);
return "Bad luck--your daughter broke her arm. You had to stop and use supplies to make a sling."; gameState.amountSpentOnMiscellaneousSupplies -= 2 + Math.floor(Math.random() * 3);
}, return "Bad luck--your daughter broke her arm. You had to stop and use supplies to make a sling.";
}, },
{ },
name: "Ox Wanders Off", {
threshold: 25, name: "Ox Wanders Off",
action: (gameState) => { threshold: 25,
gameState.totalMileageWholeTrip -= 17; action: (gameState) => {
return "Ox wanders off--spend time looking for it."; gameState.totalMileageWholeTrip -= 17;
}, return "Ox wanders off--spend time looking for it.";
}, },
{ },
name: "Son Gets Lost", {
threshold: 30, name: "Son Gets Lost",
action: (gameState) => { threshold: 30,
gameState.totalMileageWholeTrip -= 10; action: (gameState) => {
return "Your son gets lost---spend half the day looking for him."; gameState.totalMileageWholeTrip -= 10;
}, return "Your son gets lost---spend half the day looking for him.";
}, },
{ },
name: "Unsafe Water", {
threshold: 35, name: "Unsafe Water",
action: (gameState) => { threshold: 35,
gameState.totalMileageWholeTrip -= Math.floor(Math.random() * 10) + 2; action: (gameState) => {
return "Unsafe water--lose time looking for clean spring."; gameState.totalMileageWholeTrip -= Math.floor(Math.random() * 10) + 2;
}, return "Unsafe water--lose time looking for clean spring.";
}, },
{ },
name: "Heavy Rains", {
threshold: 40, name: "Heavy Rains",
action: (gameState) => { threshold: 40,
gameState.amountSpentOnFood -= 10; action: (gameState) => {
gameState.amountSpentOnMiscellaneousSupplies -= 15; gameState.amountSpentOnFood -= 10;
gameState.totalMileageWholeTrip -= Math.floor(Math.random() * 10) + 5; gameState.amountSpentOnMiscellaneousSupplies -= 15;
return "Heavy rains---time and supplies lost."; gameState.totalMileageWholeTrip -= Math.floor(Math.random() * 10) + 5;
}, return "Heavy rains---time and supplies lost.";
}, },
{ },
name: "Fire in Your Wagon", {
threshold: 45, name: "Fire in Your Wagon",
action: (gameState) => { threshold: 45,
gameState.amountSpentOnFood -= 40; action: (gameState) => {
gameState.amountSpentOnAmmunition -= 400; gameState.amountSpentOnFood -= 40;
gameState.amountSpentOnMiscellaneousSupplies -= Math.floor(Math.random() * 8) + 3; gameState.amountSpentOnAmmunition -= 400;
gameState.totalMileageWholeTrip -= 15; gameState.amountSpentOnMiscellaneousSupplies -= Math.floor(Math.random() * 8) + 3;
return "There was a fire in your wagonā€”food and supplies damaged!"; gameState.totalMileageWholeTrip -= 15;
}, return "There was a fire in your wagonā€”food and supplies damaged!";
}, },
{ },
name: "Lose Your Way in Heavy Fog", {
threshold: 50, name: "Lose Your Way in Heavy Fog",
action: (gameState) => { threshold: 50,
gameState.totalMileageWholeTrip -= 10 + Math.floor(Math.random() * 5); action: (gameState) => {
return "Lose your way in heavy fogā€”time is lost."; gameState.totalMileageWholeTrip -= 10 + Math.floor(Math.random() * 5);
}, return "Lose your way in heavy fogā€”time is lost.";
}, },
{ },
name: "Wagon Swamped Fording River", {
threshold: 55, name: "Wagon Swamped Fording River",
action: (gameState) => { threshold: 55,
gameState.amountSpentOnFood -= 30; action: (gameState) => {
gameState.amountSpentOnClothing -= 20; gameState.amountSpentOnFood -= 30;
gameState.totalMileageWholeTrip -= 20 + Math.floor(Math.random() * 20); gameState.amountSpentOnClothing -= 20;
return "Wagon gets swamped fording riverā€”lose food and clothes."; gameState.totalMileageWholeTrip -= 20 + Math.floor(Math.random() * 20);
}, return "Wagon gets swamped fording riverā€”lose food and clothes.";
} },
// Add more events here... }
]; // Add more events here...
];
this.totalThreshold = this.randomEvents.reduce((acc, event) => acc + event.threshold, 0); private static totalThreshold: number = EventPhase.randomEvents.reduce((acc, event) => acc + event.threshold, 0);
}
generateRandomEvent(gameState: GameState): string { public static async handleRandomEvent(gameState: GameState): Promise<void> {
const randomEventNumber = Math.random() * this.totalThreshold; const randomEventNumber = Math.random() * EventPhase.totalThreshold;
let cumulativeThreshold = 0; let cumulativeThreshold = 0;
let responseMessage = "";
for (let event of this.randomEvents) { for (let event of EventPhase.randomEvents) {
cumulativeThreshold += event.threshold; cumulativeThreshold += event.threshold;
if (randomEventNumber < cumulativeThreshold) { if (randomEventNumber < cumulativeThreshold) {
console.log(`Event triggered: ${event.name}`); console.log(`Event triggered: ${event.name}`);
return event.action(gameState); responseMessage = event.action(gameState);
} }
} }
return ""; gameState.lastPrompt = responseMessage;
gameState.phase = PHASE_ENUM.MOUNTAIN;
gameState.subPhase = 0
await gameState.save();
await GameFlow.executeCurrentPhase(gameState);
} }
mountains(gameState: GameState): string {
if (gameState.totalMileageWholeTrip <= 950) {
return '';
}
let message = "**šŸ”ļø Mountain Passage šŸ”ļø**\n";
let encounter = false;
let randomFactor = Math.random() * 10;
let mountainDifficulty = 9 - ((gameState.totalMileageWholeTrip / 100 - 15) ** 2 + 72) / ((gameState.totalMileageWholeTrip / 100 - 15) ** 2 + 12);
if (randomFactor > mountainDifficulty) {
encounter = true;
message += "Rugged mountains make your journey difficult.\n";
if (Math.random() > 0.1) {
gameState.totalMileageWholeTrip -= 60;
message += "šŸ” You got lostā€”losing valuable time trying to find the trail!\n";
} else if (Math.random() > 0.11) {
gameState.amountSpentOnMiscellaneousSupplies -= 5;
gameState.amountSpentOnAmmunition -= 200;
gameState.totalMileageWholeTrip -= 20 + Math.random() * 30;
message += "šŸ› ļø Wagon damaged!ā€”Lose time and supplies.\n";
} else {
gameState.totalMileageWholeTrip -= 45 + Math.random() / 0.02;
message += "šŸ¢ The going gets slow.\n";
}
}
if (!gameState.clearSouthPassFlag) {
gameState.clearSouthPassFlag = true;
if (Math.random() < 0.8) {
encounter = true;
message += "āœ… You made it safely through South Passā€”no snow.\n";
}
}
if (gameState.totalMileageWholeTrip >= 1700 && !gameState.clearBlueMountainsFlag) {
gameState.clearBlueMountainsFlag = true;
if (Math.random() < 0.7) {
encounter = true;
gameState.blizzardFlag = true;
gameState.amountSpentOnFood -= 25;
gameState.amountSpentOnMiscellaneousSupplies -= 10;
gameState.amountSpentOnAmmunition -= 300;
gameState.totalMileageWholeTrip -= 30 + Math.random() * 40;
message += "ā„ļø Blizzard in mountain passā€”time and supplies lost.\n";
if (gameState.amountSpentOnClothing < 18 + Math.random() * 2) {
message += "ā„ļøšŸ§£ Not enough clothing for the cold. This could be dire.\n";
// Add logic to affect player health or trigger a death sequence.
}
}
}
return encounter ? message : "The mountains are distant... for now.\n";
}
} }
export default GameEvents;
interface OregonEvent { interface OregonEvent {
name: string, name: string;
threshold: number, threshold: number;
action: (gameState: GameState) => string action: (gameState: GameState) => string;
} }

View File

@ -6,6 +6,8 @@ import { HuntPhase } from '../phases/hunt';
import { HandleSetup as SetupPhase } from '../phases/setup'; import { HandleSetup as SetupPhase } from '../phases/setup';
import { travelPhase as TravelPhase } from '../phases/travel'; import { travelPhase as TravelPhase } from '../phases/travel';
import { ActionPhase } from '../phases/action'; import { ActionPhase } from '../phases/action';
import { EventPhase } from './gameEvents';
import { MountainPhase } from '../phases/mountain';
class GameFlow { class GameFlow {
@ -41,9 +43,11 @@ class GameFlow {
break; break;
case PHASE_ENUM.EVENT: case PHASE_ENUM.EVENT:
// Handle random events that can occur // Handle random events that can occur
await EventPhase.handleRandomEvent(gameState);
break; break;
case PHASE_ENUM.MOUNTAIN: case PHASE_ENUM.MOUNTAIN:
// Handle mountain traversal challenges // Handle mountain traversal challenges
await MountainPhase.handleMountain(gameState);
break; break;
case PHASE_ENUM.DEATH: case PHASE_ENUM.DEATH:
// Check if conditions leading to the player's death have been met // Check if conditions leading to the player's death have been met

View File

@ -0,0 +1,81 @@
import GameFlow from '../game/gameFlow';
import GameState, { PHASE_ENUM } from '../game/gameState';
export class MountainPhase {
static async handleMountain(gameState: GameState): Promise<void> {
// If the total mileage is less than 950, return an empty string (no mountain encounter)
if (gameState.totalMileageWholeTrip <= 950) {
return;
}
let responseMessage = "**šŸ”ļø Mountain Passage šŸ”ļø**\n";
let encounter = false;
let randomFactor = Math.random() * 10;
// Calculate the mountain difficulty based on the total mileage traveled
// The difficulty peaks around 1500 miles and decreases as you get closer or further away
// Example: If totalMileageWholeTrip is 1500, mountainDifficulty will be 9
const milesFromPeak = gameState.totalMileageWholeTrip / 100 - 15;
const numerator = milesFromPeak ** 2 + 72;
const denominator = milesFromPeak ** 2 + 12;
let mountainDifficulty = 9 - (numerator / denominator);
// Check if a mountain encounter occurs based on the random factor and difficulty
if (randomFactor > mountainDifficulty) {
encounter = true;
responseMessage += "Rugged mountains make your journey difficult.\n";
// Randomly determine the type of mountain encounter
if (Math.random() > 0.1) {
gameState.totalMileageWholeTrip -= 60;
responseMessage += "šŸ” You got lostā€”losing valuable time trying to find the trail!\n";
} else if (Math.random() > 0.11) {
gameState.amountSpentOnMiscellaneousSupplies -= 5;
gameState.amountSpentOnAmmunition -= 200;
gameState.totalMileageWholeTrip -= 20 + Math.random() * 30;
responseMessage += "šŸ› ļø Wagon damaged!ā€”Lose time and supplies.\n";
} else {
gameState.totalMileageWholeTrip -= 45 + Math.random() / 0.02;
responseMessage += "šŸ¢ The going gets slow.\n";
}
}
// Check if the South Pass has been cleared
if (!gameState.clearSouthPassFlag) {
gameState.clearSouthPassFlag = true;
if (Math.random() < 0.8) {
encounter = true;
responseMessage += "āœ… You made it safely through South Passā€”no snow.\n";
}
}
// Check if the Blue Mountains have been cleared
if (gameState.totalMileageWholeTrip >= 1700 && !gameState.clearBlueMountainsFlag) {
gameState.clearBlueMountainsFlag = true;
if (Math.random() < 0.7) {
encounter = true;
gameState.blizzardFlag = true;
gameState.amountSpentOnFood -= 25;
gameState.amountSpentOnMiscellaneousSupplies -= 10;
gameState.amountSpentOnAmmunition -= 300;
gameState.totalMileageWholeTrip -= 30 + Math.random() * 40;
responseMessage += "ā„ļø Blizzard in mountain passā€”time and supplies lost.\n";
// Check if the player has enough clothing for the cold
if (gameState.amountSpentOnClothing < 18 + Math.random() * 2) {
responseMessage += "ā„ļøšŸ§£ Not enough clothing for the cold. This could be dire.\n";
// Add logic to affect player health or trigger a death sequence.
}
}
}
// Return the encounter message or a default message if no encounter occurred
gameState.lastPrompt = encounter ? responseMessage : "The mountains are distant... for now.\n";
gameState.phase = PHASE_ENUM.START_TURN;
gameState.subPhase = 0
await gameState.save();
await GameFlow.executeCurrentPhase(gameState);
}
}