mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-04 22:58:29 +08:00
Fixed bug in quest parsing code.
This commit is contained in:
parent
591640344a
commit
ab9a6afd54
@ -81,9 +81,8 @@
|
||||
"GuilShark": 24,
|
||||
"GrassAssassin": 7,
|
||||
"PoisonLily": 41,
|
||||
"PouillySlime": 2,
|
||||
"PofuillySlime": 12,
|
||||
"NanoDragon": 12,
|
||||
"PofuillySlime": 10,
|
||||
"PanArms": 13
|
||||
}
|
||||
},
|
||||
@ -92,14 +91,13 @@
|
||||
"name": "2-4:Waterway Shadow",
|
||||
"episode": 1,
|
||||
"enemyCounts": {
|
||||
"PoisonLily": 36,
|
||||
"PoisonLily": 40,
|
||||
"EvilShark": 165,
|
||||
"PalShark": 87,
|
||||
"GuilShark": 28,
|
||||
"GrassAssassin": 16,
|
||||
"NanoDragon": 17,
|
||||
"PofuillySlime": 4,
|
||||
"NarLily": 4,
|
||||
"PanArms": 4,
|
||||
"DeRolLe": 1
|
||||
}
|
||||
@ -243,15 +241,14 @@
|
||||
"name": "Addicting Food",
|
||||
"episode": 1,
|
||||
"enemyCounts": {
|
||||
"PoisonLily": 62,
|
||||
"PoisonLily": 64,
|
||||
"PalShark": 38,
|
||||
"EvilShark": 195,
|
||||
"GrassAssassin": 19,
|
||||
"GuilShark": 15,
|
||||
"NanoDragon": 19,
|
||||
"PofuillySlime": 13,
|
||||
"PanArms": 7,
|
||||
"NarLily": 2
|
||||
"PanArms": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -280,13 +277,12 @@
|
||||
"enemyCounts": {
|
||||
"EvilShark": 94,
|
||||
"PalShark": 31,
|
||||
"PoisonLily": 20,
|
||||
"PoisonLily": 22,
|
||||
"GrassAssassin": 12,
|
||||
"NanoDragon": 14,
|
||||
"PofuillySlime": 8,
|
||||
"GuilShark": 10,
|
||||
"PanArms": 3,
|
||||
"NarLily": 2
|
||||
"PanArms": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -616,12 +612,11 @@
|
||||
"enemyCounts": {
|
||||
"GrassAssassin": 14,
|
||||
"EvilShark": 38,
|
||||
"PoisonLily": 15,
|
||||
"PoisonLily": 17,
|
||||
"NanoDragon": 10,
|
||||
"PalShark": 16,
|
||||
"PanArms": 6,
|
||||
"GuilShark": 12,
|
||||
"NarLily": 2
|
||||
"GuilShark": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1024,11 +1019,10 @@
|
||||
"EvilShark": 24,
|
||||
"PalShark": 30,
|
||||
"GuilShark": 34,
|
||||
"PoisonLily": 42,
|
||||
"PoisonLily": 45,
|
||||
"GrassAssassin": 81,
|
||||
"NanoDragon": 17,
|
||||
"PanArms": 12,
|
||||
"NarLily": 3,
|
||||
"Dubswitch": 4,
|
||||
"Dubchic": 39,
|
||||
"Gilchic": 44,
|
||||
@ -1169,14 +1163,12 @@
|
||||
"Hildebear": 5,
|
||||
"EvilShark": 125,
|
||||
"PalShark": 44,
|
||||
"NarLily": 6,
|
||||
"PoisonLily": 23,
|
||||
"GrassAssassin": 14,
|
||||
"GuilShark": 25,
|
||||
"PanArms": 6,
|
||||
"PoisonLily": 17,
|
||||
"NanoDragon": 12,
|
||||
"PouillySlime": 2,
|
||||
"PofuillySlime": 9,
|
||||
"PofuillySlime": 11,
|
||||
"Dragon": 1
|
||||
}
|
||||
},
|
||||
@ -1401,14 +1393,13 @@
|
||||
"name": "5-1:Test/VR Temple 1",
|
||||
"episode": 2,
|
||||
"enemyCounts": {
|
||||
"PoisonLily2": 29,
|
||||
"PoisonLily2": 31,
|
||||
"Dimenian2": 17,
|
||||
"LaDimenian2": 33,
|
||||
"GrassAssassin2": 16,
|
||||
"RagRappy2": 13,
|
||||
"Hildebear2": 5,
|
||||
"Monest2": 3,
|
||||
"NarLily2": 2
|
||||
"Monest2": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1448,13 +1439,12 @@
|
||||
"name": "5-4:Test/VR Temple 4",
|
||||
"episode": 2,
|
||||
"enemyCounts": {
|
||||
"PoisonLily2": 56,
|
||||
"PoisonLily2": 61,
|
||||
"Dimenian2": 14,
|
||||
"LaDimenian2": 47,
|
||||
"GrassAssassin2": 24,
|
||||
"RagRappy2": 29,
|
||||
"Hildebear2": 5,
|
||||
"NarLily2": 5,
|
||||
"Monest2": 5,
|
||||
"SoDimenian2": 23,
|
||||
"DarkBelra2": 8
|
||||
@ -1687,13 +1677,12 @@
|
||||
"Dimenian2": 48,
|
||||
"LaDimenian2": 41,
|
||||
"SoDimenian2": 54,
|
||||
"PoisonLily2": 95,
|
||||
"PoisonLily2": 105,
|
||||
"GrassAssassin2": 20,
|
||||
"RagRappy2": 69,
|
||||
"Hildebear2": 38,
|
||||
"Monest2": 13,
|
||||
"DarkBelra2": 36,
|
||||
"NarLily2": 10,
|
||||
"SinowBerill": 12,
|
||||
"SinowSpigell": 16,
|
||||
"Gibbles": 4,
|
||||
@ -2426,13 +2415,12 @@
|
||||
"SoDimenian2": 55,
|
||||
"Dimenian2": 48,
|
||||
"LaDimenian2": 41,
|
||||
"PoisonLily2": 95,
|
||||
"PoisonLily2": 105,
|
||||
"GrassAssassin2": 20,
|
||||
"RagRappy2": 69,
|
||||
"Hildebear2": 38,
|
||||
"Monest2": 13,
|
||||
"DarkBelra2": 36,
|
||||
"NarLily2": 10,
|
||||
"SinowBerill": 12,
|
||||
"SinowSpigell": 16,
|
||||
"Gibbles": 4,
|
||||
|
@ -95,20 +95,42 @@ function parseObjectCode(cursor: ArrayBufferCursor, lenient: boolean): Instructi
|
||||
break;
|
||||
}
|
||||
|
||||
const [, mnemonic, mask] = list[opcode];
|
||||
const opargs = parseInstructionArguments(cursor, mask);
|
||||
let [, mnemonic, mask] = list[opcode];
|
||||
|
||||
if (!opargs) {
|
||||
logger.error(`Parameters unknown for opcode 0x${opcode.toString(16).toUpperCase()}.`);
|
||||
break;
|
||||
if (mask == null) {
|
||||
let fullOpcode = mainOpcode;
|
||||
|
||||
if (mainOpcode === 0xF8 || mainOpcode === 0xF9) {
|
||||
fullOpcode = (fullOpcode << 8) | opcode;
|
||||
}
|
||||
|
||||
logger.warn(`Parameters unknown for opcode 0x${fullOpcode.toString(16).toUpperCase()}, assuming 0.`);
|
||||
|
||||
instructions.push({
|
||||
opcode,
|
||||
mnemonic,
|
||||
args: [],
|
||||
size: opsize
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
const opargs = parseInstructionArguments(cursor, mask);
|
||||
|
||||
instructions.push({
|
||||
opcode,
|
||||
mnemonic,
|
||||
args: opargs.args,
|
||||
size: opsize + opargs.size
|
||||
});
|
||||
} catch (e) {
|
||||
instructions.push({
|
||||
opcode,
|
||||
mnemonic,
|
||||
args: [],
|
||||
size: opsize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
instructions.push({
|
||||
opcode,
|
||||
mnemonic,
|
||||
args: opargs.args,
|
||||
size: opsize + opargs.size
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (lenient) {
|
||||
@ -121,14 +143,13 @@ function parseObjectCode(cursor: ArrayBufferCursor, lenient: boolean): Instructi
|
||||
return instructions;
|
||||
}
|
||||
|
||||
function parseInstructionArguments(cursor: ArrayBufferCursor, mask: string | null) {
|
||||
if (mask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
function parseInstructionArguments(
|
||||
cursor: ArrayBufferCursor,
|
||||
mask: string
|
||||
): { args: any[], size: number } {
|
||||
const oldPos = cursor.position;
|
||||
const args = [];
|
||||
let size = 0;
|
||||
let argsSize: number;
|
||||
|
||||
outer:
|
||||
for (let i = 0; i < mask.length; ++i) {
|
||||
@ -143,71 +164,63 @@ function parseInstructionArguments(cursor: ArrayBufferCursor, mask: string | nul
|
||||
// Unsigned integers
|
||||
case 'B':
|
||||
args.push(cursor.u8());
|
||||
size += 1;
|
||||
break;
|
||||
case 'W':
|
||||
args.push(cursor.u16());
|
||||
size += 2;
|
||||
break;
|
||||
case 'L':
|
||||
args.push(cursor.u32());
|
||||
size += 4;
|
||||
break;
|
||||
|
||||
// Signed integers
|
||||
case 'I':
|
||||
args.push(cursor.i32());
|
||||
size += 4;
|
||||
break;
|
||||
|
||||
// Floats
|
||||
case 'f':
|
||||
case 'F':
|
||||
args.push(cursor.f32());
|
||||
size += 4;
|
||||
break;
|
||||
|
||||
// Registers?
|
||||
case 'R':
|
||||
case 'r':
|
||||
size += 1;
|
||||
cursor.seek(1);
|
||||
break;
|
||||
|
||||
// Pointers to unsigned integers?
|
||||
// Registers with unsigned integers?
|
||||
case 'b':
|
||||
args.push(cursor.u8());
|
||||
size += 1;
|
||||
break;
|
||||
case 'w':
|
||||
args.push(cursor.u16());
|
||||
size += 2;
|
||||
break;
|
||||
case 'l':
|
||||
args.push(cursor.u32());
|
||||
size += 4;
|
||||
break;
|
||||
|
||||
// Pointers to signed integers?
|
||||
// Registers with signed integers?
|
||||
case 'i':
|
||||
args.push(cursor.i32());
|
||||
size += 4;
|
||||
break;
|
||||
|
||||
// Variably sized data (e.g. strings)?
|
||||
// Variably sized data?
|
||||
case 'j':
|
||||
case 'J':
|
||||
size += 1 + cursor.seek(size).u8() * 2;
|
||||
argsSize = 2 * cursor.u8();
|
||||
cursor.seek(argsSize);
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
size += 1 + cursor.seek(size).u8();
|
||||
argsSize = cursor.u8();
|
||||
cursor.seek(argsSize);
|
||||
break;
|
||||
|
||||
// Strings
|
||||
case 's':
|
||||
case 'S':
|
||||
while (cursor.u16()) {
|
||||
size += 2;
|
||||
}
|
||||
size += 2;
|
||||
while (cursor.u16()) { }
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -215,8 +228,7 @@ function parseInstructionArguments(cursor: ArrayBufferCursor, mask: string | nul
|
||||
}
|
||||
}
|
||||
|
||||
cursor.seekStart(oldPos + size);
|
||||
return { args, size };
|
||||
return { args, size: cursor.position - oldPos };
|
||||
}
|
||||
|
||||
const opcodeList: Array<[number, string, string | null]> = [
|
||||
|
@ -106,7 +106,7 @@ export function parseDat(cursor: ArrayBufferCursor): DatFile {
|
||||
const rotationY = cursor.i32() / 0xFFFF * 2 * Math.PI;
|
||||
const rotationZ = cursor.i32() / 0xFFFF * 2 * Math.PI;
|
||||
const unknown3 = cursor.u8Array(4);
|
||||
const flags = cursor.u32();
|
||||
const flags = cursor.f32();
|
||||
const unknown4 = cursor.u8Array(12);
|
||||
const skin = cursor.u32();
|
||||
const unknown5 = cursor.u8Array(4);
|
||||
@ -202,7 +202,7 @@ export function writeDat({ objs, npcs, unknowns }: DatFile): ArrayBufferCursor {
|
||||
cursor.writeI32(Math.round(npc.rotation.y / (2 * Math.PI) * 0xFFFF));
|
||||
cursor.writeI32(Math.round(npc.rotation.z / (2 * Math.PI) * 0xFFFF));
|
||||
cursor.writeU8Array(npc.unknown[2]);
|
||||
cursor.writeU32(npc.flags);
|
||||
cursor.writeF32(npc.flags);
|
||||
cursor.writeU8Array(npc.unknown[3]);
|
||||
cursor.writeU32(npc.skin);
|
||||
cursor.writeU8Array(npc.unknown[4]);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ArrayBufferCursor } from '../../ArrayBufferCursor';
|
||||
import * as prs from '../../compression/prs';
|
||||
import { parseDat, writeDat, DatObject, DatNpc } from './dat';
|
||||
import { parseDat, writeDat, DatObject, DatNpc, DatFile } from './dat';
|
||||
import { parseBin, writeBin, Instruction } from './bin';
|
||||
import { parseQst, writeQst } from './qst';
|
||||
import {
|
||||
@ -64,7 +64,7 @@ export function parseQuest(cursor: ArrayBufferCursor, lenient: boolean = false):
|
||||
|
||||
if (func0Ops) {
|
||||
episode = getEpisode(func0Ops);
|
||||
areaVariants = getAreaVariants(episode, func0Ops, lenient);
|
||||
areaVariants = getAreaVariants(dat, episode, func0Ops, lenient);
|
||||
} else {
|
||||
logger.warn(`Function 0 offset ${bin.functionOffsets[0]} is invalid.`);
|
||||
}
|
||||
@ -132,11 +132,22 @@ function getEpisode(func0Ops: Instruction[]): number {
|
||||
}
|
||||
|
||||
function getAreaVariants(
|
||||
dat: DatFile,
|
||||
episode: number,
|
||||
func0Ops: Instruction[],
|
||||
lenient: boolean
|
||||
): AreaVariant[] {
|
||||
// Add area variants that have npcs or objects even if there are no BB_Map_Designate instructions for them.
|
||||
const areaVariants = new Map();
|
||||
|
||||
for (const npc of dat.npcs) {
|
||||
areaVariants.set(npc.areaId, 0);
|
||||
}
|
||||
|
||||
for (const obj of dat.objs) {
|
||||
areaVariants.set(obj.areaId, 0);
|
||||
}
|
||||
|
||||
const bbMaps = func0Ops.filter(op => op.mnemonic === 'BB_Map_Designate');
|
||||
|
||||
for (const bbMap of bbMaps) {
|
||||
@ -224,7 +235,7 @@ function parseNpcData(episode: number, npcs: DatNpc[]): QuestNpc[] {
|
||||
|
||||
// TODO: detect Mothmant, St. Rappy, Hallo Rappy, Egg Rappy, Death Gunner, Bulk and Recon.
|
||||
function getNpcType(episode: number, { typeId, flags, skin, areaId }: DatNpc): NpcType {
|
||||
const regular = (flags & 0x800000) === 0;
|
||||
const regular = Math.abs(flags - 1) > 0.00001;
|
||||
|
||||
switch (`${typeId}, ${skin % 3}, ${episode}`) {
|
||||
case `${0x044}, 0, 1`: return NpcType.Booma;
|
||||
@ -266,11 +277,6 @@ function getNpcType(episode: number, { typeId, flags, skin, areaId }: DatNpc): N
|
||||
case `${0x041}, 1, 2`: return NpcType.LoveRappy;
|
||||
case `${0x041}, 1, 4`: return NpcType.DelRappy;
|
||||
|
||||
case `${0x061}, 0, 1`: return areaId > 15 ? NpcType.DelLily : NpcType.PoisonLily;
|
||||
case `${0x061}, 0, 2`: return areaId > 15 ? NpcType.DelLily : NpcType.PoisonLily2;
|
||||
case `${0x061}, 1, 1`: return areaId > 15 ? NpcType.DelLily : NpcType.NarLily;
|
||||
case `${0x061}, 1, 2`: return areaId > 15 ? NpcType.DelLily : NpcType.NarLily2;
|
||||
|
||||
case `${0x080}, 0, 1`: return NpcType.Dubchic;
|
||||
case `${0x080}, 0, 2`: return NpcType.Dubchic2;
|
||||
case `${0x080}, 1, 1`: return NpcType.Gilchic;
|
||||
@ -306,6 +312,10 @@ function getNpcType(episode: number, { typeId, flags, skin, areaId }: DatNpc): N
|
||||
|
||||
case `${0x060}, 1`: return NpcType.GrassAssassin;
|
||||
case `${0x060}, 2`: return NpcType.GrassAssassin2;
|
||||
case `${0x061}, 1`: return areaId > 15 ? NpcType.DelLily : (
|
||||
regular ? NpcType.PoisonLily : NpcType.NarLily);
|
||||
case `${0x061}, 2`: return areaId > 15 ? NpcType.DelLily : (
|
||||
regular ? NpcType.PoisonLily2 : NpcType.NarLily2);
|
||||
case `${0x062}, 1`: return NpcType.NanoDragon;
|
||||
case `${0x064}, 1`: return regular ? NpcType.PofuillySlime : NpcType.PouillySlime;
|
||||
case `${0x065}, 1`: return NpcType.PanArms;
|
||||
|
Loading…
Reference in New Issue
Block a user