472 lines
12 KiB
JavaScript
472 lines
12 KiB
JavaScript
/**
|
|
* FISHING SYSTEM
|
|
* Complete fishing system with minigame, fish types, bait, and aquarium
|
|
*/
|
|
class FishingSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.enabled = true;
|
|
|
|
// Fishing state
|
|
this.isFishing = false;
|
|
this.currentCast = null;
|
|
this.fishingRod = null;
|
|
|
|
// Fish types
|
|
this.fishTypes = new Map();
|
|
|
|
// Caught fish
|
|
this.caughtFish = [];
|
|
this.fishCollection = new Set();
|
|
|
|
// Bait
|
|
this.currentBait = null;
|
|
|
|
// Aquarium
|
|
this.aquarium = [];
|
|
this.aquariumCapacity = 10;
|
|
|
|
// Minigame
|
|
this.minigame = null;
|
|
|
|
// Settings
|
|
this.settings = {
|
|
castDistance: 5, // tiles
|
|
biteChance: 0.3, // 30% per second
|
|
minigameTime: 3000, // 3 seconds
|
|
greenZoneSize: 0.2 // 20% of bar
|
|
};
|
|
|
|
this.loadProgress();
|
|
this.init();
|
|
|
|
console.log('✅ Fishing System initialized');
|
|
}
|
|
|
|
init() {
|
|
this.defineFishTypes();
|
|
this.defineRods();
|
|
console.log('🎣 Fishing system ready');
|
|
}
|
|
|
|
// ========== FISH TYPES ==========
|
|
|
|
defineFishTypes() {
|
|
// Common fish (70%)
|
|
this.defineFish('bass', {
|
|
name: 'Bass',
|
|
rarity: 'common',
|
|
weight: { min: 1, max: 3 },
|
|
value: 10,
|
|
chance: 0.35
|
|
});
|
|
|
|
this.defineFish('trout', {
|
|
name: 'Trout',
|
|
rarity: 'common',
|
|
weight: { min: 0.5, max: 2 },
|
|
value: 8,
|
|
chance: 0.35
|
|
});
|
|
|
|
// Rare fish (25%)
|
|
this.defineFish('salmon', {
|
|
name: 'Salmon',
|
|
rarity: 'rare',
|
|
weight: { min: 3, max: 8 },
|
|
value: 50,
|
|
chance: 0.15
|
|
});
|
|
|
|
this.defineFish('tuna', {
|
|
name: 'Tuna',
|
|
rarity: 'rare',
|
|
weight: { min: 10, max: 20 },
|
|
value: 75,
|
|
chance: 0.10
|
|
});
|
|
|
|
// Legendary fish (5%)
|
|
this.defineFish('golden_fish', {
|
|
name: 'Golden Fish',
|
|
rarity: 'legendary',
|
|
weight: { min: 5, max: 10 },
|
|
value: 500,
|
|
chance: 0.03
|
|
});
|
|
|
|
this.defineFish('sea_dragon', {
|
|
name: 'Sea Dragon',
|
|
rarity: 'legendary',
|
|
weight: { min: 50, max: 100 },
|
|
value: 1000,
|
|
chance: 0.02
|
|
});
|
|
}
|
|
|
|
defineFish(id, data) {
|
|
this.fishTypes.set(id, {
|
|
id,
|
|
...data
|
|
});
|
|
}
|
|
|
|
// ========== FISHING RODS ==========
|
|
|
|
defineRods() {
|
|
this.fishingRods = {
|
|
basic: {
|
|
name: 'Basic Rod',
|
|
cost: { wood: 5, string: 2 },
|
|
catchBonus: 0,
|
|
durability: 50
|
|
},
|
|
iron: {
|
|
name: 'Iron Rod',
|
|
cost: { iron: 3, wood: 2, string: 2 },
|
|
catchBonus: 0.1,
|
|
durability: 100
|
|
},
|
|
enchanted: {
|
|
name: 'Enchanted Rod',
|
|
cost: { magic_crystal: 1, iron: 5, string: 3 },
|
|
catchBonus: 0.3,
|
|
durability: 200
|
|
}
|
|
};
|
|
}
|
|
|
|
// ========== FISHING ==========
|
|
|
|
canFish() {
|
|
// Check if player has fishing rod
|
|
if (!this.fishingRod) {
|
|
console.log('❌ No fishing rod equipped');
|
|
return false;
|
|
}
|
|
|
|
// Check if near water
|
|
if (!this.isNearWater()) {
|
|
console.log('❌ Not near water');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
isNearWater() {
|
|
// Check if player is near water tile
|
|
if (!this.scene.player) return false;
|
|
|
|
const playerPos = this.scene.player.getPosition();
|
|
const tileX = Math.floor(playerPos.x);
|
|
const tileY = Math.floor(playerPos.y);
|
|
|
|
// Check surrounding tiles
|
|
for (let dx = -2; dx <= 2; dx++) {
|
|
for (let dy = -2; dy <= 2; dy++) {
|
|
const tile = this.scene.terrainSystem.getTile(tileX + dx, tileY + dy);
|
|
if (tile && tile.type === 'water') {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
startFishing() {
|
|
if (!this.canFish()) return false;
|
|
|
|
this.isFishing = true;
|
|
|
|
// Cast line
|
|
this.currentCast = {
|
|
startTime: Date.now(),
|
|
biteTime: this.calculateBiteTime(),
|
|
hasBite: false
|
|
};
|
|
|
|
console.log('🎣 Cast fishing line...');
|
|
return true;
|
|
}
|
|
|
|
calculateBiteTime() {
|
|
// Random time between 2-5 seconds
|
|
const baseTime = 2000 + Math.random() * 3000;
|
|
|
|
// Bait reduces wait time
|
|
if (this.currentBait) {
|
|
return baseTime * 0.7;
|
|
}
|
|
|
|
return baseTime;
|
|
}
|
|
|
|
updateFishing(delta) {
|
|
if (!this.isFishing || !this.currentCast) return;
|
|
|
|
const now = Date.now();
|
|
const elapsed = now - this.currentCast.startTime;
|
|
|
|
// Check for bite
|
|
if (!this.currentCast.hasBite && elapsed >= this.currentCast.biteTime) {
|
|
this.triggerBite();
|
|
}
|
|
}
|
|
|
|
triggerBite() {
|
|
this.currentCast.hasBite = true;
|
|
|
|
// Visual indicator
|
|
console.log('🐟 BITE! Press SPACE to reel!');
|
|
|
|
// Show minigame
|
|
this.startMinigame();
|
|
}
|
|
|
|
// ========== MINIGAME ==========
|
|
|
|
startMinigame() {
|
|
this.minigame = {
|
|
startTime: Date.now(),
|
|
duration: this.settings.minigameTime,
|
|
barPosition: 0.5, // 0-1
|
|
targetPosition: Math.random(), // 0-1
|
|
greenZoneStart: 0,
|
|
greenZoneEnd: 0,
|
|
success: false
|
|
};
|
|
|
|
// Calculate green zone
|
|
this.minigame.greenZoneStart = this.minigame.targetPosition - this.settings.greenZoneSize / 2;
|
|
this.minigame.greenZoneEnd = this.minigame.targetPosition + this.settings.greenZoneSize / 2;
|
|
|
|
console.log('🎮 Minigame started! Keep bar in green zone!');
|
|
}
|
|
|
|
updateMinigame(delta) {
|
|
if (!this.minigame) return;
|
|
|
|
const now = Date.now();
|
|
const elapsed = now - this.minigame.startTime;
|
|
|
|
// Check if time's up
|
|
if (elapsed >= this.minigame.duration) {
|
|
this.endMinigame();
|
|
return;
|
|
}
|
|
|
|
// Move target (makes it harder)
|
|
this.minigame.targetPosition += (Math.random() - 0.5) * 0.01;
|
|
this.minigame.targetPosition = Math.max(0, Math.min(1, this.minigame.targetPosition));
|
|
|
|
// Update green zone
|
|
this.minigame.greenZoneStart = this.minigame.targetPosition - this.settings.greenZoneSize / 2;
|
|
this.minigame.greenZoneEnd = this.minigame.targetPosition + this.settings.greenZoneSize / 2;
|
|
|
|
// Check if bar is in green zone
|
|
if (this.minigame.barPosition >= this.minigame.greenZoneStart &&
|
|
this.minigame.barPosition <= this.minigame.greenZoneEnd) {
|
|
this.minigame.success = true;
|
|
}
|
|
}
|
|
|
|
moveBar(direction) {
|
|
if (!this.minigame) return;
|
|
|
|
// Move bar left or right
|
|
this.minigame.barPosition += direction * 0.05;
|
|
this.minigame.barPosition = Math.max(0, Math.min(1, this.minigame.barPosition));
|
|
}
|
|
|
|
endMinigame() {
|
|
if (!this.minigame) return;
|
|
|
|
if (this.minigame.success) {
|
|
// Success! Catch fish
|
|
this.catchFish();
|
|
} else {
|
|
// Failed
|
|
console.log('❌ Fish got away!');
|
|
}
|
|
|
|
this.minigame = null;
|
|
this.isFishing = false;
|
|
this.currentCast = null;
|
|
}
|
|
|
|
// ========== CATCHING ==========
|
|
|
|
catchFish() {
|
|
// Determine which fish was caught
|
|
const fish = this.rollFish();
|
|
|
|
if (!fish) {
|
|
console.log('❌ Nothing caught');
|
|
return;
|
|
}
|
|
|
|
// Generate weight
|
|
const weight = fish.weight.min + Math.random() * (fish.weight.max - fish.weight.min);
|
|
|
|
// Create caught fish
|
|
const caughtFish = {
|
|
id: fish.id,
|
|
name: fish.name,
|
|
rarity: fish.rarity,
|
|
weight: Math.round(weight * 10) / 10,
|
|
value: fish.value,
|
|
caughtTime: Date.now()
|
|
};
|
|
|
|
this.caughtFish.push(caughtFish);
|
|
this.fishCollection.add(fish.id);
|
|
|
|
// Add to inventory
|
|
if (this.scene.inventorySystem) {
|
|
this.scene.inventorySystem.addItem(`fish_${fish.id}`, 1);
|
|
}
|
|
|
|
// Visual effect
|
|
if (this.scene.visualEnhancements) {
|
|
const player = this.scene.player;
|
|
if (player) {
|
|
const pos = player.getPosition();
|
|
const color = fish.rarity === 'legendary' ? 0xFFD700 :
|
|
fish.rarity === 'rare' ? 0x9370DB : 0x4169E1;
|
|
this.scene.visualEnhancements.createSparkleEffect(pos.x, pos.y);
|
|
this.scene.visualEnhancements.screenFlash(color, 300);
|
|
}
|
|
}
|
|
|
|
// Achievement
|
|
if (this.scene.uiGraphics) {
|
|
if (fish.rarity === 'legendary') {
|
|
this.scene.uiGraphics.unlockAchievement('legendary_fisher');
|
|
}
|
|
if (this.fishCollection.size >= 6) {
|
|
this.scene.uiGraphics.unlockAchievement('fish_collector');
|
|
}
|
|
}
|
|
|
|
console.log(`🎣 Caught ${fish.name}! (${caughtFish.weight}kg)`);
|
|
this.saveProgress();
|
|
}
|
|
|
|
rollFish() {
|
|
// Roll for fish type based on chances
|
|
const roll = Math.random();
|
|
let cumulative = 0;
|
|
|
|
// Apply rod bonus
|
|
const bonus = this.fishingRod ? this.fishingRods[this.fishingRod].catchBonus : 0;
|
|
|
|
for (const fish of this.fishTypes.values()) {
|
|
cumulative += fish.chance * (1 + bonus);
|
|
if (roll <= cumulative) {
|
|
return fish;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// ========== BAIT ==========
|
|
|
|
useBait(baitType) {
|
|
this.currentBait = baitType;
|
|
console.log(`🪱 Using ${baitType} bait`);
|
|
}
|
|
|
|
// ========== AQUARIUM ==========
|
|
|
|
addToAquarium(fishId) {
|
|
if (this.aquarium.length >= this.aquariumCapacity) {
|
|
console.log('❌ Aquarium is full');
|
|
return false;
|
|
}
|
|
|
|
const fish = this.caughtFish.find(f => f.id === fishId);
|
|
if (!fish) {
|
|
console.log('❌ Fish not found');
|
|
return false;
|
|
}
|
|
|
|
this.aquarium.push(fish);
|
|
console.log(`🐠 Added ${fish.name} to aquarium`);
|
|
this.saveProgress();
|
|
return true;
|
|
}
|
|
|
|
// ========== KEYBOARD CONTROLS ==========
|
|
|
|
setupKeyboard() {
|
|
// Press 'R' to start fishing
|
|
this.scene.input.keyboard.on('keydown-R', () => {
|
|
if (!this.isFishing) {
|
|
this.startFishing();
|
|
}
|
|
});
|
|
|
|
// Press 'SPACE' during minigame
|
|
this.scene.input.keyboard.on('keydown-SPACE', () => {
|
|
if (this.minigame) {
|
|
this.moveBar(0.1);
|
|
}
|
|
});
|
|
|
|
// Arrow keys for minigame
|
|
this.scene.input.keyboard.on('keydown-LEFT', () => {
|
|
if (this.minigame) {
|
|
this.moveBar(-0.1);
|
|
}
|
|
});
|
|
|
|
this.scene.input.keyboard.on('keydown-RIGHT', () => {
|
|
if (this.minigame) {
|
|
this.moveBar(0.1);
|
|
}
|
|
});
|
|
}
|
|
|
|
// ========== UPDATE ==========
|
|
|
|
update(delta) {
|
|
this.updateFishing(delta);
|
|
this.updateMinigame(delta);
|
|
}
|
|
|
|
// ========== PERSISTENCE ==========
|
|
|
|
saveProgress() {
|
|
const data = {
|
|
caughtFish: this.caughtFish,
|
|
fishCollection: Array.from(this.fishCollection),
|
|
aquarium: this.aquarium
|
|
};
|
|
|
|
localStorage.setItem('novafarma_fishing', JSON.stringify(data));
|
|
}
|
|
|
|
loadProgress() {
|
|
const saved = localStorage.getItem('novafarma_fishing');
|
|
if (saved) {
|
|
try {
|
|
const data = JSON.parse(saved);
|
|
this.caughtFish = data.caughtFish || [];
|
|
this.fishCollection = new Set(data.fishCollection || []);
|
|
this.aquarium = data.aquarium || [];
|
|
console.log('✅ Fishing progress loaded');
|
|
} catch (error) {
|
|
console.error('Failed to load fishing progress:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
this.saveProgress();
|
|
console.log('🎣 Fishing System destroyed');
|
|
}
|
|
}
|