Compare commits
4 Commits
5e2e9a7d15
...
e7b0f350c5
Author | SHA1 | Date |
---|---|---|
j | e7b0f350c5 | |
j | e04d63a9bb | |
j | eff594379a | |
j | 76a5710ae6 |
|
@ -1,4 +1,5 @@
|
||||||
import GameState, { PHASE_ENUM } from './gameState';
|
import GameState, { PHASE_ENUM } from './gameState';
|
||||||
|
import { MessageService, MessageFileName } from '../utils/MessageService'
|
||||||
|
|
||||||
class GameFlow {
|
class GameFlow {
|
||||||
gameState: GameState;
|
gameState: GameState;
|
||||||
|
@ -59,21 +60,10 @@ class GameFlow {
|
||||||
// Weapons Purchase Subphase
|
// Weapons Purchase Subphase
|
||||||
if (!userInput) {
|
if (!userInput) {
|
||||||
// Send instructions to the user for the current subphase
|
// Send instructions to the user for the current subphase
|
||||||
responseMessage = `
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
🔫 **Choose Your Weapon for the Journey** 🔫
|
MessageFileName.Oregon_WeaponPurchase,
|
||||||
|
{}
|
||||||
Please select from the following options by replying with **!!Oregon [choice]**:
|
)}`;
|
||||||
|
|
||||||
1. **Frontiersman's Sharpshooter Rifle** - $200 (Best accuracy and range)
|
|
||||||
2. **Pioneer's Long Rifle** - $150 (Improved accuracy and range)
|
|
||||||
3. **Settler's Carbine** - $100 (Good balance of cost and performance)
|
|
||||||
4. **Homesteader's Musket** - $75 (Reliable but not as accurate)
|
|
||||||
5. **Grandpa's Rusty Shotgun** - Free (Least accurate but no cost)
|
|
||||||
|
|
||||||
**Note:** Your choice of weapon can greatly affect your hunting success and defense against threats on the trail. Choose wisely!
|
|
||||||
|
|
||||||
Reply with the choice number, for example: **!!Oregon 3** to select the Settler's Carbine.
|
|
||||||
`;
|
|
||||||
// The lack of userInput argument triggers a request for input.
|
// The lack of userInput argument triggers a request for input.
|
||||||
} else {
|
} else {
|
||||||
// Process user input here and decide whether to advance subphase or send an error message
|
// Process user input here and decide whether to advance subphase or send an error message
|
||||||
|
@ -81,6 +71,7 @@ Reply with the choice number, for example: **!!Oregon 3** to select the Settler'
|
||||||
if (purchaseResult.success) {
|
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
|
// If the purchase was successful, advance to the next subphase and recursively call handleSetupPhase without userInput to get the next set of instructions
|
||||||
this.gameState.subPhase++;
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
return this.handleSetupPhase();
|
return this.handleSetupPhase();
|
||||||
} else {
|
} else {
|
||||||
// If there was an error, include the error message in responseMessage
|
// If there was an error, include the error message in responseMessage
|
||||||
|
@ -91,18 +82,93 @@ Reply with the choice number, for example: **!!Oregon 3** to select the Settler'
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//OXEN TEAM Purchase
|
//OXEN TEAM Purchase
|
||||||
|
if (!userInput) {
|
||||||
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
|
MessageFileName.Oregon_OxenPurchase,
|
||||||
|
{}
|
||||||
|
)}`;
|
||||||
|
} else {
|
||||||
|
const purchaseResult = this.handleGenericPurchase(PurchaseOption.OXEN, userInput, 200, 300);
|
||||||
|
if (purchaseResult.success) {
|
||||||
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
|
return this.handleSetupPhase(); // Call setup phase again for next subphase
|
||||||
|
} else {
|
||||||
|
responseMessage = purchaseResult.errorMessage || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
//FOOD Purchase
|
//FOOD Purchase
|
||||||
|
if (!userInput) {
|
||||||
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
|
MessageFileName.Oregon_FoodPurchase,
|
||||||
|
{}
|
||||||
|
)}`;
|
||||||
|
} else {
|
||||||
|
const purchaseResult = this.handleGenericPurchase(PurchaseOption.FOOD, userInput);
|
||||||
|
if (purchaseResult.success) {
|
||||||
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
|
return this.handleSetupPhase(); // Call setup phase again for next subphase
|
||||||
|
} else {
|
||||||
|
responseMessage = purchaseResult.errorMessage || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
//AMMUNITION Purchase
|
//AMMUNITION Purchase
|
||||||
|
if (!userInput) {
|
||||||
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
|
MessageFileName.Oregon_AmmoPurchase,
|
||||||
|
{}
|
||||||
|
)}`;
|
||||||
|
} else {
|
||||||
|
const purchaseResult = this.handleGenericPurchase(PurchaseOption.AMMO, userInput);
|
||||||
|
if (purchaseResult.success) {
|
||||||
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
|
return this.handleSetupPhase(); // Call setup phase again for next subphase
|
||||||
|
} else {
|
||||||
|
responseMessage = purchaseResult.errorMessage || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
//CLOTHING Purchase
|
//CLOTHING Purchase
|
||||||
|
if (!userInput) {
|
||||||
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
|
MessageFileName.Oregon_ClothingPurchase,
|
||||||
|
{}
|
||||||
|
)}`;
|
||||||
|
} else {
|
||||||
|
const purchaseResult = this.handleGenericPurchase(PurchaseOption.CLOTHING, userInput);
|
||||||
|
if (purchaseResult.success) {
|
||||||
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
|
return this.handleSetupPhase(); // Call setup phase again for next subphase
|
||||||
|
} else {
|
||||||
|
responseMessage = purchaseResult.errorMessage || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
//MISCELLANEOUS SUPPLIES Purchase
|
//MISCELLANEOUS SUPPLIES Purchase
|
||||||
|
if (!userInput) {
|
||||||
|
responseMessage = `${MessageService.getRandomMessage(
|
||||||
|
MessageFileName.Oregon_MiscSuppliesPurchase,
|
||||||
|
{}
|
||||||
|
)}`;
|
||||||
|
} else {
|
||||||
|
const purchaseResult = this.handleGenericPurchase(PurchaseOption.MISC, userInput);
|
||||||
|
if (purchaseResult.success) {
|
||||||
|
this.gameState.subPhase++;
|
||||||
|
//TODO next we will need to add a wrapper methood that will dump the game object and the message back to the player
|
||||||
|
return this.handleSetupPhase(); // Call setup phase again for next subphase
|
||||||
|
} else {
|
||||||
|
responseMessage = purchaseResult.errorMessage || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//Advance Phase
|
//Advance Phase
|
||||||
|
@ -142,6 +208,59 @@ Reply with the choice number, for example: **!!Oregon 3** to select the Settler'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleGenericPurchase(itemType: PurchaseOption, userInput: string, minAmount?: number, maxAmount?: number): { success: boolean; errorMessage?: string; responseMessage?: string } {
|
||||||
|
const amount = parseInt(userInput);
|
||||||
|
if (isNaN(amount) || amount < 0) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
errorMessage: "⚠️ Invalid input. Please enter a positive number."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((maxAmount && amount > maxAmount) || (minAmount && amount < minAmount)) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
errorMessage: `⚠️ Invalid input. Please enter a number between ${minAmount} and ${maxAmount}.`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalCost = amount
|
||||||
|
if (this.gameState.cashLeftAfterInitialPurchases < totalCost) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
errorMessage: `⚠️ You do not have enough money to purchase ${amount} units of ${itemType}. You have $${this.gameState.cashLeftAfterInitialPurchases} remaining.`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update gameState based on itemType
|
||||||
|
switch (itemType) {
|
||||||
|
case PurchaseOption.OXEN:
|
||||||
|
this.gameState.amountSpentOnAnimals += totalCost;
|
||||||
|
break;
|
||||||
|
case PurchaseOption.FOOD:
|
||||||
|
this.gameState.amountSpentOnFood += totalCost;
|
||||||
|
break;
|
||||||
|
case PurchaseOption.AMMO:
|
||||||
|
this.gameState.amountSpentOnAmmunition += totalCost * 50;
|
||||||
|
break;
|
||||||
|
case PurchaseOption.CLOTHING:
|
||||||
|
this.gameState.amountSpentOnClothing += totalCost;
|
||||||
|
break;
|
||||||
|
case PurchaseOption.MISC:
|
||||||
|
this.gameState.amountSpentOnMiscellaneousSupplies += totalCost;
|
||||||
|
break;
|
||||||
|
// Add cases for other item types
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gameState.cashLeftAfterInitialPurchases -= totalCost;
|
||||||
|
|
||||||
|
// Optionally, return a success message
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async handleRidersAttack(userInput?: string | number): Promise<void> {
|
private async handleRidersAttack(userInput?: string | number): Promise<void> {
|
||||||
// Logic for handling a riders attack, may involve checking userInput for response to attack
|
// Logic for handling a riders attack, may involve checking userInput for response to attack
|
||||||
|
@ -191,4 +310,12 @@ const weaponOptions: Record<string, WeaponOption> = {
|
||||||
"3": { name: "Settler's Carbine", cost: 100 },
|
"3": { name: "Settler's Carbine", cost: 100 },
|
||||||
"4": { name: "Homesteader's Musket", cost: 75 },
|
"4": { name: "Homesteader's Musket", cost: 75 },
|
||||||
"5": { name: "Grandpa's Rusty Shotgun", cost: 0 }
|
"5": { name: "Grandpa's Rusty Shotgun", cost: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PurchaseOption {
|
||||||
|
OXEN = 'oxen',
|
||||||
|
FOOD = 'food',
|
||||||
|
AMMO = 'ammo',
|
||||||
|
CLOTHING = 'clothing',
|
||||||
|
MISC = 'misc',
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
🔫 How much do you want to spend on ammunition? $1 buys a belt of 50 bullets. You will need bullets for attacks by animals and bandits, and for hunting food. Reply with !!Oregon [amount].
|
|
@ -0,0 +1 @@
|
||||||
|
🧥 How much do you want to spend on clothing? This is especially important for the cold weather you will encounter when crossing the mountains. Reply with !!Oregon [amount].
|
|
@ -0,0 +1 @@
|
||||||
|
🍞 How much do you want to spend on food? The more you have, the less chance there is of getting sick. Reply with !!Oregon [amount].
|
|
@ -0,0 +1 @@
|
||||||
|
🔧 How much do you want to spend on miscellaneous supplies? This includes medicine and other things you will need for sickness and emergency repairs. Reply with !!Oregon [amount].
|
|
@ -0,0 +1 @@
|
||||||
|
🐂 How much do you want to spend on your oxen team? You can spend $200-$300. Reply with !!Oregon [amount].
|
|
@ -0,0 +1,13 @@
|
||||||
|
🔫 **Choose Your Weapon for the Journey** 🔫
|
||||||
|
|
||||||
|
Please select from the following options by replying with **!!Oregon [choice]**:
|
||||||
|
|
||||||
|
1. **Frontiersman's Sharpshooter Rifle** - $200 (Best accuracy and range)
|
||||||
|
2. **Pioneer's Long Rifle** - $150 (Improved accuracy and range)
|
||||||
|
3. **Settler's Carbine** - $100 (Good balance of cost and performance)
|
||||||
|
4. **Homesteader's Musket** - $75 (Reliable but not as accurate)
|
||||||
|
5. **Grandpa's Rusty Shotgun** - Free (Least accurate but no cost)
|
||||||
|
|
||||||
|
**Note:** Your choice of weapon can greatly affect your hunting success and defense against threats on the trail. Choose wisely!
|
||||||
|
|
||||||
|
Reply with the choice number, for example: **!!Oregon 3** to select the Settler's Carbine.
|
|
@ -26,7 +26,13 @@ class SessionManager {
|
||||||
enableOfflineQueue: true
|
enableOfflineQueue: true
|
||||||
},
|
},
|
||||||
maxConcurrent: 1, // Maximum number of concurrent requests
|
maxConcurrent: 1, // Maximum number of concurrent requests
|
||||||
minTime: 1000 // Minimum time between dispatches of requests in milliseconds
|
minTime: 1000, // Minimum time between dispatches of requests in milliseconds
|
||||||
|
reservoir: 41, // Initial reservoir value for the first hour
|
||||||
|
reservoirRefreshAmount: 41, // Reservoir value to reset to every hour
|
||||||
|
reservoirRefreshInterval: 60 * 60 * 1000, // Interval to reset the reservoir (1 hour in milliseconds)
|
||||||
|
//For now will reply to every comment given enoug time even if severely rate limited
|
||||||
|
//highWater: 5, // Maximum number of queued jobs.
|
||||||
|
//strategy: Bottleneck.strategy.OVERFLOW_PRIORITY // Strategy to drop the oldest jobs in the queue when highWater is reached
|
||||||
});
|
});
|
||||||
|
|
||||||
this.axiosInstance = axios.create({
|
this.axiosInstance = axios.create({
|
||||||
|
@ -82,13 +88,13 @@ class SessionManager {
|
||||||
// Wrap the post method
|
// Wrap the post method
|
||||||
const originalPost = instance.post;
|
const originalPost = instance.post;
|
||||||
instance.post = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
instance.post = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
return this.limiter.schedule(() => originalPost.apply(instance, [url, data, config])) as Promise<R>;
|
return this.limiter.schedule({ priority: 1 }, () => originalPost.apply(instance, [url, data, config])) as Promise<R>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrap the put method
|
// Wrap the put method
|
||||||
const originalPut = instance.put;
|
const originalPut = instance.put;
|
||||||
instance.put = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
instance.put = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
return this.limiter.schedule(() => originalPut.apply(instance, [url, data, config])) as Promise<R>;
|
return this.limiter.schedule({ priority: 1 }, () => originalPut.apply(instance, [url, data, config])) as Promise<R>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrap the delete method
|
// Wrap the delete method
|
||||||
|
|
|
@ -3,10 +3,12 @@ import path from 'path';
|
||||||
|
|
||||||
// Define an enum for message file names
|
// Define an enum for message file names
|
||||||
export enum MessageFileName {
|
export enum MessageFileName {
|
||||||
RdramaPreviousMessage = 'rdrama_PreviousMessage.txt',
|
Oregon_WeaponPurchase = 'oregon_WeaponPurchase.txt',
|
||||||
RdramaShouldntNotify = 'rdrama_ShouldntNotify.txt',
|
Oregon_OxenPurchase = 'oregon_OxenPurchase.txt',
|
||||||
RedditMessages = 'reddit_messages.txt',
|
Oregon_FoodPurchase = 'oregon_FoodPurchase.txt',
|
||||||
RdramaMessages = 'rdrama_messages.txt',
|
Oregon_AmmoPurchase = 'oregon_AmmoPurchase.txt',
|
||||||
|
Oregon_ClothingPurchase = 'oregon_ClothingPurchase.txt',
|
||||||
|
Oregon_MiscSuppliesPurchase = 'oregon_MiscSuppliesPurchase.txt',
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageService {
|
export class MessageService {
|
||||||
|
|
Loading…
Reference in New Issue