FEATURE: Gem Drop System - Diamond, Emerald, Ruby, Sapphire rare drops with rarity chances + sell values
This commit is contained in:
@@ -109,6 +109,7 @@
|
|||||||
<script src="src/systems/MountSystem.js"></script>
|
<script src="src/systems/MountSystem.js"></script>
|
||||||
<script src="src/systems/SteamIntegrationSystem.js"></script>
|
<script src="src/systems/SteamIntegrationSystem.js"></script>
|
||||||
<script src="src/systems/StarterChestSystem.js"></script>
|
<script src="src/systems/StarterChestSystem.js"></script>
|
||||||
|
<script src="src/systems/GemDropSystem.js"></script>
|
||||||
|
|
||||||
<!-- Multiplayer -->
|
<!-- Multiplayer -->
|
||||||
<!-- <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script> -->
|
<!-- <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script> -->
|
||||||
|
|||||||
187
src/systems/GemDropSystem.js
Normal file
187
src/systems/GemDropSystem.js
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/**
|
||||||
|
* GEM DROP SYSTEM
|
||||||
|
* Handles rare gem drops from enemies, mining, etc.
|
||||||
|
* Gems: Diamond, Emerald, Ruby (high value items for selling)
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GemDropSystem {
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
// Gem definitions with rarity and value
|
||||||
|
this.gems = {
|
||||||
|
'diamond': {
|
||||||
|
name: 'Diamond',
|
||||||
|
rarity: 'legendary', // 0.5% drop
|
||||||
|
value: 500, // Sell price in gold
|
||||||
|
icon: '💎'
|
||||||
|
},
|
||||||
|
'emerald': {
|
||||||
|
name: 'Emerald',
|
||||||
|
rarity: 'epic', // 2% drop
|
||||||
|
value: 200,
|
||||||
|
icon: '💚'
|
||||||
|
},
|
||||||
|
'ruby': {
|
||||||
|
name: 'Ruby',
|
||||||
|
rarity: 'rare', // 5% drop
|
||||||
|
value: 100,
|
||||||
|
icon: '❤️'
|
||||||
|
},
|
||||||
|
'sapphire': {
|
||||||
|
name: 'Sapphire',
|
||||||
|
rarity: 'uncommon', // 10% drop
|
||||||
|
value: 50,
|
||||||
|
icon: '💙'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Drop chance by rarity
|
||||||
|
this.rarityChances = {
|
||||||
|
'legendary': 0.005, // 0.5%
|
||||||
|
'epic': 0.02, // 2%
|
||||||
|
'rare': 0.05, // 5%
|
||||||
|
'uncommon': 0.10 // 10%
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roll for gem drop from enemy/resource
|
||||||
|
* @param {string} source - 'zombie', 'elite', 'stone_ore', 'iron_ore'
|
||||||
|
* @param {number} x - Grid X
|
||||||
|
* @param {number} y - Grid Y
|
||||||
|
* @param {number} luckBonus - Player luck modifier (0-1)
|
||||||
|
*/
|
||||||
|
rollGemDrop(source, x, y, luckBonus = 0) {
|
||||||
|
const dropTable = this.getDropTableForSource(source);
|
||||||
|
if (!dropTable || dropTable.length === 0) return;
|
||||||
|
|
||||||
|
// Roll for each possible gem
|
||||||
|
for (const gemEntry of dropTable) {
|
||||||
|
const gemType = gemEntry.gem;
|
||||||
|
const gem = this.gems[gemType];
|
||||||
|
if (!gem) continue;
|
||||||
|
|
||||||
|
const baseChance = this.rarityChances[gem.rarity];
|
||||||
|
const finalChance = baseChance * (1 + luckBonus);
|
||||||
|
|
||||||
|
if (Math.random() < finalChance) {
|
||||||
|
// GEM DROPPED!
|
||||||
|
console.log(`💎 RARE DROP: ${gem.name} from ${source}!`);
|
||||||
|
this.spawnGem(gemType, x, y);
|
||||||
|
|
||||||
|
// Play special sound/effect
|
||||||
|
if (this.scene.particleEffects) {
|
||||||
|
this.scene.particleEffects.gemSparkle(x, y, gem.icon);
|
||||||
|
}
|
||||||
|
if (this.scene.soundManager) {
|
||||||
|
this.scene.soundManager.playRareDrop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only drop 1 gem per source
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get drop table based on source
|
||||||
|
*/
|
||||||
|
getDropTableForSource(source) {
|
||||||
|
const tables = {
|
||||||
|
'zombie': [
|
||||||
|
{ gem: 'sapphire', weight: 1 }
|
||||||
|
],
|
||||||
|
'elite_zombie': [
|
||||||
|
{ gem: 'ruby', weight: 2 },
|
||||||
|
{ gem: 'emerald', weight: 1 }
|
||||||
|
],
|
||||||
|
'troll': [
|
||||||
|
{ gem: 'emerald', weight: 2 },
|
||||||
|
{ gem: 'diamond', weight: 0.5 }
|
||||||
|
],
|
||||||
|
'stone_ore': [
|
||||||
|
{ gem: 'sapphire', weight: 1 }
|
||||||
|
],
|
||||||
|
'iron_ore': [
|
||||||
|
{ gem: 'ruby', weight: 1 }
|
||||||
|
],
|
||||||
|
'gold_ore': [
|
||||||
|
{ gem: 'emerald', weight: 1.5 },
|
||||||
|
{ gem: 'diamond', weight: 0.3 }
|
||||||
|
],
|
||||||
|
'boss': [
|
||||||
|
{ gem: 'diamond', weight: 5 } // Guaranteed almost!
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
return tables[source] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawn gem as loot item
|
||||||
|
*/
|
||||||
|
spawnGem(gemType, gridX, gridY) {
|
||||||
|
if (this.scene.lootSystem) {
|
||||||
|
this.scene.lootSystem.spawnLoot(gridX, gridY, gemType, 1);
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ LootSystem not found - gem cannot spawn!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show floating text
|
||||||
|
const gem = this.gems[gemType];
|
||||||
|
if (this.scene.events) {
|
||||||
|
const screenPos = this.scene.terrainSystem.iso.toScreen(gridX, gridY);
|
||||||
|
this.scene.events.emit('show-floating-text', {
|
||||||
|
x: screenPos.x,
|
||||||
|
y: screenPos.y - 50,
|
||||||
|
text: `${gem.icon} ${gem.name}!`,
|
||||||
|
color: '#ff00ff', // Purple for rare
|
||||||
|
size: '20px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get gem sell value
|
||||||
|
*/
|
||||||
|
getGemValue(gemType) {
|
||||||
|
const gem = this.gems[gemType];
|
||||||
|
return gem ? gem.value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sell gem to merchant
|
||||||
|
*/
|
||||||
|
sellGem(gemType, amount, playerInventory) {
|
||||||
|
const gem = this.gems[gemType];
|
||||||
|
if (!gem) {
|
||||||
|
console.warn('⚠️ Unknown gem type:', gemType);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if player has gem
|
||||||
|
const hasAmount = playerInventory.getItemCount(gemType);
|
||||||
|
if (hasAmount < amount) {
|
||||||
|
console.warn(`⚠️ Not enough ${gem.name} to sell!`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total value
|
||||||
|
const totalValue = gem.value * amount;
|
||||||
|
|
||||||
|
// Remove from inventory
|
||||||
|
playerInventory.removeItem(gemType, amount);
|
||||||
|
|
||||||
|
// Add gold
|
||||||
|
playerInventory.addItem('gold_coin', totalValue);
|
||||||
|
|
||||||
|
console.log(`💰 Sold ${amount}x ${gem.name} for ${totalValue} gold`);
|
||||||
|
return totalValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export
|
||||||
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
module.exports = GemDropSystem;
|
||||||
|
}
|
||||||
@@ -24,7 +24,9 @@ class LootSystem {
|
|||||||
const symbols = {
|
const symbols = {
|
||||||
'wood': '🪵', 'stone': '🪨', 'seeds': '🌱', 'wheat': '🌾',
|
'wood': '🪵', 'stone': '🪨', 'seeds': '🌱', 'wheat': '🌾',
|
||||||
'axe': '🪓', 'pickaxe': '⛏️', 'sword': '⚔️', 'hoe': '🚜',
|
'axe': '🪓', 'pickaxe': '⛏️', 'sword': '⚔️', 'hoe': '🚜',
|
||||||
'item_bone': '🦴', 'flower': '🌸'
|
'item_bone': '🦴', 'flower': '🌸',
|
||||||
|
'diamond': '💎', 'emerald': '💚', 'ruby': '❤️', // GEMS!
|
||||||
|
'gold_coin': '🪙', 'iron': '⚙️'
|
||||||
};
|
};
|
||||||
if (symbols[type]) symbol = symbols[type];
|
if (symbols[type]) symbol = symbols[type];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user