/* * Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "object.h" #include "story.h" #include "portme.h" #include "messages.h" #include "memory.h" uint32_t objectPointerGet(uint16_t objectId) { uint32_t ptr; if (objectId == 0) portDie(MSG_INT_OBJECT0_REF); if ((storyVersion() <= 3) && (objectId > 255)) portDie(MSG_INT_OBJECT_BAD_ID); ptr = storyObjectTableAddress(); ptr += 31 * 2; // Skip properties defaults table. ptr += 9 * (objectId - 1); // Find object in table. return ptr; } uint32_t objectPointerParentGet(uint32_t objectPointer) { uint32_t result = 0; uint32_t parent; if (storyVersion() <= 3) { parent = ZPEEK(objectPointer + 4); result = parent ? objectPointerGet(parent) : 0; } else { portDie(MSG_UNIMPLEMENTED); } return result; } uint16_t objectPropertyDefaultGet(uint32_t propertyId) { uint32_t values; if (((storyVersion() <= 3) && (propertyId > 31)) || ((storyVersion() >= 4) && (propertyId > 63))) { //***TODO*** Should we die here? This seems to work. return 0; } values = storyObjectTableAddress() + ((propertyId - 1) * 2); return ZPEEKW(values); } uint32_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) { uint32_t ptr = objectPointerGet(objectId); uint16_t addr; uint8_t info; uint16_t num; uint8_t s; if (storyVersion() <= 3) { ptr += 7; // Skip to properties address field. addr = ZPEEKW(ptr); ptr = addr; ptr += ZPEEK(ptr) * 2 + 1; // Skip object name to start of properties. while (1) { info = ZPEEK(ptr++); num = (info & 0x1f); // 5 bits for property ID. s = ((info >> 5) & 0x7) + 1; // 3 bits for property size. // These go in descending numeric order, and should fail the interpreter if missing. // We use 0xFFFFFFFF internally to mean "first property". if ((num == propertyId) || (propertyId == 0xFFFFFFFF)) { // found it? if (size) *size = s; return ptr; } else if (num < propertyId) // we're past it. break; // Try the next property. ptr += s; } } else { portDie(MSG_UNIMPLEMENTED); } return 0; } uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship) { uint32_t objPtr = objectPointerGet(objectId); uint16_t result = 0; if (storyVersion() <= 3) { result = ZPEEK(objPtr + relationship); } else { portDie(MSG_UNIMPLEMENTED); } return result; } void objectUnparent(uint16_t objectId) { uint32_t objPtr = objectPointerGet(objectId); uint32_t parentPtr = objectPointerParentGet(objPtr); uint32_t ptr; if (parentPtr != 0) { if (storyVersion() <= 3) { ptr = parentPtr + 6; // 4 to skip attrs, 2 to skip to child. #ifdef DEBUGGING printf("Checking %X (%d) for %d\n", (unsigned int)ptr, ZPEEK(ptr), objectId); #endif while (ZPEEK(ptr) != objectId) { // If not direct child, look through sibling list.. ptr = objectPointerGet(ZPEEK(ptr)) + 5; #ifdef DEBUGGING printf("Checking %X (%d) for %d\n", (unsigned int)ptr, ZPEEK(ptr), objectId); #endif } ZPOKE(ptr, ZPEEK(objPtr + 5)); // obj sibling takes obj's place. #ifdef DEBUGGING printf("Setting %X to %d from %X\n", (unsigned int)ptr, ZPEEK(objPtr + 5), objPtr + 5); #endif } else { portDie(MSG_UNIMPLEMENTED); } } }