(Only) Enter Forgotten Hall, Set Game Mode, Clean Up Map/Maze Excels (#56)
* Implement avatar levelup and promotion. * Clean up maz and map excels, set the correct game mode based on plane type, make forgotten hall enterable. * Remove non-working spawn command.
This commit is contained in:
parent
5e1209deba
commit
22cd1f6ba1
@ -3,6 +3,7 @@ import { ActorEntity } from "../game/entities/Actor";
|
|||||||
import Interface, { Command } from "./Interface";
|
import Interface, { Command } from "./Interface";
|
||||||
import { GetCurSceneInfoScRsp } from "../data/proto/StarRail";
|
import { GetCurSceneInfoScRsp } from "../data/proto/StarRail";
|
||||||
import MazePlaneExcel from "../util/excel/MazePlaneExcel";
|
import MazePlaneExcel from "../util/excel/MazePlaneExcel";
|
||||||
|
import MapEntryExcel from "../util/excel/MapEntryExcel";
|
||||||
const c = new Logger("/scene", "blue");
|
const c = new Logger("/scene", "blue");
|
||||||
|
|
||||||
export default async function handle(command: Command) {
|
export default async function handle(command: Command) {
|
||||||
@ -11,8 +12,8 @@ export default async function handle(command: Command) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0]))
|
const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0]));
|
||||||
const uid = Interface.target.player.db._id;
|
const entryId = MapEntryExcel.fromFloorId(planeID.StartFloorID).ID;
|
||||||
const posData = Interface.target.player.db.posData;
|
const posData = Interface.target.player.db.posData;
|
||||||
|
|
||||||
const lineup2 = await Interface.target.player.getLineup();
|
const lineup2 = await Interface.target.player.getLineup();
|
||||||
@ -35,9 +36,9 @@ export default async function handle(command: Command) {
|
|||||||
curAvatarEntity
|
curAvatarEntity
|
||||||
],
|
],
|
||||||
entityBuffList: [],
|
entityBuffList: [],
|
||||||
entryId: 10001,
|
entryId: entryId,
|
||||||
envBuffList: [],
|
envBuffList: [],
|
||||||
gameModeType: 1,
|
gameModeType: MazePlaneExcel.getGameModeForPlaneType(planeID.PlaneType),
|
||||||
lightenSectionList: []
|
lightenSectionList: []
|
||||||
},
|
},
|
||||||
} as unknown as GetCurSceneInfoScRsp);
|
} as unknown as GetCurSceneInfoScRsp);
|
||||||
|
@ -13,9 +13,11 @@ export class Scene {
|
|||||||
public spawnEntity(entity: Entity, silent: boolean = false) {
|
public spawnEntity(entity: Entity, silent: boolean = false) {
|
||||||
this.entities.set(entity.entityId, entity);
|
this.entities.set(entity.entityId, entity);
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
this.player.session.send(SceneEntityUpdateScNotify, {
|
const dataObj : SceneEntityUpdateScNotify = {
|
||||||
entityList: [entity.getSceneEntityInfo()]
|
entityList: [entity.getSceneEntityInfo()]
|
||||||
} as SceneEntityUpdateScNotify);
|
};
|
||||||
|
|
||||||
|
this.player.session.send(SceneEntityUpdateScNotify, dataObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,15 +10,16 @@ export class ActorEntity extends Entity
|
|||||||
super(scene, pos, rot);
|
super(scene, pos, rot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSceneEntityInfo(): SceneEntityInfo {
|
public getSceneActorInfo(): SceneEntityInfo {
|
||||||
const sceneEntityInfo = super.getSceneEntityInfo();
|
return {
|
||||||
sceneEntityInfo.actor = {
|
...super.getSceneEntityInfo(),
|
||||||
|
actor: {
|
||||||
avatarType: AvatarType.AVATAR_FORMAL_TYPE,
|
avatarType: AvatarType.AVATAR_FORMAL_TYPE,
|
||||||
baseAvatarId: this.avatarId,
|
baseAvatarId: this.avatarId,
|
||||||
uid: this.scene.player.db._id,
|
uid: this.scene.player.db._id,
|
||||||
mapLayer: 0 //?
|
mapLayer: 0 //?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return sceneEntityInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEntityType(): EntityType {
|
public getEntityType(): EntityType {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { EnterMazeCsReq, EnterMazeScRsp } from "../../data/proto/StarRail";
|
import { EnterMazeCsReq, EnterMazeScRsp } from "../../data/proto/StarRail";
|
||||||
|
import MapEntryExcel from "../../util/excel/MapEntryExcel";
|
||||||
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
||||||
import Packet from "../kcp/Packet";
|
import Packet from "../kcp/Packet";
|
||||||
import Session from "../kcp/Session";
|
import Session from "../kcp/Session";
|
||||||
@ -6,7 +7,8 @@ import Session from "../kcp/Session";
|
|||||||
export default async function handle(session: Session, packet: Packet) {
|
export default async function handle(session: Session, packet: Packet) {
|
||||||
const body = packet.body as EnterMazeCsReq;
|
const body = packet.body as EnterMazeCsReq;
|
||||||
|
|
||||||
const mazeEntry = MazePlaneExcel.getEntry(body.entryId);
|
const mazeEntry = MapEntryExcel.fromId(body.entryId);
|
||||||
|
const mazePlane = MazePlaneExcel.fromPlaneId(mazeEntry.PlaneID);
|
||||||
|
|
||||||
let curLineup = await session.player.getLineup();
|
let curLineup = await session.player.getLineup();
|
||||||
curLineup.planeId = mazeEntry.PlaneID;
|
curLineup.planeId = mazeEntry.PlaneID;
|
||||||
@ -23,7 +25,7 @@ export default async function handle(session: Session, packet: Packet) {
|
|||||||
scene: {
|
scene: {
|
||||||
planeId: mazeEntry.PlaneID,
|
planeId: mazeEntry.PlaneID,
|
||||||
floorId: mazeEntry.FloorID,
|
floorId: mazeEntry.FloorID,
|
||||||
gameModeType: 1,
|
gameModeType: MazePlaneExcel.getGameModeForPlaneType(mazePlane.PlaneType),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
id: mazeEntry.PlaneID,
|
id: mazeEntry.PlaneID,
|
||||||
|
@ -1,28 +1,38 @@
|
|||||||
import { GetCurSceneInfoScRsp, Vector } from "../../data/proto/StarRail";
|
import { GetCurSceneInfoScRsp, MotionInfo, SceneEntityInfo, SceneNpcMonsterInfo, Vector } from "../../data/proto/StarRail";
|
||||||
import { ActorEntity } from "../../game/entities/Actor";
|
import { ActorEntity } from "../../game/entities/Actor";
|
||||||
|
import MapEntryExcel from "../../util/excel/MapEntryExcel";
|
||||||
|
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
||||||
import Packet from "../kcp/Packet";
|
import Packet from "../kcp/Packet";
|
||||||
import Session from "../kcp/Session";
|
import Session from "../kcp/Session";
|
||||||
|
|
||||||
export default async function handle(session: Session, packet: Packet) {
|
export default async function handle(session: Session, packet: Packet) {
|
||||||
|
// Get data.
|
||||||
const posData = session.player.db.posData;
|
const posData = session.player.db.posData;
|
||||||
const _lineup = session.player.db.lineup;
|
const _lineup = session.player.db.lineup;
|
||||||
const lineup = _lineup.lineups[_lineup.curIndex];
|
const lineup = _lineup.lineups[_lineup.curIndex];
|
||||||
const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[0], posData.pos);
|
const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[lineup.leaderSlot], posData.pos);
|
||||||
|
const entryId = MapEntryExcel.fromFloorId(posData.floorID).ID;
|
||||||
|
const mazePlane = MazePlaneExcel.fromPlaneId(posData.planeID);
|
||||||
|
|
||||||
|
// Scene management.
|
||||||
|
session.player.scene.spawnEntity(curAvatarEntity, true);
|
||||||
|
session.player.scene.entryId = entryId;
|
||||||
|
|
||||||
|
// Send response.
|
||||||
session.send(GetCurSceneInfoScRsp, {
|
session.send(GetCurSceneInfoScRsp, {
|
||||||
retcode: 0,
|
retcode: 0,
|
||||||
scene: {
|
scene: {
|
||||||
planeId: posData.planeID,
|
planeId: posData.planeID,
|
||||||
floorId: posData.floorID,
|
floorId: posData.floorID,
|
||||||
entityList: [
|
entityList: [
|
||||||
curAvatarEntity
|
curAvatarEntity.getSceneEntityInfo()
|
||||||
],
|
],
|
||||||
|
lightenSectionList: [],
|
||||||
|
leaderEntityId: curAvatarEntity.entityId,
|
||||||
entityBuffList: [],
|
entityBuffList: [],
|
||||||
entryId: 10001,
|
entryId: entryId,
|
||||||
envBuffList: [],
|
envBuffList: [],
|
||||||
gameModeType: 1,
|
gameModeType: MazePlaneExcel.getGameModeForPlaneType(mazePlane.PlaneType),
|
||||||
lightenSectionList: []
|
|
||||||
},
|
},
|
||||||
} as unknown as GetCurSceneInfoScRsp);
|
} as GetCurSceneInfoScRsp);
|
||||||
session.player.scene.spawnEntity(curAvatarEntity, true);
|
|
||||||
session.player.scene.entryId = 10001;
|
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { GetMazeMapInfoCsReq, GetMazeMapInfoScRsp } from "../../data/proto/StarRail";
|
import { GetMazeMapInfoCsReq, GetMazeMapInfoScRsp } from "../../data/proto/StarRail";
|
||||||
|
import MapEntryExcel from "../../util/excel/MapEntryExcel";
|
||||||
import MappingInfoExcel from "../../util/excel/MappingInfoExcel";
|
import MappingInfoExcel from "../../util/excel/MappingInfoExcel";
|
||||||
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
||||||
import Packet from "../kcp/Packet";
|
import Packet from "../kcp/Packet";
|
||||||
@ -24,7 +25,7 @@ export default async function handle(session: Session, packet: Packet) {
|
|||||||
dataObj.lightenSectionList.push(i)
|
dataObj.lightenSectionList.push(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataObj.unlockTeleportList = MazePlaneExcel.getAllEntries().map(x => x.ID);
|
dataObj.unlockTeleportList = MapEntryExcel.all().map(x => x.ID);
|
||||||
|
|
||||||
session.send(GetMazeMapInfoScRsp, dataObj);
|
session.send(GetMazeMapInfoScRsp, dataObj);
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ import Session from "../kcp/Session";
|
|||||||
|
|
||||||
export default async function handle(session: Session, packet: Packet) {
|
export default async function handle(session: Session, packet: Packet) {
|
||||||
const body = packet.body as SceneEntityMoveCsReq;
|
const body = packet.body as SceneEntityMoveCsReq;
|
||||||
|
|
||||||
if (session.player.scene.entryId !== body.entryId) {
|
if (session.player.scene.entryId !== body.entryId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
import { ChallengeStatus, ExtraLineupType, StartChallengeCsReq, StartChallengeScRsp } from "../../data/proto/StarRail";
|
import { ChallengeStatus, CurChallenge, ExtraLineupType, Maze, SceneActorInfo, SceneEntityInfo, SceneInfo, SceneNpcInfo, SceneNpcMonsterInfo, ScenePropInfo, StartChallengeCsReq, StartChallengeScRsp } from "../../data/proto/StarRail";
|
||||||
|
import { ActorEntity } from "../../game/entities/Actor";
|
||||||
import Packet from "../kcp/Packet";
|
import Packet from "../kcp/Packet";
|
||||||
import Session from "../kcp/Session";
|
import Session from "../kcp/Session";
|
||||||
|
|
||||||
// StartChallengeCsReq { challengeId: 101 }
|
// StartChallengeCsReq { challengeId: 101 }
|
||||||
export default async function handle(session: Session, packet: Packet) {
|
export default async function handle(session: Session, packet: Packet) {
|
||||||
const body = packet.body as StartChallengeCsReq;
|
const body = packet.body as StartChallengeCsReq;
|
||||||
|
console.log(JSON.stringify(body, undefined, 4));
|
||||||
|
|
||||||
// TODO: This packet is just a base
|
// TODO: This packet is just a base
|
||||||
|
const _lineup = session.player.db.lineup;
|
||||||
|
const lineup = _lineup.lineups[_lineup.curIndex];
|
||||||
|
const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[lineup.leaderSlot], { x: 0, y: 0, z: 0 });
|
||||||
|
|
||||||
session.send(StartChallengeScRsp, {
|
session.send(StartChallengeScRsp, {
|
||||||
retcode: 0,
|
retcode: 0,
|
||||||
curChallenge: {
|
curChallenge: {
|
||||||
challengeId: body.challengeId,
|
challengeId: body.challengeId,
|
||||||
deadAvatarNum: 0,
|
|
||||||
extraLineupType: ExtraLineupType.LINEUP_CHALLENGE,
|
|
||||||
rounds: 1,
|
rounds: 1,
|
||||||
status: ChallengeStatus.CHALLENGE_DOING,
|
status: ChallengeStatus.CHALLENGE_DOING,
|
||||||
killMonsterList: [{
|
extraLineupType: ExtraLineupType.LINEUP_NONE,
|
||||||
monsterId: 8013010,
|
killMonsterList: [],
|
||||||
killNum: 1,
|
deadAvatarNum: 0,
|
||||||
}]
|
} as CurChallenge,
|
||||||
},
|
|
||||||
maze: {
|
maze: {
|
||||||
// ? Data from MappingInfoExcelTable
|
// ? Data from MappingInfoExcelTable
|
||||||
id: 30101,
|
id: 30104,
|
||||||
mapEntryId: 10001,
|
mapEntryId: 3000401,
|
||||||
floor: {
|
floor: {
|
||||||
floorId: 20121001,
|
floorId: 20121001,
|
||||||
scene: {
|
scene: {
|
||||||
planeId: 20121,
|
planeId: 30104,
|
||||||
entryId: 1000,
|
entryId: 3000401,
|
||||||
floorId: 20121001,
|
floorId: 30104001,
|
||||||
gameModeType: 1,
|
lightenSectionList: [],
|
||||||
entityList: [{
|
gameModeType: 4,
|
||||||
entityId: 10010101,
|
entityList: [
|
||||||
npcMonster: {
|
curAvatarEntity.getSceneEntityInfo(),
|
||||||
monsterId: 8013010,
|
{
|
||||||
worldLevel: 1,
|
entityId: 10000,
|
||||||
},
|
|
||||||
groupId: 11,
|
|
||||||
motion: {
|
motion: {
|
||||||
pos: {
|
pos: {
|
||||||
x: 0,
|
x: 74719,
|
||||||
y: 100,
|
y: 2014,
|
||||||
z: 0,
|
z: -94205,
|
||||||
},
|
},
|
||||||
rot: {
|
rot: {
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -51,9 +51,26 @@ export default async function handle(session: Session, packet: Packet) {
|
|||||||
z: 0
|
z: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}]
|
groupId: 3,
|
||||||
}
|
instId: 1,
|
||||||
}
|
actor: {} as SceneActorInfo,
|
||||||
|
npc: {} as SceneNpcInfo,
|
||||||
|
prop: {} as ScenePropInfo,
|
||||||
|
npcMonster: {
|
||||||
|
monsterId: 1003020,
|
||||||
|
isGenMonster: false,
|
||||||
|
eventId: 0,
|
||||||
|
isSetWorldLevel: false,
|
||||||
|
worldLevel: 6
|
||||||
|
} as SceneNpcMonsterInfo
|
||||||
|
} as SceneEntityInfo,
|
||||||
|
],
|
||||||
|
leaderEntityId: curAvatarEntity.entityId,
|
||||||
|
entityBuffList: [],
|
||||||
|
envBuffList: [],
|
||||||
|
snar: ""
|
||||||
|
} as SceneInfo
|
||||||
}
|
}
|
||||||
|
} as Maze
|
||||||
} as StartChallengeScRsp);
|
} as StartChallengeScRsp);
|
||||||
}
|
}
|
24
src/util/excel/MapEntryExcel.ts
Normal file
24
src/util/excel/MapEntryExcel.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import _MapEntryExcelTable from "../../data/excel/MapEntryExcelTable.json";
|
||||||
|
type MapEntryExcelTableEntry = typeof _MapEntryExcelTable[keyof typeof _MapEntryExcelTable]
|
||||||
|
const MapEntryExcelTable = _MapEntryExcelTable as { [key: string]: MapEntryExcelTableEntry };
|
||||||
|
|
||||||
|
export default class MapEntryExcel {
|
||||||
|
private constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static all() : MapEntryExcelTableEntry[] {
|
||||||
|
return Object.values(MapEntryExcelTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromId(id: number) : MapEntryExcelTableEntry {
|
||||||
|
return MapEntryExcelTable[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromIds(ids: number[]): MapEntryExcelTableEntry[] {
|
||||||
|
return ids.map(id => MapEntryExcel.fromId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromFloorId(id: number) : MapEntryExcelTableEntry {
|
||||||
|
return Object.values(MapEntryExcelTable).filter(e => e.FloorID == id)?.[0];
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import _MapEntryExcelTable from "../../data/excel/MapEntryExcelTable.json";
|
|
||||||
import _MazePlaneExcelTable from "../../data/excel/MazePlaneExcelTable.json";
|
import _MazePlaneExcelTable from "../../data/excel/MazePlaneExcelTable.json";
|
||||||
|
import MapEntryExcel from "./MapEntryExcel";
|
||||||
|
|
||||||
interface MazePlaneExcelTableEntry {
|
interface MazePlaneExcelTableEntry {
|
||||||
PlaneID: number;
|
PlaneID: number;
|
||||||
@ -11,44 +11,13 @@ interface MazePlaneExcelTableEntry {
|
|||||||
FloorIDList: number[];
|
FloorIDList: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TextMap {
|
|
||||||
hash: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
type EntranceType = "Town" | "Mission" | "Explore";
|
|
||||||
|
|
||||||
interface MapEntryExcelTableEntry {
|
|
||||||
ID: number;
|
|
||||||
IsShowInMapMenu: boolean;
|
|
||||||
MapMenuSortID: number;
|
|
||||||
EntranceType: EntranceType | number; // Actually an enum. Town | Mission | Explore
|
|
||||||
EntranceGroupID: number;
|
|
||||||
Name: TextMap;
|
|
||||||
Desc: TextMap;
|
|
||||||
EntranceListIcon: string;
|
|
||||||
ImagePath: string;
|
|
||||||
MiniMapIconHintList: any[];
|
|
||||||
ShowReward: number;
|
|
||||||
PlaneID: number;
|
|
||||||
FloorID: number;
|
|
||||||
StartGroupID: number;
|
|
||||||
StartAnchorID: number;
|
|
||||||
TargetMission: number;
|
|
||||||
TargetMainMissionList: number[];
|
|
||||||
BeginMainMissionList: number[];
|
|
||||||
FinishMainMissionList: number[];
|
|
||||||
FinishQuestList: number[];
|
|
||||||
UnlockQuest: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MazePlaneExcelTable = _MazePlaneExcelTable as { [key: string]: MazePlaneExcelTableEntry };
|
const MazePlaneExcelTable = _MazePlaneExcelTable as { [key: string]: MazePlaneExcelTableEntry };
|
||||||
const MapEntryExcelTable = _MapEntryExcelTable as { [key: string]: MapEntryExcelTableEntry };
|
|
||||||
|
|
||||||
export default class MazePlaneExcel {
|
export default class MazePlaneExcel {
|
||||||
private constructor() { }
|
private constructor() { }
|
||||||
|
|
||||||
public static fromEntryId(entryId: number): MazePlaneExcelTableEntry {
|
public static fromEntryId(entryId: number): MazePlaneExcelTableEntry {
|
||||||
const mapEntry = MapEntryExcelTable[entryId.toString()];
|
const mapEntry = MapEntryExcel.fromId(entryId);
|
||||||
return MazePlaneExcelTable[mapEntry.PlaneID.toString()];
|
return MazePlaneExcelTable[mapEntry.PlaneID.toString()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +25,21 @@ export default class MazePlaneExcel {
|
|||||||
return MazePlaneExcelTable[planeId.toString()];
|
return MazePlaneExcelTable[planeId.toString()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getEntry(entryId: number): MapEntryExcelTableEntry {
|
public static getGameModeForPlaneType(planeType: string): number {
|
||||||
return MapEntryExcelTable[entryId.toString()];
|
switch (planeType) {
|
||||||
|
case "Town": return 1;
|
||||||
|
case "Maze": return 2;
|
||||||
|
case "Train": return 3;
|
||||||
|
case "Challenge": return 4;
|
||||||
|
case "RogueExplore": return 5;
|
||||||
|
case "RogueChallenge": return 6;
|
||||||
|
case "TownRoom": return 7;
|
||||||
|
case "Raid": return 8;
|
||||||
|
case "FarmRelic": return 9;
|
||||||
|
case "Client": return 10;
|
||||||
|
case "ChallengeActivity": return 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getAllEntries(): MapEntryExcelTableEntry[] {
|
return 0;
|
||||||
return Object.values(MapEntryExcelTable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
20
src/util/excel/MonsterExcel.ts
Normal file
20
src/util/excel/MonsterExcel.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import _MonsterExcelTable from "../../data/excel/MonsterExcelTable.json";
|
||||||
|
type MonsterExcelTableEntry = typeof _MonsterExcelTable[keyof typeof _MonsterExcelTable]
|
||||||
|
const MonsterExcelTable = _MonsterExcelTable as { [key: string]: MonsterExcelTableEntry };
|
||||||
|
|
||||||
|
export default class MonsterExcel {
|
||||||
|
private constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static all() : MonsterExcelTableEntry[] {
|
||||||
|
return Object.values(MonsterExcelTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromId(id: number) : MonsterExcelTableEntry {
|
||||||
|
return MonsterExcelTable[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromIds(ids: number[]): MonsterExcelTableEntry[] {
|
||||||
|
return ids.map(id => MonsterExcel.fromId(id));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user