Update Dungeonsystem
This commit is contained in:
parent
54b85f0f1f
commit
86bfae2228
@ -31,7 +31,6 @@ class GameDataManager {
|
||||
if (Array.isArray(data.rooms)) {
|
||||
data.rooms.forEach((r) => this.rooms.set(r.id, r));
|
||||
}
|
||||
console.log(this.hostiles);
|
||||
if (data.languages) {
|
||||
this.translations = data.languages;
|
||||
}
|
||||
|
||||
@ -233,3 +233,41 @@
|
||||
border-radius: 3px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.qty-label {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
right: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
text-shadow:
|
||||
1px 1px 0 #000,
|
||||
-1px -1px 0 #000,
|
||||
1px -1px 0 #000,
|
||||
-1px 1px 0 #000,
|
||||
0 0 5px rgba(0, 0, 0, 0.8);
|
||||
pointer-events: none;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.item-slot {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: rgba(5, 8, 12, 0.9);
|
||||
border: 1px solid #1a2638;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.item-img-grid {
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
object-fit: contain;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
"id": "original:tutorial/tutorial_dungeon",
|
||||
"displayName": "dungeons.original.tutorial.tutorial",
|
||||
"description": "dungeons.original.tutorial.tutorial.desc",
|
||||
"meta":{
|
||||
"meta": {
|
||||
"energyCost": 0,
|
||||
"repeatable": false,
|
||||
"missionArea":"space",
|
||||
"raid": false, "_comment_1":"Future raid type picking, when you can have friends in the dugeon to help you.",
|
||||
"missionAllowed": [], "_comment_2":"Future ship type picking, when ship classes are started"
|
||||
"missionArea": "space",
|
||||
"raid": false,
|
||||
"_comment_1": "Future raid type picking, when you can have friends in the dugeon to help you.",
|
||||
"missionAllowed": [],
|
||||
"_comment_2": "Future ship type picking, when ship classes are started"
|
||||
},
|
||||
"rooms": [
|
||||
{ "id": "original:tutorial/tutorial_enemy_room" },
|
||||
|
||||
@ -8,6 +8,19 @@
|
||||
"damage": 4,
|
||||
"critical.chance": 0.3,
|
||||
"attack.rate": 2
|
||||
}
|
||||
},
|
||||
"loot": [
|
||||
{
|
||||
"id": "original:ore_coal",
|
||||
"chance": 1.0,
|
||||
"count": 50
|
||||
},
|
||||
{
|
||||
"id": "original:ore_copper",
|
||||
"chance": 1.0,
|
||||
"count": 20
|
||||
}
|
||||
],
|
||||
"meta": {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
{
|
||||
"rooms": {
|
||||
"id": "original:tutorial/tutorial_boss_room",
|
||||
"displayName": "rooms.original.tutorial.tutorial_boss_room.name",
|
||||
"description": "rooms.original.tutorial.tutorial_boss_room.desc",
|
||||
"hostiles": ["original:tutorial/tutorial_boss_hostile"],
|
||||
"gainXp": 4,
|
||||
"credits": 200
|
||||
"credits": 200,
|
||||
"loot": [],
|
||||
"meta": {
|
||||
"isBossRoom": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
{
|
||||
"rooms": {
|
||||
"id": "original:tutorial/tutorial_enemy_room",
|
||||
"displayName": "rooms.original.tutorial.tutorial_enemy_room.name",
|
||||
"description": "rooms.original.tutorial.tutorial_enemy_room.desc",
|
||||
"hostiles": ["original:tutorial/tutorial_hostile"],
|
||||
"gainXp": 3,
|
||||
"credits": 30
|
||||
"credits": 30,
|
||||
"loot": [],
|
||||
"meta": {
|
||||
"isBossRoom": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,20 @@
|
||||
{
|
||||
"rooms": {
|
||||
"id": "original:tutorial/tutorial_loot_room",
|
||||
"loot": [{ "id": "original:bio_pulp", "count": 1 }]
|
||||
"displayName": "rooms.original.tutorial.tutorial_loot_room.name",
|
||||
"description": "rooms.original.tutorial.tutorial_loot_room.desc",
|
||||
"hostiles": [],
|
||||
"gainXp": 0,
|
||||
"credits": 0,
|
||||
"loot": [
|
||||
{
|
||||
"id": "original:bio_pulp",
|
||||
"chance": 1.0,
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"isBossRoom": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ class DatapackLoader {
|
||||
const data = json[typeKey];
|
||||
if (!data) return;
|
||||
|
||||
const fullId = `${packName}:${data.id}`;
|
||||
const fullId = `${data.id}`;
|
||||
|
||||
switch (typeKey) {
|
||||
case "armour":
|
||||
|
||||
@ -16,7 +16,6 @@ class DungeonManager {
|
||||
currentEnemyHp: undefined,
|
||||
rewards: { xp: 0, credits: 0, items: [] },
|
||||
};
|
||||
|
||||
this.activeSessions.set(playerId, session);
|
||||
return this.getCurrentRoomData(playerId);
|
||||
}
|
||||
@ -27,16 +26,17 @@ class DungeonManager {
|
||||
|
||||
const dungeon = DatapackLoader.getDungeon(session.dungeonId);
|
||||
const roomRef = dungeon.rooms[session.currentRoomIndex];
|
||||
const roomData = DatapackLoader.getRoom(roomRef.id);
|
||||
if (!roomData) return null;
|
||||
|
||||
const rawRoom = DatapackLoader.getRoom(roomRef.id);
|
||||
|
||||
if (!rawRoom) return null;
|
||||
|
||||
const roomData = rawRoom;
|
||||
const hostiles = (roomData.hostiles || [])
|
||||
.map((hId) => {
|
||||
const hostile = DatapackLoader.getEnemy(hId);
|
||||
return hostile ? { ...hostile } : null;
|
||||
return DatapackLoader.getEnemy(hId);
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
return {
|
||||
roomIndex: session.currentRoomIndex,
|
||||
totalRooms: dungeon.rooms.length,
|
||||
@ -51,15 +51,29 @@ class DungeonManager {
|
||||
|
||||
const dungeon = DatapackLoader.getDungeon(session.dungeonId);
|
||||
const roomRef = dungeon.rooms[session.currentRoomIndex];
|
||||
const currentRoom = DatapackLoader.getRoom(roomRef.id);
|
||||
const rawRoom = DatapackLoader.getRoom(roomRef.id);
|
||||
|
||||
if (currentRoom) {
|
||||
session.rewards.xp += currentRoom.gainXp || 0;
|
||||
session.rewards.credits += currentRoom.credits || 0;
|
||||
if (rawRoom && rawRoom.room) {
|
||||
const room = rawRoom.room;
|
||||
|
||||
if (currentRoom.loot && Array.isArray(currentRoom.loot)) {
|
||||
currentRoom.loot.forEach((item) => {
|
||||
session.rewards.items.push({ ...item });
|
||||
session.rewards.xp += room.gainXp || 0;
|
||||
session.rewards.credits += room.credits || 0;
|
||||
|
||||
if (room.loot && Array.isArray(room.loot)) {
|
||||
room.loot.forEach((lootEntry) => {
|
||||
const roll = Math.random();
|
||||
if (roll <= (lootEntry.chance || 1.0)) {
|
||||
session.rewards.items.push({
|
||||
id: lootEntry.id,
|
||||
count:
|
||||
typeof lootEntry.count === "object"
|
||||
? Math.floor(
|
||||
Math.random() *
|
||||
(lootEntry.count.max - lootEntry.count.min + 1),
|
||||
) + lootEntry.count.min
|
||||
: lootEntry.count || 1,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,25 +50,48 @@ module.exports = (io, socket) => {
|
||||
const session = dungeonManager.activeSessions.get(userId);
|
||||
if (!session || session.isFinished) return;
|
||||
|
||||
const enemyTemplate = DatapackLoader.getEnemy(enemyId);
|
||||
if (!enemyTemplate) {
|
||||
const rawEnemy = DatapackLoader.getEnemy(enemyId);
|
||||
if (!rawEnemy || !rawEnemy) {
|
||||
return socket.emit("error", { message: "Target data corrupted" });
|
||||
}
|
||||
|
||||
const enemy = rawEnemy;
|
||||
|
||||
if (session.currentEnemyHp === undefined) {
|
||||
session.currentEnemyHp = enemyTemplate.stats?.health || 100;
|
||||
session.currentEnemyHp = enemy.stats?.health || 100;
|
||||
}
|
||||
|
||||
const damage = Math.floor(Math.random() * 10) + 20;
|
||||
session.currentEnemyHp -= damage;
|
||||
|
||||
const isDefeated = session.currentEnemyHp <= 0;
|
||||
let lootDropped = [];
|
||||
|
||||
if (isDefeated && enemy.loot) {
|
||||
enemy.loot.forEach((entry) => {
|
||||
if (Math.random() <= (entry.chance || 1.0)) {
|
||||
const count =
|
||||
typeof entry.count === "object"
|
||||
? Math.floor(
|
||||
Math.random() * (entry.count.max - entry.count.min + 1),
|
||||
) + entry.count.min
|
||||
: entry.count || 1;
|
||||
|
||||
const drop = { id: entry.id, count };
|
||||
lootDropped.push(drop);
|
||||
session.rewards.items.push(drop);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
socket.emit("dungeon:combat_result", {
|
||||
damageDealt: damage,
|
||||
enemyHp: Math.max(0, session.currentEnemyHp),
|
||||
targetDefeated: isDefeated,
|
||||
message: `Strike successful. Dealt ${damage} damage.`,
|
||||
loot: lootDropped,
|
||||
message: isDefeated
|
||||
? `Enemy eliminated!`
|
||||
: `Strike successful. Dealt ${damage} damage.`,
|
||||
});
|
||||
|
||||
if (isDefeated) {
|
||||
@ -119,10 +142,27 @@ async function finalizeDungeon(socket, sessionRewards) {
|
||||
await player.increment("credits", { by: sessionRewards.credits });
|
||||
}
|
||||
|
||||
if (sessionRewards.xp > 0 && player.xp !== undefined) {
|
||||
await player.increment("xp", { by: sessionRewards.xp });
|
||||
}
|
||||
|
||||
if (sessionRewards.items.length > 0) {
|
||||
for (const item of sessionRewards.items) {
|
||||
const [invItem, created] = await Inventory.findOrCreate({
|
||||
where: { playerId: userId, itemId: item.id },
|
||||
defaults: { quantity: 0 },
|
||||
});
|
||||
|
||||
await invItem.increment("quantity", { by: item.count });
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit("dungeon:completed", {
|
||||
rewards: sessionRewards,
|
||||
message: "Mission successful. All objectives secured.",
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Finalize Error:", err);
|
||||
} finally {
|
||||
dungeonManager.leaveDungeon(userId);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user