diff --git a/Makefile b/Makefile index 0e957b2..b83ccb0 100644 --- a/Makefile +++ b/Makefile @@ -173,8 +173,10 @@ MODEL_LIST = assets/models/cube/cube.blend \ assets/models/portal/portal_blue_face.blend \ assets/models/portal/portal_orange.blend \ assets/models/portal/portal_orange_filled.blend \ - assets/models/portal/portal_orange_face.blend + assets/models/portal/portal_orange_face.blend \ + assets/models/pedestal.blend +ANIM_LIST = build/assets/models/pedestal_anim.o MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h) MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o) @@ -188,6 +190,12 @@ build/src/decor/decor_object_list.o: $(MODEL_HEADERS) build/src/scene/portal.o: $(MODEL_HEADERS) +build/assets/models/%_anim.o: build/assets/models/%.h + +build/anims.ld: $(ANIM_LIST) tools/generate_animation_ld.js + @mkdir -p $(@D) + node tools/generate_animation_ld.js $@ $(ANIM_LIST) + #################### ## Test Chambers #################### @@ -271,6 +279,8 @@ build/src/audio/clips.h: tools/generate_sound_ids.js $(SOUND_CLIPS) build/src/audio/clips.o: build/src/audio/clips.h build/src/decor/decor_object_list.o: build/src/audio/clips.h +build/src/scene/pedestal.o: build/assets/models/pedestal.h + #################### ## Linking #################### @@ -292,7 +302,7 @@ $(CODESEGMENT)_no_debug.o: $(CODEOBJECTS_NO_DEBUG) $(LD) -o $(CODESEGMENT)_no_debug.o -r $(CODEOBJECTS_NO_DEBUG) $(LDFLAGS) -$(CP_LD_SCRIPT)_no_debug.ld: $(LD_SCRIPT) build/levels.ld +$(CP_LD_SCRIPT)_no_debug.ld: $(LD_SCRIPT) build/levels.ld build/anims.ld cpp -P -Wno-trigraphs $(LCDEFS) -DCODE_SEGMENT=$(CODESEGMENT)_no_debug.o -o $@ $< $(BASE_TARGET_NAME).z64: $(CODESEGMENT)_no_debug.o $(OBJECTS) $(CP_LD_SCRIPT)_no_debug.ld @@ -310,7 +320,7 @@ endif $(CODESEGMENT)_debug.o: $(CODEOBJECTS_DEBUG) $(LD) -o $(CODESEGMENT)_debug.o -r $(CODEOBJECTS_DEBUG) $(LDFLAGS) -$(CP_LD_SCRIPT)_debug.ld: $(LD_SCRIPT) build/levels.ld +$(CP_LD_SCRIPT)_debug.ld: $(LD_SCRIPT) build/levels.ld build/anims.ld cpp -P -Wno-trigraphs $(LCDEFS) -DCODE_SEGMENT=$(CODESEGMENT)_debug.o -o $@ $< $(BASE_TARGET_NAME)_debug.z64: $(CODESEGMENT)_debug.o $(OBJECTS) $(CP_LD_SCRIPT)_debug.ld diff --git a/README.md b/README.md index 9862f2d..273b486 100644 --- a/README.md +++ b/README.md @@ -84,20 +84,14 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender ## Current TODO list -- [ ] Fix bug where opening a portal can trigger a teleportation +- [ ] Prevent Glados from talking over herself +- [ ] Elevator and door sounds +- [ ] Portal gun pedistal - [ ] Turn level indicator board into a game object - [ ] Presort portal gun polygon order -- [ ] Implement level transitions - - Implement loading levels from the cartridge - [ ] Change the way player standing logic works - [ ] Cube dispenser - [ ] NAN in overlap -- [x] Implement "Elevator" -- [x] Implement "Emancipation grid" -- [x] Cut holes in portal walls -- [x] Get an optimized build working -- [x] Portal animations -- [x] Figure out why clip is silent -- [x] Fix z fighting in elevator -- [x] Fix crash -- [x] Determine why bad gfx cause RDP crash \ No newline at end of file +- [x] Fix portal overlapping bug +- [x] Fix bug where opening a portal can trigger a teleportation +- [x] Implement level transitions \ No newline at end of file diff --git a/assets/materials/objects.skm.yaml b/assets/materials/objects.skm.yaml index 949ab88..f49ca54 100644 --- a/assets/materials/objects.skm.yaml +++ b/assets/materials/objects.skm.yaml @@ -105,3 +105,31 @@ materials: set: [G_LIGHTING, G_SHADE] gDPSetCombineMode: color: ["SHADE", "0", "PRIMITIVE", "0"] + + solid_white: + gDPSetPrimColor: + r: 255 + g: 255 + b: 255 + gSPGeometryMode: + set: [G_LIGHTING, G_SHADE] + gDPSetCombineMode: + color: ["PRIMITIVE", "0", "SHADE", "0"] + + solid_black: + gDPSetPrimColor: + r: 32 + g: 32 + b: 32 + gSPGeometryMode: + set: [G_LIGHTING, G_SHADE] + gDPSetCombineMode: + color: ["PRIMITIVE", "0", "SHADE", "0"] + + blue_glow: + gDPSetPrimColor: + r: 32 + g: 32 + b: 32 + gDPSetCombineMode: + color: ["0", "0", "0", "PRIMITIVE"] diff --git a/assets/models/pedestal.blend b/assets/models/pedestal.blend new file mode 100644 index 0000000..e0e14ab Binary files /dev/null and b/assets/models/pedestal.blend differ diff --git a/assets/models/pedestal.flags b/assets/models/pedestal.flags new file mode 100644 index 0000000..b445cbb --- /dev/null +++ b/assets/models/pedestal.flags @@ -0,0 +1 @@ +-r 90,0,0 -m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material default \ No newline at end of file diff --git a/portal.ld b/portal.ld index d3bc9a6..30e9564 100644 --- a/portal.ld +++ b/portal.ld @@ -71,6 +71,7 @@ SECTIONS END_SEG(sound_data) #include "build/levels.ld" +#include "build/anims.ld" /* Discard everything not specifically mentioned above. */ /DISCARD/ : diff --git a/skelatool64/src/definition_generator/LevelGenerator.cpp b/skelatool64/src/definition_generator/LevelGenerator.cpp index e3f1279..eecdea0 100644 --- a/skelatool64/src/definition_generator/LevelGenerator.cpp +++ b/skelatool64/src/definition_generator/LevelGenerator.cpp @@ -664,6 +664,44 @@ void generateElevatorDefinitions( levelDef.AddPrimitive("elevatorCount", elevatorCount); } +void generatePedestalDefinitions( + const aiScene* scene, + CFileDefinition& fileDefinition, + StructureDataChunk& levelDef, + const RoomGeneratorOutput& roomOutput, + const DisplayListSettings& settings, + NodeGroups& nodeGroups) { + + int pedestalCount = 0; + std::unique_ptr pedestals(new StructureDataChunk()); + + aiMatrix4x4 baseTransform = settings.CreateCollisionTransform(); + + for (auto& nodeInfo : nodeGroups.NodesForType("@pedestal")) { + std::unique_ptr pedestalsData(new StructureDataChunk()); + aiVector3D pos; + aiQuaternion rot; + aiVector3D scale; + (baseTransform * nodeInfo.node->mTransformation).Decompose(scale, rot, pos); + pedestalsData->Add(std::unique_ptr(new StructureDataChunk(pos))); + pedestalsData->AddPrimitive(roomOutput.RoomForNode(nodeInfo.node)); + + pedestals->Add(std::move(pedestalsData)); + ++pedestalCount; + } + + std::string pedestalsCount = fileDefinition.AddDataDefinition( + "pedestals", + "struct PedestalDefinition", + true, + "_geo", + std::move(pedestals) + ); + + levelDef.AddPrimitive("pedestals", pedestalsCount); + levelDef.AddPrimitive("pedestalCount", pedestalCount); +} + void generateLevel( const aiScene* scene, CFileDefinition& fileDefinition, @@ -707,5 +745,7 @@ void generateLevel( generateElevatorDefinitions(scene, fileDefinition, *levelDef, roomOutput, settings, signals, nodeGroups); + generatePedestalDefinitions(scene, fileDefinition, *levelDef, roomOutput, settings, nodeGroups); + fileDefinition.AddDefinition(std::unique_ptr(new DataFileDefinition("struct LevelDefinition", fileDefinition.GetUniqueName("level"), false, "_geo", std::move(levelDef)))); } \ No newline at end of file diff --git a/src/levels/level_definition.h b/src/levels/level_definition.h index 02c0268..6f19012 100644 --- a/src/levels/level_definition.h +++ b/src/levels/level_definition.h @@ -130,6 +130,11 @@ struct ElevatorDefinition { short isExit; }; +struct PedestalDefinition { + struct Vector3 position; + short roomIndex; +}; + struct LevelDefinition { struct CollisionObject* collisionQuads; struct StaticContentElement *staticContent; @@ -149,6 +154,7 @@ struct LevelDefinition { struct DecorDefinition* decor; struct FizzlerDefinition* fizzlers; struct ElevatorDefinition* elevators; + struct PedestalDefinition* pedestals; short collisionQuadCount; short staticContentCount; short portalSurfaceCount; @@ -161,6 +167,7 @@ struct LevelDefinition { short decorCount; short fizzlerCount; short elevatorCount; + short pedestalCount; short startLocation; }; diff --git a/src/levels/levels.c b/src/levels/levels.c index c86bde5..569137d 100644 --- a/src/levels/levels.c +++ b/src/levels/levels.c @@ -76,6 +76,7 @@ struct LevelDefinition* levelFixPointers(struct LevelDefinition* from, int point result->decor = ADJUST_POINTER_POS(result->decor, pointerOffset); result->fizzlers = ADJUST_POINTER_POS(result->fizzlers, pointerOffset); result->elevators = ADJUST_POINTER_POS(result->elevators, pointerOffset); + result->pedestals = ADJUST_POINTER_POS(result->pedestals, pointerOffset); return result; } diff --git a/src/main.c b/src/main.c index 1c0d020..b86feab 100644 --- a/src/main.c +++ b/src/main.c @@ -149,7 +149,7 @@ static void gameProc(void* arg) { dynamicSceneInit(); contactSolverInit(&gContactSolver); - levelLoad(1); + levelLoad(0); controllersInit(); initAudio(); soundPlayerInit(); diff --git a/src/player/player.c b/src/player/player.c index e8133e9..bde2f88 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -79,7 +79,7 @@ void playerInit(struct Player* player, struct Location* startLocation) { #define ROTATE_RATE_DELTA (M_PI * 0.125f) #define ROTATE_RATE_STOP_DELTA (M_PI * 0.25f) -#define JUMP_IMPULSE 3.2f +#define JUMP_IMPULSE 2.7f void playerHandleCollision(struct Player* player) { struct ContactManifold* contact = contactSolverNextManifold(&gContactSolver, &player->collisionObject, NULL); diff --git a/src/player/player.h b/src/player/player.h index 3b6df36..e3be3ab 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -9,7 +9,7 @@ #define PLAYER_GRABBING_THROUGH_NOTHING -1 -#define PLAYER_HEAD_HEIGHT 0.8f +#define PLAYER_HEAD_HEIGHT 1.0f enum PlayerFlags { PlayerFlagsGrounded = (1 << 0), diff --git a/src/scene/camera.c b/src/scene/camera.c index 92e2628..1dce723 100644 --- a/src/scene/camera.c +++ b/src/scene/camera.c @@ -3,6 +3,7 @@ #include "math/transform.h" #include "defs.h" #include "../graphics/graphics.h" +#include "../math/mathf.h" int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox) { for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) { @@ -90,6 +91,10 @@ void cameraExtractClippingPlane(float viewPersp[4][4], struct Plane* output, int output->d *= mult; } +int cameraIsValidMatrix(float matrix[4][4]) { + return fabsf(matrix[3][0]) <= 0x7fff && fabsf(matrix[3][1]) <= 0x7fff && fabsf(matrix[3][2]) <= 0x7fff; +} + Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, float aspectRatio, u16* perspNorm, Vp* viewport, struct FrustrumCullingInformation* clippingInfo) { Mtx* viewProjMatrix = renderStateRequestMatrices(renderState, 2); @@ -97,6 +102,8 @@ Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, return NULL; } + Gfx* renderStateStart = renderState->dl; + guMtxIdent(&viewProjMatrix[0]); gSPMatrix(renderState->dl++, osVirtualToPhysical(&viewProjMatrix[0]), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); @@ -117,6 +124,11 @@ Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, cameraBuildViewMatrix(camera, view); guMtxCatF(view, persp, combined); + + if (!cameraIsValidMatrix(combined)) { + goto error; + } + guMtxF2L(combined, &viewProjMatrix[1]); if (clippingInfo) { @@ -137,4 +149,8 @@ Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, } return &viewProjMatrix[1]; + +error: + renderState->dl = renderStateStart; + return NULL; } \ No newline at end of file diff --git a/src/scene/pedestal.c b/src/scene/pedestal.c new file mode 100644 index 0000000..f4b0edc --- /dev/null +++ b/src/scene/pedestal.c @@ -0,0 +1,44 @@ +#include "pedestal.h" + +#include "../scene/dynamic_scene.h" +#include "../defs.h" + +#include "../build/assets/materials/static.h" +#include "../build/assets/models/pedestal.h" + +void pedestalRender(void* data, struct RenderScene* renderScene) { + struct Pedestal* pedestal = (struct Pedestal*)data; + + Mtx* matrix = renderStateRequestMatrices(renderScene->renderState, 1); + transformToMatrixL(&pedestal->transform, matrix, SCENE_SCALE); + + Mtx* armature = renderStateRequestMatrices(renderScene->renderState, pedestal->armature.numberOfBones); + + skCalculateTransforms(&pedestal->armature, armature); + + renderSceneAdd( + renderScene, + pedestal->armature.displayList, + matrix, + DEFAULT_INDEX, + &pedestal->transform.position, + armature + ); +} + +void pedestalInit(struct Pedestal* pedestal, struct PedestalDefinition* definition) { + transformInitIdentity(&pedestal->transform); + + pedestal->transform.position = definition->position; + pedestal->roomIndex = definition->roomIndex; + + skArmatureInit( + &pedestal->armature, + pedestal_model_gfx, + PEDESTAL_DEFAULT_BONES_COUNT, + pedestal_default_bones, + pedestal_bone_parent + ); + + pedestal->dynamicId = dynamicSceneAdd(pedestal, pedestalRender, &pedestal->transform, 0.8f); +} \ No newline at end of file diff --git a/src/scene/pedestal.h b/src/scene/pedestal.h new file mode 100644 index 0000000..8c4e47d --- /dev/null +++ b/src/scene/pedestal.h @@ -0,0 +1,17 @@ +#ifndef __SCENE_PEDESTAL_H__ +#define __SCENE_PEDESTAL_H__ + +#include "../sk64/skelatool_armature.h" +#include "../levels/level_definition.h" + +struct Pedestal { + struct Transform transform; + struct SKArmature armature; + + short dynamicId; + short roomIndex; +}; + +void pedestalInit(struct Pedestal* pedestal, struct PedestalDefinition* definition); + +#endif \ No newline at end of file diff --git a/src/scene/portal.c b/src/scene/portal.c index 8a74298..f0173fa 100644 --- a/src/scene/portal.c +++ b/src/scene/portal.c @@ -173,7 +173,7 @@ Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* rend return viewport; } -void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState) { +int renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState) { struct Transform otherInverse; transformInvert(fromPortal, &otherInverse); struct Transform portalCombined; @@ -200,7 +200,10 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru } // render any objects halfway through portals - cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, &next->perspectiveCorrect, current->viewport, NULL); + if (!cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, &next->perspectiveCorrect, current->viewport, NULL)) { + return 0; + } + dynamicSceneRenderTouchingPortal(&next->camera.transform, ¤t->cullingInfo, renderState); next->currentDepth = current->currentDepth - 1; @@ -240,6 +243,8 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru gSPViewport(renderState->dl++, viewport); gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, next->minX, next->minY, next->maxX, next->maxY); #endif + + return 1; } void portalInit(struct Portal* portal, enum PortalFlags flags) { @@ -337,6 +342,19 @@ void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct R gDPSetRenderMode(renderState->dl++, G_RM_ZB_OPA_SURF, G_RM_ZB_OPA_SURF2); } +void portalRenderCover(struct Portal* portal, float portalTransform[4][4], struct RenderState* renderState) { + Mtx* matrix = renderStateRequestMatrices(renderState, 1); + + guMtxF2L(portalTransform, matrix); + gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL); + if (portal->flags & PortalFlagsOddParity) { + gSPDisplayList(renderState->dl++, portal_portal_blue_filled_model_gfx); + } else { + gSPDisplayList(renderState->dl++, portal_portal_orange_filled_model_gfx); + } + gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW); +} + void portalRender(struct Portal* portal, struct Portal* otherPortal, struct RenderProps* props, SceneRenderCallback sceneRenderer, void* data, struct RenderState* renderState) { struct Vector3 forward = gForward; if (!(portal->flags & PortalFlagsOddParity)) { @@ -370,16 +388,7 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend transformToMatrix(&finalTransform, portalTransform, SCENE_SCALE); if (props->currentDepth == 0 || !otherPortal) { - Mtx* matrix = renderStateRequestMatrices(renderState, 1); - - guMtxF2L(portalTransform, matrix); - gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL); - if (portal->flags & PortalFlagsOddParity) { - gSPDisplayList(renderState->dl++, portal_portal_blue_filled_model_gfx); - } else { - gSPDisplayList(renderState->dl++, portal_portal_orange_filled_model_gfx); - } - gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW); + portalRenderCover(portal, portalTransform, renderState); return; } @@ -408,7 +417,11 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend } if (nextProps.minX < nextProps.maxX && nextProps.minY < nextProps.maxY) { - renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState); + if (!renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState)) { + portalRenderCover(portal, portalTransform, renderState); + return; + } + sceneRenderer(data, &nextProps, renderState); // revert to previous state diff --git a/src/scene/portal.h b/src/scene/portal.h index e63ff81..46bcf08 100644 --- a/src/scene/portal.h +++ b/src/scene/portal.h @@ -56,7 +56,7 @@ struct RenderProps { }; void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex); -void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState); +int renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState); void portalInit(struct Portal* portal, enum PortalFlags flags); void portalUpdate(struct Portal* portal, int isOpen); diff --git a/src/scene/scene.c b/src/scene/scene.c index 3cffab1..e6d64aa 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -95,6 +95,12 @@ void sceneInit(struct Scene* scene) { for (int i = 0; i < scene->elevatorCount; ++i) { elevatorInit(&scene->elevators[i], &gCurrentLevel->elevators[i]); } + + scene->pedestalCount = gCurrentLevel->pedestalCount; + scene->pedestals = malloc(sizeof(struct Pedestal) * scene->pedestalCount); + for (int i = 0; i < scene->pedestalCount; ++i) { + pedestalInit(&scene->pedestals[i], &gCurrentLevel->pedestals[i]); + } } void sceneRenderWithProperties(void* data, struct RenderProps* properties, struct RenderState* renderState) { @@ -103,7 +109,7 @@ void sceneRenderWithProperties(void* data, struct RenderProps* properties, struc u64 visibleRooms = 0; staticRenderDetermineVisibleRooms(&properties->cullingInfo, properties->fromRoom, &visibleRooms); - int closerPortal = vector3DistSqrd(&properties->camera.transform.position, &scene->portals[0].transform.position) > vector3DistSqrd(&properties->camera.transform.position, &scene->portals[1].transform.position) ? 0 : 1; + int closerPortal = vector3DistSqrd(&properties->camera.transform.position, &scene->portals[0].transform.position) < vector3DistSqrd(&properties->camera.transform.position, &scene->portals[1].transform.position) ? 0 : 1; int otherPortal = 1 - closerPortal; for (int i = 0; i < 2; ++i) { diff --git a/src/scene/scene.h b/src/scene/scene.h index 39ab053..dc65ecf 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -13,6 +13,7 @@ #include "./door.h" #include "./fizzler.h" #include "elevator.h" +#include "pedestal.h" struct Scene { struct Camera camera; @@ -23,6 +24,7 @@ struct Scene { struct Door* doors; struct Fizzler* fizzlers; struct Elevator* elevators; + struct Pedestal* pedestals; OSTime cpuTime; OSTime lastFrameStart; OSTime lastFrameTime; @@ -31,6 +33,7 @@ struct Scene { u8 doorCount; u8 fizzlerCount; u8 elevatorCount; + u8 pedestalCount; }; extern struct Scene gScene; diff --git a/src/sk64/skelatool_armature.c b/src/sk64/skelatool_armature.c index b31ac34..764e137 100644 --- a/src/sk64/skelatool_armature.c +++ b/src/sk64/skelatool_armature.c @@ -7,9 +7,16 @@ void skArmatureInit(struct SKArmature* object, Gfx* displayList, u32 numberOfBones, struct Transform* initialPose, unsigned short* boneParentIndex) { object->displayList = displayList; object->numberOfBones = numberOfBones; - object->boneTransforms = malloc(sizeof(Mtx) * numberOfBones); + + unsigned transformSize = sizeof(Mtx) * numberOfBones; + + object->boneTransforms = malloc(transformSize); if (initialPose) { - romCopy((void*)initialPose, (void*)object->boneTransforms, sizeof(Mtx) * numberOfBones); + if (IS_KSEG0(initialPose)) { + memCopy(object->boneTransforms, initialPose, transformSize); + } else { + romCopy((void*)initialPose, (void*)object->boneTransforms, transformSize); + } } object->boneParentIndex = boneParentIndex; } diff --git a/tools/generate_animation_ld.js b/tools/generate_animation_ld.js new file mode 100644 index 0000000..571067a --- /dev/null +++ b/tools/generate_animation_ld.js @@ -0,0 +1,24 @@ +const fs = require('fs'); +const path = require('path'); + +function generateLD(objectLocation) { + return ` + ${objectLocation}(.data); + ${objectLocation}(.bss); + `; +} + +function generateData(objectLocations) { + + return ` + BEGIN_SEG(animation_segment, 0x0D000000) + { + ${objectLocations.map(objectLocation => generateLD(objectLocation)).join('\n')} + } + END_SEG(animation_segment) + `; +} + +const output = process.argv[2]; + +fs.writeFileSync(output, generateData(process.argv.slice(3))); \ No newline at end of file