150 lines
4.2 KiB
C
150 lines
4.2 KiB
C
/*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|
|
|