Path: blob/master/RSDKv5/RSDK/Scene/Object.cpp
1163 views
#include "RSDK/Core/RetroEngine.hpp"12using namespace RSDK;34#if RETRO_REV0U5#include "Legacy/ObjectLegacy.cpp"6#endif78ObjectClass RSDK::objectClassList[OBJECT_COUNT];9int32 RSDK::objectClassCount = 0;1011int32 RSDK::globalObjectCount = 0;12int32 RSDK::globalObjectIDs[OBJECT_COUNT];13int32 RSDK::stageObjectIDs[OBJECT_COUNT];1415EntityBase RSDK::objectEntityList[ENTITY_COUNT];1617EditableVarInfo *RSDK::editableVarList;18int32 RSDK::editableVarCount = 0;1920TypeGroupList RSDK::typeGroups[TYPEGROUP_COUNT];2122bool32 RSDK::validDraw = false;2324ForeachStackInfo RSDK::foreachStackList[FOREACH_STACK_COUNT];25ForeachStackInfo *RSDK::foreachStackPtr = NULL;2627#if RETRO_REV0U28#if RETRO_USE_MOD_LOADER29void RSDK::RegisterObject(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, void (*update)(),30void (*lateUpdate)(), void (*staticUpdate)(), void (*draw)(), void (*create)(void *), void (*stageLoad)(),31void (*editorLoad)(), void (*editorDraw)(), void (*serialize)(), void (*staticLoad)(Object *))32{33return RegisterObject_STD(staticVars, name, entityClassSize, staticClassSize, update, lateUpdate, staticUpdate, draw, create, stageLoad,34editorLoad, editorDraw, serialize, staticLoad);35}3637void RSDK::RegisterObject_STD(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, std::function<void()> update,38std::function<void()> lateUpdate, std::function<void()> staticUpdate, std::function<void()> draw,39std::function<void(void *)> create, std::function<void()> stageLoad, std::function<void()> editorLoad,40std::function<void()> editorDraw, std::function<void()> serialize, std::function<void(Object *)> staticLoad)41#else42void RSDK::RegisterObject(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, void (*update)(),43void (*lateUpdate)(), void (*staticUpdate)(), void (*draw)(), void (*create)(void *), void (*stageLoad)(),44void (*editorLoad)(), void (*editorDraw)(), void (*serialize)(), void (*staticLoad)(Object *))45#endif46#else47#if RETRO_USE_MOD_LOADER48void RSDK::RegisterObject(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, void (*update)(),49void (*lateUpdate)(), void (*staticUpdate)(), void (*draw)(), void (*create)(void *), void (*stageLoad)(),50void (*editorLoad)(), void (*editorDraw)(), void (*serialize)())51{52return RegisterObject_STD(staticVars, name, entityClassSize, staticClassSize, update, lateUpdate, staticUpdate, draw, create, stageLoad,53editorLoad, editorDraw, serialize);54}5556void RSDK::RegisterObject_STD(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, std::function<void()> update,57std::function<void()> lateUpdate, std::function<void()> staticUpdate, std::function<void()> draw,58std::function<void(void *)> create, std::function<void()> stageLoad, std::function<void()> editorLoad,59std::function<void()> editorDraw, std::function<void()> serialize)60#else61void RSDK::RegisterObject(Object **staticVars, const char *name, uint32 entityClassSize, uint32 staticClassSize, void (*update)(),62void (*lateUpdate)(), void (*staticUpdate)(), void (*draw)(), void (*create)(void *), void (*stageLoad)(),63void (*editorLoad)(), void (*editorDraw)(), void (*serialize)())64#endif65#endif66{67if (objectClassCount < OBJECT_COUNT) {68if (entityClassSize > sizeof(EntityBase))69PrintLog(PRINT_NORMAL, "Class exceeds max entity memory: %s", name);7071ObjectClass *classInfo = &objectClassList[objectClassCount];72GEN_HASH_MD5(name, classInfo->hash);73classInfo->staticVars = staticVars;74classInfo->entityClassSize = entityClassSize;75classInfo->staticClassSize = staticClassSize;76classInfo->update = update;77classInfo->lateUpdate = lateUpdate;78classInfo->staticUpdate = staticUpdate;79classInfo->draw = draw;80classInfo->create = create;81classInfo->stageLoad = stageLoad;82classInfo->editorLoad = editorLoad;83classInfo->editorDraw = editorDraw;84classInfo->serialize = serialize;85#if RETRO_REV0U86classInfo->staticLoad = staticLoad;87#endif8889#if !RETRO_USE_ORIGINAL_CODE90classInfo->name = name;91#endif9293++objectClassCount;94}95}9697#if RETRO_REV02 || RETRO_USE_MOD_LOADER98void RSDK::RegisterStaticVariables(void **staticVars, const char *name, uint32 classSize)99{100RETRO_HASH_MD5(hash);101GEN_HASH_MD5(name, hash);102AllocateStorage((void **)staticVars, classSize, DATASET_STG, true);103LoadStaticVariables((uint8 *)*staticVars, hash, 0);104}105#endif106107#define ALIGN_TO(type) \108aligned = dataPos & -(int32)sizeof(type); \109if (aligned < dataPos) \110dataPos = aligned + sizeof(type);111112void RSDK::LoadStaticVariables(uint8 *classPtr, uint32 *hash, int32 readOffset)113{114char fullFilePath[0x40];115116const char *hexChars = "0123456789ABCDEF";117char classHash[] = "00000000000000000000000000000000";118119int32 strPos = 0;120for (int32 i = 0; i < 32; i += 4) classHash[strPos++] = hexChars[(hash[0] >> i) & 0xF];121for (int32 i = 0; i < 32; i += 4) classHash[strPos++] = hexChars[(hash[1] >> i) & 0xF];122for (int32 i = 0; i < 32; i += 4) classHash[strPos++] = hexChars[(hash[2] >> i) & 0xF];123for (int32 i = 0; i < 32; i += 4) classHash[strPos++] = hexChars[(hash[3] >> i) & 0xF];124125sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Objects/Static/%s.bin", classHash);126127FileInfo info;128InitFileInfo(&info);129if (LoadFile(&info, fullFilePath, FMODE_RB)) {130uint32 sig = ReadInt32(&info, false);131132if (sig != RSDK_SIGNATURE_OBJ) {133CloseFile(&info);134return;135}136137int32 dataPos = readOffset;138while (info.readPos < info.fileSize) {139int32 type = ReadInt8(&info);140int32 arraySize = ReadInt32(&info, false);141142bool32 hasValues = (type & 0x80) != 0;143type &= 0x7F;144145int32 aligned = 0;146if (hasValues) {147uint32 count = ReadInt32(&info, false);148149switch (type) {150default:151#if !RETRO_USE_ORIGINAL_CODE152PrintLog(PRINT_NORMAL, "Invalid static variable type: %d", type);153#endif154break;155156case SVAR_UINT8:157case SVAR_INT8:158if (info.readPos + (count * sizeof(uint8)) <= info.fileSize && &classPtr[dataPos]) {159for (int32 i = 0; i < count * sizeof(uint8); i += sizeof(uint8)) ReadBytes(&info, &classPtr[dataPos + i], sizeof(uint8));160}161else {162info.readPos += count * sizeof(uint8);163}164165dataPos += count * sizeof(uint8);166break;167168case SVAR_UINT16:169case SVAR_INT16: {170ALIGN_TO(int16);171172if (info.readPos + (count * sizeof(int16)) <= info.fileSize && &classPtr[dataPos]) {173for (int32 i = 0; i < count * sizeof(int16); i += sizeof(int16)) {174#if !RETRO_USE_ORIGINAL_CODE175*(int16 *)&classPtr[dataPos + i] = ReadInt16(&info);176#else177// This only works as intended on little-endian CPUs.178ReadBytes(&info, &classPtr[dataPos + i], sizeof(int16));179#endif180}181}182else {183info.readPos += count * sizeof(int16);184}185186dataPos += sizeof(int16) * count;187break;188}189190case SVAR_UINT32:191case SVAR_INT32: {192ALIGN_TO(int32);193194if (info.readPos + (count * sizeof(int32)) <= info.fileSize && &classPtr[dataPos]) {195for (int32 i = 0; i < count * sizeof(int32); i += sizeof(int32)) {196#if !RETRO_USE_ORIGINAL_CODE197*(int32 *)&classPtr[dataPos + i] = ReadInt32(&info, false);198#else199// This only works as intended on little-endian CPUs.200ReadBytes(&info, &classPtr[dataPos + i], sizeof(int32));201#endif202}203}204else {205info.readPos += count * sizeof(int32);206}207208dataPos += sizeof(int32) * count;209break;210}211212case SVAR_BOOL: {213ALIGN_TO(bool32);214215if (info.readPos + (count * sizeof(bool32)) <= info.fileSize && &classPtr[dataPos]) {216for (int32 i = 0; i < count * sizeof(bool32); i += sizeof(bool32)) {217#if !RETRO_USE_ORIGINAL_CODE218*(bool32 *)&classPtr[dataPos + i] = (bool32)ReadInt32(&info, false);219#else220// This only works as intended on little-endian CPUs.221ReadBytes(&info, &classPtr[dataPos + i], sizeof(bool32));222#endif223}224}225else {226info.readPos += count * sizeof(bool32);227}228229dataPos += sizeof(bool32) * count;230break;231}232}233}234else {235switch (type) {236case SVAR_UINT8:237case SVAR_INT8: dataPos += sizeof(uint8) * arraySize; break;238239case SVAR_UINT16:240case SVAR_INT16:241ALIGN_TO(int16);242243dataPos += sizeof(int16) * arraySize;244break;245246case SVAR_UINT32:247case SVAR_INT32:248ALIGN_TO(int32);249250dataPos += sizeof(int32) * arraySize;251break;252253case SVAR_BOOL:254ALIGN_TO(bool32);255256dataPos += sizeof(bool32) * arraySize;257break;258259case SVAR_POINTER:260ALIGN_TO(void *);261262dataPos += sizeof(void *) * arraySize;263break;264265case SVAR_VECTOR2:266ALIGN_TO(int32);267268dataPos += sizeof(Vector2) * arraySize;269break;270271case SVAR_STRING:272ALIGN_TO(void *);273274dataPos += sizeof(String) * arraySize;275break;276277case SVAR_ANIMATOR:278ALIGN_TO(void *);279280dataPos += sizeof(Animator) * arraySize;281break;282283case SVAR_HITBOX:284ALIGN_TO(int16);285286dataPos += sizeof(Hitbox) * arraySize;287break;288289case SVAR_SPRITEFRAME:290ALIGN_TO(int16);291292dataPos += sizeof(GameSpriteFrame) * arraySize;293break;294295default:296#if !RETRO_USE_ORIGINAL_CODE297PrintLog(PRINT_NORMAL, "Invalid data type: %d", type);298#endif299break;300}301}302}303304CloseFile(&info);305}306}307308void RSDK::InitObjects()309{310sceneInfo.entitySlot = 0;311sceneInfo.createSlot = ENTITY_COUNT - 0x100;312cameraCount = 0;313314for (int32 o = 0; o < sceneInfo.classCount; ++o) {315#if RETRO_USE_MOD_LOADER316currentObjectID = o;317#endif318319if (objectClassList[stageObjectIDs[o]].stageLoad)320objectClassList[stageObjectIDs[o]].stageLoad();321}322323#if RETRO_USE_MOD_LOADER324RunModCallbacks(MODCB_ONSTAGELOAD, NULL);325#endif326327for (int32 e = 0; e < ENTITY_COUNT; ++e) {328sceneInfo.entitySlot = e;329sceneInfo.entity = &objectEntityList[e];330331if (sceneInfo.entity->classID) {332if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].create) {333sceneInfo.entity->interaction = true;334objectClassList[stageObjectIDs[sceneInfo.entity->classID]].create(NULL);335}336}337}338339sceneInfo.state = ENGINESTATE_REGULAR;340341if (!cameraCount)342AddCamera(&screens[0].position, TO_FIXED(screens[0].center.x), TO_FIXED(screens[0].center.y), false);343}344void RSDK::ProcessObjects()345{346for (int32 i = 0; i < DRAWGROUP_COUNT; ++i) drawGroups[i].entityCount = 0;347348for (int32 o = 0; o < sceneInfo.classCount; ++o) {349#if RETRO_USE_MOD_LOADER350currentObjectID = o;351#endif352353ObjectClass *classInfo = &objectClassList[stageObjectIDs[o]];354if ((*classInfo->staticVars)->active == ACTIVE_ALWAYS || (*classInfo->staticVars)->active == ACTIVE_NORMAL) {355if (classInfo->staticUpdate)356classInfo->staticUpdate();357}358}359360#if RETRO_USE_MOD_LOADER361RunModCallbacks(MODCB_ONSTATICUPDATE, INT_TO_VOID(ENGINESTATE_REGULAR));362#endif363364for (int32 s = 0; s < cameraCount; ++s) {365CameraInfo *camera = &cameras[s];366367if (camera->targetPos) {368if (camera->worldRelative) {369camera->position.x = camera->targetPos->x;370camera->position.y = camera->targetPos->y;371}372else {373camera->position.x = TO_FIXED(camera->targetPos->x);374camera->position.y = TO_FIXED(camera->targetPos->y);375}376}377}378379sceneInfo.entitySlot = 0;380for (int32 e = 0; e < ENTITY_COUNT; ++e) {381sceneInfo.entity = &objectEntityList[e];382if (sceneInfo.entity->classID) {383switch (sceneInfo.entity->active) {384default:385case ACTIVE_DISABLED: break;386387case ACTIVE_NEVER:388case ACTIVE_PAUSED: sceneInfo.entity->inRange = false; break;389390case ACTIVE_ALWAYS:391case ACTIVE_NORMAL: sceneInfo.entity->inRange = true; break;392393case ACTIVE_BOUNDS:394sceneInfo.entity->inRange = false;395396for (int32 s = 0; s < cameraCount; ++s) {397int32 sx = abs(sceneInfo.entity->position.x - cameras[s].position.x);398int32 sy = abs(sceneInfo.entity->position.y - cameras[s].position.y);399400if (sx <= sceneInfo.entity->updateRange.x + cameras[s].offset.x401&& sy <= sceneInfo.entity->updateRange.y + cameras[s].offset.y) {402sceneInfo.entity->inRange = true;403break;404}405}406break;407408case ACTIVE_XBOUNDS:409sceneInfo.entity->inRange = false;410411for (int32 s = 0; s < cameraCount; ++s) {412int32 sx = abs(sceneInfo.entity->position.x - cameras[s].position.x);413414if (sx <= sceneInfo.entity->updateRange.x + cameras[s].offset.x) {415sceneInfo.entity->inRange = true;416break;417}418}419break;420421case ACTIVE_YBOUNDS:422sceneInfo.entity->inRange = false;423424for (int32 s = 0; s < cameraCount; ++s) {425int32 sy = abs(sceneInfo.entity->position.y - cameras[s].position.y);426427if (sy <= sceneInfo.entity->updateRange.y + cameras[s].offset.y) {428sceneInfo.entity->inRange = true;429break;430}431}432break;433434case ACTIVE_RBOUNDS:435sceneInfo.entity->inRange = false;436437for (int32 s = 0; s < cameraCount; ++s) {438int32 sx = FROM_FIXED(abs(sceneInfo.entity->position.x - cameras[s].position.x));439int32 sy = FROM_FIXED(abs(sceneInfo.entity->position.y - cameras[s].position.y));440441if (sx * sx + sy * sy <= sceneInfo.entity->updateRange.x + cameras[s].offset.x) {442sceneInfo.entity->inRange = true;443break;444}445}446break;447}448449if (sceneInfo.entity->inRange) {450if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update)451objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update();452453if (sceneInfo.entity->drawGroup < DRAWGROUP_COUNT)454drawGroups[sceneInfo.entity->drawGroup].entries[drawGroups[sceneInfo.entity->drawGroup].entityCount++] = sceneInfo.entitySlot;455}456}457else {458sceneInfo.entity->inRange = false;459}460461sceneInfo.entitySlot++;462}463464#if RETRO_USE_MOD_LOADER465RunModCallbacks(MODCB_ONUPDATE, INT_TO_VOID(ENGINESTATE_REGULAR));466#endif467468for (int32 i = 0; i < TYPEGROUP_COUNT; ++i) typeGroups[i].entryCount = 0;469470sceneInfo.entitySlot = 0;471for (int32 e = 0; e < ENTITY_COUNT; ++e) {472sceneInfo.entity = &objectEntityList[e];473474if (sceneInfo.entity->inRange && sceneInfo.entity->interaction) {475typeGroups[GROUP_ALL].entries[typeGroups[GROUP_ALL].entryCount++] = e; // All active objects476477typeGroups[sceneInfo.entity->classID].entries[typeGroups[sceneInfo.entity->classID].entryCount++] = e; // class-based groups478479if (sceneInfo.entity->group >= TYPE_COUNT)480typeGroups[sceneInfo.entity->group].entries[typeGroups[sceneInfo.entity->group].entryCount++] = e; // extra groups481}482483sceneInfo.entitySlot++;484}485486sceneInfo.entitySlot = 0;487for (int32 e = 0; e < ENTITY_COUNT; ++e) {488sceneInfo.entity = &objectEntityList[e];489490if (sceneInfo.entity->inRange) {491if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate)492objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate();493}494495sceneInfo.entity->onScreen = 0;496sceneInfo.entitySlot++;497}498499#if RETRO_USE_MOD_LOADER500RunModCallbacks(MODCB_ONLATEUPDATE, INT_TO_VOID(ENGINESTATE_REGULAR));501#endif502}503void RSDK::ProcessPausedObjects()504{505for (int32 i = 0; i < DRAWGROUP_COUNT; ++i) drawGroups[i].entityCount = 0;506507for (int32 o = 0; o < sceneInfo.classCount; ++o) {508#if RETRO_USE_MOD_LOADER509currentObjectID = o;510#endif511512ObjectClass *classInfo = &objectClassList[stageObjectIDs[o]];513if ((*classInfo->staticVars)->active == ACTIVE_ALWAYS || (*classInfo->staticVars)->active == ACTIVE_PAUSED) {514if (classInfo->staticUpdate)515classInfo->staticUpdate();516}517}518519#if RETRO_USE_MOD_LOADER520RunModCallbacks(MODCB_ONSTATICUPDATE, INT_TO_VOID(ENGINESTATE_PAUSED));521#endif522523sceneInfo.entitySlot = 0;524for (int32 e = 0; e < ENTITY_COUNT; ++e) {525sceneInfo.entity = &objectEntityList[e];526527if (sceneInfo.entity->classID) {528if (sceneInfo.entity->active == ACTIVE_ALWAYS || sceneInfo.entity->active == ACTIVE_PAUSED) {529if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update)530objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update();531532if (sceneInfo.entity->drawGroup < DRAWGROUP_COUNT)533drawGroups[sceneInfo.entity->drawGroup].entries[drawGroups[sceneInfo.entity->drawGroup].entityCount++] = sceneInfo.entitySlot;534}535}536else {537sceneInfo.entity->inRange = false;538}539540sceneInfo.entitySlot++;541}542543#if RETRO_USE_MOD_LOADER544RunModCallbacks(MODCB_ONUPDATE, INT_TO_VOID(ENGINESTATE_PAUSED));545#endif546547sceneInfo.entitySlot = 0;548for (int32 e = 0; e < ENTITY_COUNT; ++e) {549sceneInfo.entity = &objectEntityList[e];550551if (sceneInfo.entity->active == ACTIVE_ALWAYS || sceneInfo.entity->active == ACTIVE_PAUSED) {552if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate)553objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate();554}555556sceneInfo.entity->onScreen = 0;557sceneInfo.entitySlot++;558}559560#if RETRO_USE_MOD_LOADER561RunModCallbacks(MODCB_ONLATEUPDATE, INT_TO_VOID(ENGINESTATE_PAUSED));562#endif563}564void RSDK::ProcessFrozenObjects()565{566for (int32 i = 0; i < DRAWGROUP_COUNT; ++i) drawGroups[i].entityCount = 0;567568for (int32 o = 0; o < sceneInfo.classCount; ++o) {569#if RETRO_USE_MOD_LOADER570currentObjectID = o;571#endif572573ObjectClass *classInfo = &objectClassList[stageObjectIDs[o]];574if ((*classInfo->staticVars)->active == ACTIVE_ALWAYS || (*classInfo->staticVars)->active == ACTIVE_PAUSED) {575if (classInfo->staticUpdate)576classInfo->staticUpdate();577}578}579580#if RETRO_USE_MOD_LOADER581RunModCallbacks(MODCB_ONSTATICUPDATE, INT_TO_VOID(ENGINESTATE_FROZEN));582#endif583584for (int32 s = 0; s < cameraCount; ++s) {585CameraInfo *camera = &cameras[s];586587if (camera->targetPos) {588if (camera->worldRelative) {589camera->position.x = camera->targetPos->x;590camera->position.y = camera->targetPos->y;591}592else {593camera->position.x = TO_FIXED(camera->targetPos->x);594camera->position.y = TO_FIXED(camera->targetPos->y);595}596}597}598599sceneInfo.entitySlot = 0;600for (int32 e = 0; e < ENTITY_COUNT; ++e) {601sceneInfo.entity = &objectEntityList[e];602603if (sceneInfo.entity->classID) {604switch (sceneInfo.entity->active) {605default:606case ACTIVE_DISABLED: break;607608case ACTIVE_NEVER:609case ACTIVE_PAUSED: sceneInfo.entity->inRange = false; break;610611case ACTIVE_ALWAYS:612case ACTIVE_NORMAL: sceneInfo.entity->inRange = true; break;613614case ACTIVE_BOUNDS:615sceneInfo.entity->inRange = false;616617for (int32 s = 0; s < cameraCount; ++s) {618int32 sx = abs(sceneInfo.entity->position.x - cameras[s].position.x);619int32 sy = abs(sceneInfo.entity->position.y - cameras[s].position.y);620621if (sx <= sceneInfo.entity->updateRange.x + cameras[s].offset.x622&& sy <= sceneInfo.entity->updateRange.y + cameras[s].offset.y) {623sceneInfo.entity->inRange = true;624break;625}626}627break;628629case ACTIVE_XBOUNDS:630sceneInfo.entity->inRange = false;631632for (int32 s = 0; s < cameraCount; ++s) {633int32 sx = abs(sceneInfo.entity->position.x - cameras[s].position.x);634635if (sx <= sceneInfo.entity->updateRange.x + cameras[s].offset.x) {636sceneInfo.entity->inRange = true;637break;638}639}640break;641642case ACTIVE_YBOUNDS:643sceneInfo.entity->inRange = false;644645for (int32 s = 0; s < cameraCount; ++s) {646int32 sy = abs(sceneInfo.entity->position.y - cameras[s].position.y);647648if (sy <= sceneInfo.entity->updateRange.y + cameras[s].offset.y) {649sceneInfo.entity->inRange = true;650break;651}652}653break;654655case ACTIVE_RBOUNDS:656sceneInfo.entity->inRange = false;657658for (int32 s = 0; s < cameraCount; ++s) {659int32 sx = FROM_FIXED(abs(sceneInfo.entity->position.x - cameras[s].position.x));660int32 sy = FROM_FIXED(abs(sceneInfo.entity->position.y - cameras[s].position.y));661662if (sx * sx + sy * sy <= sceneInfo.entity->updateRange.x + cameras[s].offset.x) {663sceneInfo.entity->inRange = true;664break;665}666}667break;668}669670if (sceneInfo.entity->inRange) {671if (sceneInfo.entity->active == ACTIVE_ALWAYS || sceneInfo.entity->active == ACTIVE_PAUSED) {672if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update)673objectClassList[stageObjectIDs[sceneInfo.entity->classID]].update();674}675676if (sceneInfo.entity->drawGroup < DRAWGROUP_COUNT)677drawGroups[sceneInfo.entity->drawGroup].entries[drawGroups[sceneInfo.entity->drawGroup].entityCount++] = sceneInfo.entitySlot;678}679}680else {681sceneInfo.entity->inRange = false;682}683684sceneInfo.entitySlot++;685}686687#if RETRO_USE_MOD_LOADER688RunModCallbacks(MODCB_ONUPDATE, INT_TO_VOID(ENGINESTATE_FROZEN));689#endif690691for (int32 i = 0; i < TYPEGROUP_COUNT; ++i) typeGroups[i].entryCount = 0;692693sceneInfo.entitySlot = 0;694for (int32 e = 0; e < ENTITY_COUNT; ++e) {695sceneInfo.entity = &objectEntityList[e];696697if (sceneInfo.entity->inRange) {698if (sceneInfo.entity->active == ACTIVE_ALWAYS || sceneInfo.entity->active == ACTIVE_PAUSED) {699if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate)700objectClassList[stageObjectIDs[sceneInfo.entity->classID]].lateUpdate();701}702703if (sceneInfo.entity->interaction) {704typeGroups[GROUP_ALL].entries[typeGroups[GROUP_ALL].entryCount++] = e; // All active entities705706typeGroups[sceneInfo.entity->classID].entries[typeGroups[sceneInfo.entity->classID].entryCount++] = e; // type-based groups707708if (sceneInfo.entity->group >= TYPE_COUNT)709typeGroups[sceneInfo.entity->group].entries[typeGroups[sceneInfo.entity->group].entryCount++] = e; // extra groups710}711}712713sceneInfo.entity->onScreen = 0;714sceneInfo.entitySlot++;715}716717#if RETRO_USE_MOD_LOADER718RunModCallbacks(MODCB_ONLATEUPDATE, INT_TO_VOID(ENGINESTATE_FROZEN));719#endif720}721void RSDK::ProcessObjectDrawLists()722{723if (sceneInfo.state != ENGINESTATE_LOAD && sceneInfo.state != (ENGINESTATE_LOAD | ENGINESTATE_STEPOVER)) {724for (int32 s = 0; s < videoSettings.screenCount; ++s) {725currentScreen = &screens[s];726sceneInfo.currentScreenID = s;727728for (int32 l = 0; l < DRAWGROUP_COUNT; ++l) drawGroups[l].layerCount = 0;729730for (int32 t = 0; t < LAYER_COUNT; ++t) {731uint8 drawGroup = tileLayers[t].drawGroup[s];732733if (drawGroup < DRAWGROUP_COUNT)734drawGroups[drawGroup].layerDrawList[drawGroups[drawGroup].layerCount++] = t;735}736737sceneInfo.currentDrawGroup = 0;738for (int32 l = 0; l < DRAWGROUP_COUNT; ++l) {739if (engine.drawGroupVisible[l]) {740DrawList *list = &drawGroups[l];741742if (list->hookCB)743list->hookCB();744745if (list->sorted) {746for (int32 e = 0; e < list->entityCount; ++e) {747for (int32 i = list->entityCount - 1; i > e; --i) {748int32 slot1 = list->entries[i - 1];749int32 slot2 = list->entries[i];750if (objectEntityList[slot2].zdepth > objectEntityList[slot1].zdepth) {751list->entries[i - 1] = slot2;752list->entries[i] = slot1;753}754}755}756}757758for (int32 i = 0; i < list->entityCount; ++i) {759sceneInfo.entitySlot = list->entries[i];760validDraw = false;761sceneInfo.entity = &objectEntityList[list->entries[i]];762if (sceneInfo.entity->visible) {763if (objectClassList[stageObjectIDs[sceneInfo.entity->classID]].draw)764objectClassList[stageObjectIDs[sceneInfo.entity->classID]].draw();765766#if RETRO_VER_EGS || RETRO_USE_DUMMY_ACHIEVEMENTS767if (i == list->entityCount - 1)768SKU::DrawAchievements();769#endif770771sceneInfo.entity->onScreen |= validDraw << sceneInfo.currentScreenID;772}773}774775for (int32 i = 0; i < list->layerCount; ++i) {776TileLayer *layer = &tileLayers[list->layerDrawList[i]];777778#if RETRO_USE_MOD_LOADER779RunModCallbacks(MODCB_ONSCANLINECB, (void *)layer->scanlineCallback);780#endif781if (layer->scanlineCallback)782layer->scanlineCallback(scanlines);783else784ProcessParallax(layer);785786switch (layer->type) {787case LAYER_HSCROLL: DrawLayerHScroll(layer); break;788case LAYER_VSCROLL: DrawLayerVScroll(layer); break;789case LAYER_ROTOZOOM: DrawLayerRotozoom(layer); break;790case LAYER_BASIC: DrawLayerBasic(layer); break;791default: break;792}793}794795#if RETRO_USE_MOD_LOADER796RunModCallbacks(MODCB_ONDRAW, INT_TO_VOID(l));797#endif798799if (currentScreen->clipBound_X1 > 0)800currentScreen->clipBound_X1 = 0;801802if (currentScreen->clipBound_Y1 > 0)803currentScreen->clipBound_Y1 = 0;804805if (currentScreen->size.x >= 0) {806if (currentScreen->clipBound_X2 < currentScreen->size.x)807currentScreen->clipBound_X2 = currentScreen->size.x;808}809else {810currentScreen->clipBound_X2 = 0;811}812813if (currentScreen->size.y >= 0) {814if (currentScreen->clipBound_Y2 < currentScreen->size.y)815currentScreen->clipBound_Y2 = currentScreen->size.y;816}817else {818currentScreen->clipBound_Y2 = 0;819}820}821822sceneInfo.currentDrawGroup++;823}824825#if !RETRO_USE_ORIGINAL_CODE826if (engine.showUpdateRanges) {827for (int32 l = 0; l < DRAWGROUP_COUNT; ++l) {828if (engine.drawGroupVisible[l]) {829DrawList *list = &drawGroups[l];830for (int32 i = 0; i < list->entityCount; ++i) {831Entity *entity = &objectEntityList[list->entries[i]];832833if (entity->visible || (engine.showUpdateRanges & 2)) {834switch (entity->active) {835default:836case ACTIVE_DISABLED:837case ACTIVE_NEVER: break;838839case ACTIVE_ALWAYS:840case ACTIVE_NORMAL:841case ACTIVE_PAUSED:842DrawRectangle(entity->position.x, entity->position.y, TO_FIXED(1), TO_FIXED(1), 0x0000FF, 0xFF, INK_NONE,843false);844break;845846case ACTIVE_BOUNDS:847DrawLine(entity->position.x - entity->updateRange.x, entity->position.y - entity->updateRange.y,848entity->position.x + entity->updateRange.x, entity->position.y - entity->updateRange.y, 0x0000FF,8490xFF, INK_NONE, false);850851DrawLine(entity->position.x - entity->updateRange.x, entity->position.y + entity->updateRange.y,852entity->position.x + entity->updateRange.x, entity->position.y + entity->updateRange.y, 0x0000FF,8530xFF, INK_NONE, false);854855DrawLine(entity->position.x - entity->updateRange.x, entity->position.y - entity->updateRange.y,856entity->position.x - entity->updateRange.x, entity->position.y + entity->updateRange.y, 0x0000FF,8570xFF, INK_NONE, false);858859DrawLine(entity->position.x + entity->updateRange.x, entity->position.y - entity->updateRange.y,860entity->position.x + entity->updateRange.x, entity->position.y + entity->updateRange.y, 0x0000FF,8610xFF, INK_NONE, false);862break;863864case ACTIVE_XBOUNDS:865DrawLine(entity->position.x - entity->updateRange.x, TO_FIXED(currentScreen->position.y),866entity->position.x - entity->updateRange.x,867TO_FIXED(currentScreen->position.y + currentScreen->size.y), 0x0000FF, 0xFF, INK_NONE, false);868869DrawLine(entity->position.x + entity->updateRange.x, TO_FIXED(currentScreen->position.y),870entity->position.x + entity->updateRange.x,871TO_FIXED(currentScreen->position.y + currentScreen->size.y), 0x0000FF, 0xFF, INK_NONE, false);872break;873874case ACTIVE_YBOUNDS:875DrawLine(TO_FIXED(currentScreen->position.x), entity->position.y - entity->updateRange.y,876TO_FIXED(currentScreen->position.x + currentScreen->size.x),877entity->position.y - entity->updateRange.y, 0x0000FF, 0xFF, INK_NONE, false);878879DrawLine(TO_FIXED(currentScreen->position.x), entity->position.y + entity->updateRange.y,880TO_FIXED(currentScreen->position.x + currentScreen->size.x),881entity->position.y + entity->updateRange.y, 0x0000FF, 0xFF, INK_NONE, false);882break;883884case ACTIVE_RBOUNDS:885DrawCircleOutline(entity->position.x, entity->position.y, FROM_FIXED(entity->updateRange.x),886FROM_FIXED(entity->updateRange.x) + 1, 0x0000FF, 0xFF, INK_NONE, false);887break;888}889}890}891}892}893}894895if (engine.showEntityInfo) {896for (int32 l = 0; l < DRAWGROUP_COUNT; ++l) {897if (engine.drawGroupVisible[l]) {898DrawList *list = &drawGroups[l];899for (int32 i = 0; i < list->entityCount; ++i) {900Entity *entity = &objectEntityList[list->entries[i]];901902if (entity->visible || (engine.showEntityInfo & 2)) {903char buffer[0x100];904sprintf_s(buffer, sizeof(buffer), "%s\nx: %g\ny: %g", objectClassList[stageObjectIDs[entity->classID]].name,905entity->position.x / 65536.0f, entity->position.y / 65536.0f);906907DrawDevString(buffer, FROM_FIXED(entity->position.x) - currentScreen->position.x,908FROM_FIXED(entity->position.y) - currentScreen->position.y, ALIGN_LEFT, 0xF0F0F0);909}910}911}912}913}914915if (showHitboxes) {916for (int32 i = 0; i < debugHitboxCount; ++i) {917DebugHitboxInfo *info = &debugHitboxList[i];918int32 x = info->pos.x + TO_FIXED(info->hitbox.left);919int32 y = info->pos.y + TO_FIXED(info->hitbox.top);920int32 w = abs((info->pos.x + TO_FIXED(info->hitbox.right)) - x);921int32 h = abs((info->pos.y + TO_FIXED(info->hitbox.bottom)) - y);922923switch (info->type) {924case H_TYPE_TOUCH: DrawRectangle(x, y, w, h, info->collision ? 0x808000 : 0xFF0000, 0x60, INK_ALPHA, false); break;925926case H_TYPE_CIRCLE:927DrawCircle(info->pos.x, info->pos.y, info->hitbox.left, info->collision ? 0x808000 : 0xFF0000, 0x60, INK_ALPHA, false);928break;929930case H_TYPE_BOX:931DrawRectangle(x, y, w, h, 0x0000FF, 0x60, INK_ALPHA, false);932933if (info->collision & 1) // top934DrawRectangle(x, y, w, TO_FIXED(1), 0xFFFF00, 0xC0, INK_ALPHA, false);935936if (info->collision & 8) // bottom937DrawRectangle(x, y + h, w, TO_FIXED(1), 0xFFFF00, 0xC0, INK_ALPHA, false);938939if (info->collision & 2) { // left940int32 sy = y;941int32 sh = h;942943if (info->collision & 1) {944sy += TO_FIXED(1);945sh -= TO_FIXED(1);946}947948if (info->collision & 8)949sh -= TO_FIXED(1);950951DrawRectangle(x, sy, TO_FIXED(1), sh, 0xFFFF00, 0xC0, INK_ALPHA, false);952}953954if (info->collision & 4) { // right955int32 sy = y;956int32 sh = h;957958if (info->collision & 1) {959sy += TO_FIXED(1);960sh -= TO_FIXED(1);961}962963if (info->collision & 8)964sh -= TO_FIXED(1);965966DrawRectangle(x + w, sy, TO_FIXED(1), sh, 0xFFFF00, 0xC0, INK_ALPHA, false);967}968break;969970case H_TYPE_PLAT:971DrawRectangle(x, y, w, h, 0x00FF00, 0x60, INK_ALPHA, false);972973if (info->collision & 1) // top974DrawRectangle(x, y, w, TO_FIXED(1), 0xFFFF00, 0xC0, INK_ALPHA, false);975976if (info->collision & 8) // bottom977DrawRectangle(x, y + h, w, TO_FIXED(1), 0xFFFF00, 0xC0, INK_ALPHA, false);978break;979}980}981}982983if (engine.showPaletteOverlay) {984for (int32 p = 0; p < PALETTE_BANK_COUNT; ++p) {985int32 x = (videoSettings.pixWidth - (0x10 << 3));986int32 y = (SCREEN_YSIZE - (0x10 << 2));987988for (int32 c = 0; c < PALETTE_BANK_SIZE; ++c) {989uint32 clr = GetPaletteEntry(p, c);990991DrawRectangle(x + ((c & 0xF) << 1) + ((p % (PALETTE_BANK_COUNT / 2)) * (2 * 16)),992y + ((c >> 4) << 1) + ((p / (PALETTE_BANK_COUNT / 2)) * (2 * 16)), 2, 2, clr, 0xFF, INK_NONE, true);993}994}995}996997#endif998999currentScreen++;1000sceneInfo.currentScreenID++;1001}1002}1003}10041005uint16 RSDK::FindObject(const char *name)1006{1007RETRO_HASH_MD5(hash);1008GEN_HASH_MD5(name, hash);10091010for (int32 o = 0; o < sceneInfo.classCount; ++o) {1011if (HASH_MATCH_MD5(hash, objectClassList[stageObjectIDs[o]].hash))1012return o;1013}10141015return TYPE_DEFAULTOBJECT;1016}10171018int32 RSDK::GetEntityCount(uint16 classID, bool32 isActive)1019{1020if (classID >= TYPE_COUNT)1021return 0;1022if (isActive)1023return typeGroups[classID].entryCount;10241025int32 entityCount = 0;1026for (int32 i = 0; i < ENTITY_COUNT; ++i) {1027if (objectEntityList[i].classID == classID)1028entityCount++;1029}10301031return entityCount;1032}10331034void RSDK::ResetEntity(Entity *entity, uint16 classID, void *data)1035{1036if (entity) {1037ObjectClass *info = &objectClassList[stageObjectIDs[classID]];1038memset(entity, 0, info->entityClassSize);10391040if (info->create) {1041Entity *curEnt = sceneInfo.entity;10421043sceneInfo.entity = entity;1044sceneInfo.entity->interaction = true;1045#if RETRO_USE_MOD_LOADER1046int32 superStore = superLevels[inheritLevel];1047superLevels[inheritLevel] = 0;1048#endif1049info->create(data);1050#if RETRO_USE_MOD_LOADER1051superLevels[inheritLevel] = superStore;1052#endif1053sceneInfo.entity->classID = classID;10541055sceneInfo.entity = curEnt;1056}10571058entity->classID = classID;1059}1060}10611062void RSDK::ResetEntitySlot(uint16 slot, uint16 classID, void *data)1063{1064ObjectClass *object = &objectClassList[stageObjectIDs[classID]];1065slot = slot < ENTITY_COUNT ? slot : (ENTITY_COUNT - 1);10661067Entity *entity = &objectEntityList[slot];1068memset(&objectEntityList[slot], 0, object->entityClassSize);10691070if (object->create) {1071Entity *curEnt = sceneInfo.entity;10721073sceneInfo.entity = entity;1074entity->interaction = true;1075#if RETRO_USE_MOD_LOADER1076int32 superStore = superLevels[inheritLevel];1077superLevels[inheritLevel] = 0;1078#endif1079object->create(data);1080#if RETRO_USE_MOD_LOADER1081superLevels[inheritLevel] = superStore;1082#endif1083entity->classID = classID;10841085sceneInfo.entity = curEnt;1086}1087else {1088entity->classID = classID;1089}1090}10911092Entity *RSDK::CreateEntity(uint16 classID, void *data, int32 x, int32 y)1093{1094ObjectClass *object = &objectClassList[stageObjectIDs[classID]];1095Entity *entity = &objectEntityList[sceneInfo.createSlot];10961097int32 permCnt = 0, loopCnt = 0;1098while (entity->classID) {1099// after 16 loops, the game says fuck it and will start overwriting non-temp objects1100if (!entity->isPermanent && loopCnt >= 16)1101break;11021103if (entity->isPermanent)1104++permCnt;11051106sceneInfo.createSlot++;1107if (sceneInfo.createSlot == ENTITY_COUNT) {1108sceneInfo.createSlot = TEMPENTITY_START;1109entity = &objectEntityList[sceneInfo.createSlot];1110}1111else {1112entity = &objectEntityList[sceneInfo.createSlot];1113}11141115if (permCnt >= TEMPENTITY_COUNT)1116break;11171118++loopCnt;1119}11201121memset(entity, 0, object->entityClassSize);1122entity->position.x = x;1123entity->position.y = y;1124entity->interaction = true;11251126if (object->create) {1127Entity *curEnt = sceneInfo.entity;11281129sceneInfo.entity = entity;1130#if RETRO_USE_MOD_LOADER1131int32 superStore = superLevels[inheritLevel];1132superLevels[inheritLevel] = 0;1133#endif1134object->create(data);1135#if RETRO_USE_MOD_LOADER1136superLevels[inheritLevel] = superStore;1137#endif1138entity->classID = classID;11391140sceneInfo.entity = curEnt;1141}1142else {1143entity->classID = classID;1144entity->active = ACTIVE_NORMAL;1145entity->visible = true;1146}11471148return entity;1149}11501151bool32 RSDK::GetActiveEntities(uint16 group, Entity **entity)1152{1153if (group >= TYPEGROUP_COUNT)1154return false;11551156if (!entity)1157return false;11581159if (*entity) {1160++foreachStackPtr->id;1161}1162else {1163foreachStackPtr++;1164foreachStackPtr->id = 0;1165}11661167for (Entity *nextEntity = &objectEntityList[typeGroups[group].entries[foreachStackPtr->id]]; foreachStackPtr->id < typeGroups[group].entryCount;1168++foreachStackPtr->id, nextEntity = &objectEntityList[typeGroups[group].entries[foreachStackPtr->id]]) {1169if (nextEntity->classID == group) {1170*entity = nextEntity;1171return true;1172}1173}11741175foreachStackPtr--;11761177return false;1178}1179bool32 RSDK::GetAllEntities(uint16 classID, Entity **entity)1180{1181if (classID >= OBJECT_COUNT)1182return false;11831184if (!entity)1185return false;11861187if (*entity) {1188++foreachStackPtr->id;1189}1190else {1191foreachStackPtr++;1192foreachStackPtr->id = 0;1193}11941195for (; foreachStackPtr->id < ENTITY_COUNT; ++foreachStackPtr->id) {1196Entity *nextEntity = &objectEntityList[foreachStackPtr->id];1197if (nextEntity->classID == classID) {1198*entity = nextEntity;1199return true;1200}1201}12021203foreachStackPtr--;12041205return false;1206}12071208bool32 RSDK::CheckOnScreen(Entity *entity, Vector2 *range)1209{1210if (!entity)1211return false;12121213if (!range)1214range = &entity->updateRange;12151216return CheckPosOnScreen(&entity->position, range);1217}1218bool32 RSDK::CheckPosOnScreen(Vector2 *position, Vector2 *range)1219{1220if (!position || !range)1221return false;12221223for (int32 s = 0; s < cameraCount; ++s) {1224int32 sx = abs(position->x - cameras[s].position.x);1225int32 sy = abs(position->y - cameras[s].position.y);12261227if (sx <= range->x + cameras[s].offset.x && sy <= range->y + cameras[s].offset.y)1228return true;1229}12301231return false;1232}12331234void RSDK::ClearStageObjects()1235{1236// Unload static object classes1237for (int32 o = 0; o < sceneInfo.classCount; ++o) {1238if (objectClassList[stageObjectIDs[o]].staticVars) {1239*objectClassList[stageObjectIDs[o]].staticVars = NULL;1240}1241}1242}124312441245