2014-04-10 18:08:41 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* Copyright (c) 2014 Ted John
|
|
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
|
|
*
|
|
|
|
* This file is part of OpenRCT2.
|
|
|
|
*
|
|
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2014-04-10 18:08:41 +02:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2014-04-10 18:08:41 +02:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2014-05-24 17:48:13 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "addresses.h"
|
2015-06-24 12:41:19 +02:00
|
|
|
#include "config.h"
|
2014-10-06 18:36:58 +02:00
|
|
|
#include "localisation/localisation.h"
|
2014-05-24 17:48:13 +02:00
|
|
|
#include "object.h"
|
2014-10-09 15:03:54 +02:00
|
|
|
#include "platform/platform.h"
|
2015-03-01 15:24:05 +01:00
|
|
|
#include "ride/ride.h"
|
2014-10-06 18:36:58 +02:00
|
|
|
#include "util/sawyercoding.h"
|
2015-02-25 15:06:29 +01:00
|
|
|
#include "drawing/drawing.h"
|
2015-02-26 15:58:13 +01:00
|
|
|
#include "world/footpath.h"
|
2015-03-01 22:06:51 +01:00
|
|
|
#include "world/water.h"
|
|
|
|
#include "world/entrance.h"
|
2015-03-01 22:59:30 +01:00
|
|
|
#include "world/scenery.h"
|
2015-02-26 15:58:13 +01:00
|
|
|
#include "scenario.h"
|
2015-06-25 11:46:17 +02:00
|
|
|
#include "rct1.h"
|
2014-05-24 17:48:13 +02:00
|
|
|
|
2015-09-07 23:05:36 +02:00
|
|
|
char gTempObjectLoadName[9] = { 0 };
|
|
|
|
|
2015-08-29 14:12:52 +02:00
|
|
|
int object_load_entry(const utf8 *path, rct_object_entry *outEntry)
|
2014-12-07 22:45:42 +01:00
|
|
|
{
|
2015-08-29 14:12:52 +02:00
|
|
|
SDL_RWops *file;
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2015-08-29 14:12:52 +02:00
|
|
|
file = SDL_RWFromFile(path, "rb");
|
2014-12-07 22:45:42 +01:00
|
|
|
if (file == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2015-08-29 14:12:52 +02:00
|
|
|
if (SDL_RWread(file, outEntry, sizeof(rct_object_entry), 1) != 1) {
|
|
|
|
SDL_RWclose(file);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-29 14:12:52 +02:00
|
|
|
SDL_RWclose(file);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSize, const rct_object_entry *installedObject)
|
2014-12-07 22:45:42 +01:00
|
|
|
{
|
2014-12-07 22:58:19 +01:00
|
|
|
uint8 objectType;
|
2014-12-07 22:45:42 +01:00
|
|
|
rct_object_entry openedEntry;
|
2015-08-04 22:39:44 +02:00
|
|
|
char path[MAX_PATH];
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWops* rw;
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2015-12-22 16:31:51 +01:00
|
|
|
substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16);
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2015-02-04 18:44:39 +01:00
|
|
|
log_verbose("loading object, %s", path);
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2015-08-29 14:12:52 +02:00
|
|
|
rw = SDL_RWFromFile(path, "rb");
|
2015-07-05 06:36:25 +02:00
|
|
|
if (rw == NULL)
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1);
|
2014-12-07 22:45:42 +01:00
|
|
|
if (!object_entry_compare(&openedEntry, entry)) {
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWclose(rw);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get chunk size
|
2014-12-07 22:58:19 +01:00
|
|
|
uint8 *installedObject_pointer = (uint8*)installedObject + 16;
|
|
|
|
// Skip file name
|
|
|
|
while (*installedObject_pointer++);
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
// Read chunk size
|
|
|
|
*chunkSize = *((uint32*)installedObject_pointer);
|
2015-10-19 20:27:27 +02:00
|
|
|
uint8 *chunk;
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2014-12-07 22:45:42 +01:00
|
|
|
if (*chunkSize == 0xFFFFFFFF) {
|
2016-01-07 23:09:58 +01:00
|
|
|
chunk = (uint8*)malloc(0x600000);
|
2015-07-05 06:36:25 +02:00
|
|
|
*chunkSize = sawyercoding_read_chunk(rw, chunk);
|
2016-01-08 20:04:17 +01:00
|
|
|
chunk = realloc(chunk, *chunkSize);
|
2014-12-07 22:45:42 +01:00
|
|
|
}
|
|
|
|
else {
|
2016-01-07 23:09:58 +01:00
|
|
|
chunk = (uint8*)malloc(*chunkSize);
|
2015-07-05 06:36:25 +02:00
|
|
|
*chunkSize = sawyercoding_read_chunk(rw, chunk);
|
2014-12-07 22:45:42 +01:00
|
|
|
}
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWclose(rw);
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2016-01-06 08:58:56 +01:00
|
|
|
int calculatedChecksum=object_calculate_checksum(&openedEntry, chunk, *chunkSize);
|
2014-12-07 22:45:42 +01:00
|
|
|
|
|
|
|
// Calculate and check checksum
|
2016-01-06 08:58:56 +01:00
|
|
|
if (calculatedChecksum != openedEntry.checksum) {
|
|
|
|
char buffer[100];
|
|
|
|
sprintf(buffer, "Object Load failed due to checksum failure: calculated checksum %d, object says %d.", calculatedChecksum, (int)openedEntry.checksum);
|
|
|
|
log_error(buffer);
|
2014-12-07 22:45:42 +01:00
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 2;
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
objectType = openedEntry.flags & 0x0F;
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
if (!object_test(objectType, chunk)) {
|
2014-12-07 22:45:42 +01:00
|
|
|
log_error("Object Load failed due to paint failure.");
|
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 3;
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-01 18:45:45 +01:00
|
|
|
if (RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) >= 0x4726E){
|
|
|
|
log_error("Object Load failed due to too many images loaded.");
|
2014-12-07 22:45:42 +01:00
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 4;
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
uint8** chunk_list = object_entry_groups[objectType].chunks;
|
2014-12-07 22:45:42 +01:00
|
|
|
if (groupIndex == -1) {
|
2014-12-07 22:58:19 +01:00
|
|
|
for (groupIndex = 0; chunk_list[groupIndex] != (uint8*)-1; groupIndex++) {
|
|
|
|
if (groupIndex + 1 >= object_entry_group_counts[objectType]) {
|
|
|
|
log_error("Object Load failed due to too many objects of a certain type.");
|
2014-12-07 22:45:42 +01:00
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 5;
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-12-07 22:45:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-07 22:58:19 +01:00
|
|
|
chunk_list[groupIndex] = chunk;
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
rct_object_entry_extended* extended_entry = &object_entry_groups[objectType].entries[groupIndex];
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
memcpy(extended_entry, &openedEntry, sizeof(rct_object_entry));
|
|
|
|
extended_entry->chunk_size = *chunkSize;
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2016-01-06 21:41:21 +01:00
|
|
|
gLastLoadedObjectChunkData = chunk;
|
2014-12-07 22:45:42 +01:00
|
|
|
|
2016-01-06 21:41:21 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAFD, uint8) != 0) {
|
2016-01-07 20:01:19 +01:00
|
|
|
object_load(objectType, chunk, groupIndex);
|
2016-01-06 21:41:21 +01:00
|
|
|
}
|
2014-12-07 22:45:42 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-05-24 17:48:13 +02:00
|
|
|
/**
|
2015-02-25 15:06:29 +01:00
|
|
|
*
|
2014-05-24 17:48:13 +02:00
|
|
|
* rct2: 0x006A985D
|
|
|
|
*/
|
2016-01-07 20:01:19 +01:00
|
|
|
int object_load_chunk(int groupIndex, rct_object_entry *entry, int* chunkSize)
|
2014-05-24 17:48:13 +02:00
|
|
|
{
|
2014-12-07 22:45:42 +01:00
|
|
|
// Alow chunkSize to be null
|
|
|
|
int tempChunkSize;
|
|
|
|
if (chunkSize == NULL)
|
|
|
|
chunkSize = &tempChunkSize;
|
2014-09-25 19:34:51 +02:00
|
|
|
|
2014-12-07 22:45:42 +01:00
|
|
|
RCT2_GLOBAL(0xF42B64, uint32) = groupIndex;
|
2014-09-25 19:34:51 +02:00
|
|
|
|
2016-01-06 21:41:21 +01:00
|
|
|
if (gInstalledObjectsCount == 0) {
|
2014-09-25 19:34:51 +02:00
|
|
|
RCT2_GLOBAL(0xF42BD9, uint8) = 0;
|
2014-11-30 22:16:36 +01:00
|
|
|
log_error("Object Load failed due to no items installed check.");
|
2014-09-25 19:34:51 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2014-09-25 21:50:38 +02:00
|
|
|
|
2014-12-07 22:45:42 +01:00
|
|
|
rct_object_entry *installedObject = object_list_find(entry);
|
|
|
|
if (installedObject == NULL) {
|
|
|
|
log_error("object not installed");
|
|
|
|
return 0;
|
2014-09-25 19:34:51 +02:00
|
|
|
}
|
2014-12-07 22:45:42 +01:00
|
|
|
|
|
|
|
if (object_load_file(groupIndex, entry, chunkSize, installedObject))
|
|
|
|
return 1;
|
|
|
|
|
2014-09-29 13:46:26 +02:00
|
|
|
return 0;
|
2014-05-24 19:07:29 +02:00
|
|
|
}
|
|
|
|
|
2015-12-11 16:38:37 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006a9f42
|
|
|
|
* ebx: file
|
|
|
|
* ebp: entry
|
2014-10-01 19:52:02 +02:00
|
|
|
*/
|
2016-01-07 20:01:19 +01:00
|
|
|
int write_object_file(SDL_RWops *rw, rct_object_entry* entry)
|
|
|
|
{
|
2015-03-05 23:00:32 +01:00
|
|
|
uint8 entryGroupIndex = 0, type = 0;
|
|
|
|
uint8* chunk = 0;
|
2014-10-01 19:52:02 +02:00
|
|
|
|
2015-03-05 23:00:32 +01:00
|
|
|
if (!find_object_in_entry_group(entry, &type, &entryGroupIndex))return 0;
|
2015-02-25 15:06:29 +01:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
chunk = object_entry_groups[type].chunks[entryGroupIndex];
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
object_unload(type, chunk);
|
2014-10-01 22:49:37 +02:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
rct_object_entry_extended* installed_entry = &object_entry_groups[type].entries[entryGroupIndex];
|
2016-01-07 23:09:58 +01:00
|
|
|
uint8* dst_buffer = (uint8*)malloc(0x600000);
|
2015-03-05 23:00:32 +01:00
|
|
|
memcpy(dst_buffer, installed_entry, sizeof(rct_object_entry));
|
2014-10-01 19:52:02 +02:00
|
|
|
|
2014-12-07 22:58:19 +01:00
|
|
|
uint32 size_dst = sizeof(rct_object_entry);
|
2014-10-01 22:49:37 +02:00
|
|
|
|
2015-02-25 15:06:29 +01:00
|
|
|
sawyercoding_chunk_header chunkHeader;
|
2014-10-04 12:41:16 +02:00
|
|
|
// Encoding type (not used anymore)
|
2014-10-01 22:49:37 +02:00
|
|
|
RCT2_GLOBAL(0x9E3CBD, uint8) = object_entry_group_encoding[type];
|
2014-10-04 12:41:16 +02:00
|
|
|
|
2014-10-01 22:49:37 +02:00
|
|
|
chunkHeader.encoding = object_entry_group_encoding[type];
|
2014-12-07 22:58:19 +01:00
|
|
|
chunkHeader.length = installed_entry->chunk_size;
|
2014-10-01 22:49:37 +02:00
|
|
|
|
2015-03-05 23:00:32 +01:00
|
|
|
size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader);
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWwrite(rw, dst_buffer, 1, size_dst);
|
2014-10-04 12:41:16 +02:00
|
|
|
|
|
|
|
free(dst_buffer);
|
2014-10-16 03:02:43 +02:00
|
|
|
return 1;
|
2014-10-01 19:52:02 +02:00
|
|
|
}
|
|
|
|
|
2014-09-29 20:07:25 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006AA2B7
|
|
|
|
*/
|
2015-07-05 06:36:25 +02:00
|
|
|
int object_load_packed(SDL_RWops* rw)
|
2014-09-29 20:07:25 +02:00
|
|
|
{
|
|
|
|
object_unload_all();
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
rct_object_entry entry;
|
2014-09-29 20:07:25 +02:00
|
|
|
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWread(rw, &entry, 16, 1);
|
2014-09-29 20:07:25 +02:00
|
|
|
|
2016-01-07 23:09:58 +01:00
|
|
|
uint8* chunk = (uint8*)malloc(0x600000);
|
2015-07-05 06:36:25 +02:00
|
|
|
uint32 chunkSize = sawyercoding_read_chunk(rw, chunk);
|
2016-01-08 20:04:17 +01:00
|
|
|
chunk = realloc(chunk, chunkSize);
|
2015-03-07 10:44:34 +01:00
|
|
|
|
2014-09-29 20:07:25 +02:00
|
|
|
if (chunk == NULL){
|
2015-03-07 10:44:34 +01:00
|
|
|
log_error("Failed to allocate memory for packed object.");
|
2014-09-29 20:07:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
if (object_calculate_checksum(&entry, chunk, chunkSize) != entry.checksum){
|
2016-01-06 08:58:56 +01:00
|
|
|
log_error("Checksum mismatch from packed object: %.8s", entry.name);
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-09-29 20:07:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
int type = entry.flags & 0x0F;
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
if (!object_test(type, chunk)) {
|
2015-03-07 10:44:34 +01:00
|
|
|
log_error("Packed object failed paint test.");
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-09-29 20:07:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-01 18:45:45 +01:00
|
|
|
if (RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) >= 0x4726E){
|
2015-03-07 10:44:34 +01:00
|
|
|
log_error("Packed object has too many images.");
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-09-29 20:07:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entryGroupIndex = 0;
|
|
|
|
|
|
|
|
for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){
|
2014-12-07 22:58:19 +01:00
|
|
|
if (object_entry_groups[type].chunks[entryGroupIndex] == (uint8*)-1){
|
2014-09-29 20:07:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entryGroupIndex == object_entry_group_counts[type]){
|
2015-08-04 22:39:44 +02:00
|
|
|
// This should never occur. Objects are not loaded before installing a
|
2015-03-07 10:44:34 +01:00
|
|
|
// packed object. So there is only one object loaded at this point.
|
|
|
|
log_error("Too many objects of the same type loaded.");
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2014-09-29 20:07:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Copy the entry into the relevant entry group.
|
2014-12-07 22:58:19 +01:00
|
|
|
object_entry_groups[type].chunks[entryGroupIndex] = chunk;
|
2015-03-07 10:44:34 +01:00
|
|
|
rct_object_entry_extended* extended_entry = &object_entry_groups[type].entries[entryGroupIndex];
|
|
|
|
memcpy(extended_entry, &entry, sizeof(rct_object_entry));
|
|
|
|
extended_entry->chunk_size = chunkSize;
|
2014-09-29 20:07:25 +02:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Ensure the entry does not already exist.
|
2016-01-06 21:41:21 +01:00
|
|
|
rct_object_entry *installedObject = gInstalledObjects;
|
|
|
|
if (gInstalledObjectsCount){
|
|
|
|
for (uint32 i = 0; i < gInstalledObjectsCount; ++i){
|
2015-03-07 10:44:34 +01:00
|
|
|
if (object_entry_compare(&entry, installedObject)){
|
2014-09-29 20:07:25 +02:00
|
|
|
object_unload_all();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
installedObject = object_get_next(installedObject);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Convert the entry name to a upper case path name
|
2015-08-04 22:39:44 +02:00
|
|
|
char path[MAX_PATH];
|
2015-03-07 10:44:34 +01:00
|
|
|
char objectPath[9] = { 0 };
|
2014-09-29 20:07:25 +02:00
|
|
|
for (int i = 0; i < 8; ++i){
|
2015-03-07 10:44:34 +01:00
|
|
|
if (entry.name[i] != ' ')
|
|
|
|
objectPath[i] = toupper(entry.name[i]);
|
2014-09-29 20:07:25 +02:00
|
|
|
else
|
|
|
|
objectPath[i] = '\0';
|
|
|
|
}
|
2014-09-30 19:04:17 +02:00
|
|
|
|
2015-12-22 16:31:51 +01:00
|
|
|
substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath);
|
2015-03-07 10:44:34 +01:00
|
|
|
// Require pointer to start of filename
|
2014-09-30 19:04:17 +02:00
|
|
|
char* last_char = path + strlen(path);
|
|
|
|
strcat(path, ".DAT");
|
2014-10-01 19:52:02 +02:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Check that file does not exist
|
|
|
|
// Adjust filename if it does.
|
2014-10-09 15:03:54 +02:00
|
|
|
for (; platform_file_exists(path);){
|
2014-09-30 19:04:17 +02:00
|
|
|
for (char* curr_char = last_char - 1;; --curr_char){
|
|
|
|
if (*curr_char == '\\'){
|
2015-12-22 16:31:51 +01:00
|
|
|
substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "00000000.DAT");
|
2014-09-30 19:04:17 +02:00
|
|
|
char* last_char = path + strlen(path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*curr_char < '0') *curr_char = '0';
|
|
|
|
else if (*curr_char == '9') *curr_char = 'A';
|
|
|
|
else if (*curr_char == 'Z') *curr_char = '0';
|
|
|
|
else (*curr_char)++;
|
|
|
|
if (*curr_char != '0') break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Actually write the object to the file
|
2015-08-29 14:12:52 +02:00
|
|
|
SDL_RWops* rw_out = SDL_RWFromFile(path, "wb");
|
2015-07-05 06:36:25 +02:00
|
|
|
if (rw_out != NULL){
|
|
|
|
uint8 result = write_object_file(rw_out, &entry);
|
2015-03-07 10:44:34 +01:00
|
|
|
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWclose(rw_out);
|
2014-10-01 19:52:02 +02:00
|
|
|
object_unload_all();
|
2015-03-07 10:44:34 +01:00
|
|
|
|
|
|
|
return result;
|
2014-10-01 22:49:37 +02:00
|
|
|
}
|
2015-03-07 10:44:34 +01:00
|
|
|
|
|
|
|
object_unload_all();
|
|
|
|
return 0;
|
2014-09-29 20:07:25 +02:00
|
|
|
}
|
|
|
|
|
2014-05-24 19:07:29 +02:00
|
|
|
/**
|
2015-02-25 15:06:29 +01:00
|
|
|
*
|
2014-05-24 19:07:29 +02:00
|
|
|
* rct2: 0x006A9CAF
|
|
|
|
*/
|
2016-01-07 20:01:19 +01:00
|
|
|
void object_unload_chunk(rct_object_entry *entry)
|
2014-05-24 19:07:29 +02:00
|
|
|
{
|
2015-06-26 18:45:38 +02:00
|
|
|
uint8 object_type, object_index;
|
|
|
|
if (!find_object_in_entry_group(entry, &object_type, &object_index)){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8* chunk = object_entry_groups[object_type].chunks[object_index];
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
object_unload(object_type, chunk);
|
2015-06-26 18:45:38 +02:00
|
|
|
|
2016-01-07 23:09:58 +01:00
|
|
|
free(chunk);
|
2015-10-19 20:27:27 +02:00
|
|
|
object_entry_groups[object_type].chunks[object_index] = (uint8*)-1;
|
2014-05-24 23:14:42 +02:00
|
|
|
}
|
|
|
|
|
2014-12-07 22:45:42 +01:00
|
|
|
int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b)
|
2014-05-26 18:59:42 +02:00
|
|
|
{
|
2015-03-07 10:44:34 +01:00
|
|
|
// If an official object don't bother checking checksum
|
2016-01-06 08:58:56 +01:00
|
|
|
if ((a->flags & 0xF0) || (b->flags & 0xF0)) {
|
2014-05-26 18:59:42 +02:00
|
|
|
if ((a->flags & 0x0F) != (b->flags & 0x0F))
|
|
|
|
return 0;
|
2015-12-31 09:16:44 +01:00
|
|
|
int match = memcmp(a->name, b->name, 8);
|
|
|
|
if (match)
|
2014-05-26 18:59:42 +02:00
|
|
|
return 0;
|
2015-02-25 15:06:29 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-05-26 18:59:42 +02:00
|
|
|
if (a->flags != b->flags)
|
|
|
|
return 0;
|
2015-12-31 09:16:44 +01:00
|
|
|
int match = memcmp(a->name, b->name, 8);
|
|
|
|
if (match)
|
2014-05-26 18:59:42 +02:00
|
|
|
return 0;
|
|
|
|
if (a->checksum != b->checksum)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-10-19 20:27:27 +02:00
|
|
|
int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength)
|
2014-05-26 18:59:42 +02:00
|
|
|
{
|
2016-01-06 01:57:54 +01:00
|
|
|
const uint8 *entryBytePtr = (uint8*)entry;
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2016-01-06 01:57:54 +01:00
|
|
|
uint32 checksum = 0xF369A75B;
|
|
|
|
checksum ^= entryBytePtr[0];
|
2014-05-26 18:59:42 +02:00
|
|
|
checksum = rol32(checksum, 11);
|
2016-01-06 01:57:54 +01:00
|
|
|
for (int i = 4; i < 12; i++) {
|
|
|
|
checksum ^= entryBytePtr[i];
|
2014-05-26 18:59:42 +02:00
|
|
|
checksum = rol32(checksum, 11);
|
|
|
|
}
|
2016-01-06 01:57:54 +01:00
|
|
|
for (int i = 0; i < dataLength; i++) {
|
|
|
|
checksum ^= data[i];
|
2014-05-26 18:59:42 +02:00
|
|
|
checksum = rol32(checksum, 11);
|
|
|
|
}
|
2016-01-06 01:57:54 +01:00
|
|
|
return (int)checksum;
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
|
|
|
|
2015-12-11 16:38:37 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006A9ED1
|
|
|
|
*/
|
2015-03-01 15:24:05 +01:00
|
|
|
int object_chunk_load_image_directory(uint8_t** chunk)
|
2015-02-25 15:06:29 +01:00
|
|
|
{
|
2015-03-01 18:45:45 +01:00
|
|
|
int image_start_no = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32_t);
|
2015-08-04 22:39:44 +02:00
|
|
|
|
2015-03-01 15:24:05 +01:00
|
|
|
// First dword of chunk is no_images
|
|
|
|
int no_images = *((uint32_t*)(*chunk));
|
|
|
|
*chunk += 4;
|
|
|
|
// Second dword of chunk is length of image data
|
|
|
|
int length_of_data = *((uint32_t*)(*chunk));
|
|
|
|
*chunk += 4;
|
2015-02-26 19:42:25 +01:00
|
|
|
|
2015-03-01 18:45:45 +01:00
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32_t) = no_images + image_start_no;
|
2015-02-26 19:42:25 +01:00
|
|
|
|
2015-05-28 01:16:51 +02:00
|
|
|
rct_g1_element* g1_dest = &g1Elements[image_start_no];
|
2015-02-26 19:42:25 +01:00
|
|
|
|
2015-03-01 15:24:05 +01:00
|
|
|
// After length of data is the start of all g1 element structs
|
|
|
|
rct_g1_element* g1_source = (rct_g1_element*)(*chunk);
|
|
|
|
|
|
|
|
// After the g1 element structs is the actual images.
|
|
|
|
uint8* image_offset = no_images * sizeof(rct_g1_element) + (uint8*)g1_source;
|
|
|
|
|
|
|
|
for (int i = 0; i < no_images; ++i){
|
2015-02-26 19:42:25 +01:00
|
|
|
*g1_dest = *g1_source++;
|
2015-03-01 15:24:05 +01:00
|
|
|
g1_dest->offset += (uint32)image_offset;
|
2015-02-26 19:42:25 +01:00
|
|
|
g1_dest++;
|
2015-02-25 15:06:29 +01:00
|
|
|
}
|
2015-02-26 19:42:25 +01:00
|
|
|
|
2015-03-01 15:24:05 +01:00
|
|
|
*chunk = ((uint8*)g1_source) + length_of_data;
|
|
|
|
return image_start_no;
|
2015-02-25 15:06:29 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
typedef bool (*object_load_func)(void *objectEntry, uint32 entryIndex);
|
|
|
|
typedef void (*object_unload_func)(void *objectEntry);
|
|
|
|
typedef bool (*object_test_func)(void *objectEntry);
|
2016-01-07 20:01:19 +01:00
|
|
|
typedef void (*object_paint_func)(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y);
|
2016-01-07 20:12:59 +01:00
|
|
|
typedef rct_string_id (*object_desc_func)(void *objectEntry);
|
2016-01-06 23:13:49 +01:00
|
|
|
|
2015-12-11 16:38:37 +01:00
|
|
|
/**
|
2016-01-06 23:13:49 +01:00
|
|
|
* Represents addresses for virtual object functions.
|
2015-12-11 16:38:37 +01:00
|
|
|
*/
|
2016-01-06 23:13:49 +01:00
|
|
|
typedef struct {
|
|
|
|
object_load_func load;
|
|
|
|
object_unload_func unload;
|
|
|
|
object_test_func test;
|
|
|
|
object_paint_func paint;
|
|
|
|
object_desc_func desc;
|
|
|
|
} object_type_vtable;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Ride (rct2: 0x006E6E2A)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_ride_load(void *objectEntry, uint32 entryIndex)
|
2015-02-25 15:06:29 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_ride_type *rideEntry = (rct_ride_type*)objectEntry;
|
|
|
|
|
|
|
|
// After rideEntry is 3 string tables
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_ride_type));
|
|
|
|
rideEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 0);
|
|
|
|
rideEntry->description = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 1);
|
|
|
|
|
|
|
|
//TODO: Move to its own function when ride construction window is merged.
|
|
|
|
if (gConfigInterface.select_by_track_type) {
|
|
|
|
rideEntry->enabledTrackPieces = 0xFFFFFFFFFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 2);
|
|
|
|
rideEntry->vehicle_preset_list = (vehicle_colour_preset_list*)extendedEntryData;
|
|
|
|
|
|
|
|
// If Unknown struct size is 0xFF then there are 32 3 byte structures
|
|
|
|
uint8 unknown_size = *extendedEntryData++;
|
|
|
|
if (unknown_size != 0xFF) {
|
|
|
|
extendedEntryData += unknown_size * 3;
|
|
|
|
} else {
|
|
|
|
extendedEntryData += 0x60;
|
|
|
|
}
|
|
|
|
|
|
|
|
sint8 *peep_loading_positions = (sint8*)extendedEntryData;
|
|
|
|
// Peep loading positions variable size
|
|
|
|
// 4 different vehicle subtypes are available
|
|
|
|
for (int i = 0; i < 4; i++){
|
|
|
|
uint16 no_peep_positions = *extendedEntryData++;
|
|
|
|
// If no_peep_positions is 0xFF then no_peep_positions is a word
|
|
|
|
if (no_peep_positions == 0xFF) {
|
|
|
|
no_peep_positions = *((uint16*)extendedEntryData);
|
|
|
|
extendedEntryData += 2;
|
2015-06-24 12:41:19 +02:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += no_peep_positions;
|
|
|
|
}
|
2015-06-24 12:41:19 +02:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int images_offset = object_chunk_load_image_directory(&extendedEntryData);
|
|
|
|
rideEntry->images_offset = images_offset;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int cur_vehicle_images_offset = images_offset + 3;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
rct_ride_type_vehicle* vehicleEntry = &rideEntry->vehicles[i];
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT) {
|
|
|
|
int al = 1;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_SWINGING) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 13;
|
2016-01-09 17:51:23 +01:00
|
|
|
if ((vehicleEntry->flags_b & (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) != (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 7;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_5)) {
|
|
|
|
if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_11)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 5;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_9) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 3;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
|
|
|
vehicleEntry->var_03 = al;
|
|
|
|
// 0x6DE90B
|
|
|
|
|
|
|
|
al = 0x20;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 1;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_7) {
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->var_11 != 6) {
|
|
|
|
al = 2;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_7)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = 4;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_12) {
|
2016-01-06 23:13:49 +01:00
|
|
|
al = vehicleEntry->special_frames;
|
|
|
|
}
|
|
|
|
vehicleEntry->var_02 = al;
|
|
|
|
// 0x6DE946
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
vehicleEntry->var_16 = vehicleEntry->var_02 * vehicleEntry->var_03;
|
|
|
|
vehicleEntry->base_image_id = cur_vehicle_images_offset;
|
|
|
|
int image_index = vehicleEntry->base_image_id;
|
2015-04-03 19:21:50 +02:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->car_visual != VEHICLE_VISUAL_RIVER_RAPIDS) {
|
|
|
|
int b = vehicleEntry->var_16 * 32;
|
2015-04-03 19:21:50 +02:00
|
|
|
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_11) b /= 2;
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_15) b /= 8;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
image_index += b;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Incline 25
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPES) {
|
|
|
|
vehicleEntry->var_20 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 72;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14)
|
2016-01-06 23:13:49 +01:00
|
|
|
b = vehicleEntry->var_16 * 16;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
image_index += b;
|
|
|
|
}
|
2015-04-03 19:21:50 +02:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Incline 60
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_STEEP_SLOPES) {
|
|
|
|
vehicleEntry->var_24 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 80;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-04-03 19:21:50 +02:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Verticle
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES) {
|
|
|
|
vehicleEntry->var_28 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 116;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Unknown
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES) {
|
|
|
|
vehicleEntry->var_2C = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 24;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Bank
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_BANKED) {
|
|
|
|
vehicleEntry->var_30 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 80;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_INLINE_TWISTS) {
|
|
|
|
vehicleEntry->var_34 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 40;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-04-03 19:21:50 +02:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Track half? Up/Down
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS) {
|
|
|
|
vehicleEntry->var_38 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 128;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Unknown
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS) {
|
|
|
|
vehicleEntry->var_3C = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 16;
|
|
|
|
image_index += b;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Unknown
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS) {
|
|
|
|
vehicleEntry->var_40 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 16;
|
|
|
|
image_index += b;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS) {
|
|
|
|
vehicleEntry->var_44 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 128;
|
|
|
|
image_index += b;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS) {
|
|
|
|
vehicleEntry->var_48 = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 16;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_CORKSCREWS) {
|
|
|
|
vehicleEntry->var_4C = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 80;
|
|
|
|
image_index += b;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Unknown
|
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) {
|
|
|
|
vehicleEntry->var_1C = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 12;
|
|
|
|
image_index += b;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_14) {
|
|
|
|
// Same offset as above???
|
|
|
|
vehicleEntry->var_4C = image_index;
|
|
|
|
b = vehicleEntry->var_16 * 32;
|
|
|
|
image_index += b;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
} else {
|
|
|
|
image_index += vehicleEntry->var_16 * 36;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
// No vehicle images
|
|
|
|
vehicleEntry->no_vehicle_images = image_index - cur_vehicle_images_offset;
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Move the offset over this vehicles images. Including peeps
|
|
|
|
cur_vehicle_images_offset = image_index + vehicleEntry->no_seating_rows * vehicleEntry->no_vehicle_images;
|
|
|
|
// 0x6DEB0D
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-09 17:51:23 +01:00
|
|
|
if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_10)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
int num_images = cur_vehicle_images_offset - vehicleEntry->base_image_id;
|
2016-01-09 17:51:23 +01:00
|
|
|
if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_13) {
|
2016-01-06 23:13:49 +01:00
|
|
|
num_images *= 2;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
set_vehicle_type_image_max_sizes(vehicleEntry, num_images);
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
sint8 no_positions = *peep_loading_positions++;
|
|
|
|
if (no_positions == -1) {
|
|
|
|
// The no_positions is 16 bit skip over
|
|
|
|
peep_loading_positions += 2;
|
|
|
|
}
|
|
|
|
vehicleEntry->peep_loading_positions = peep_loading_positions;
|
|
|
|
}
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// 0x6DEB71
|
|
|
|
if (RCT2_GLOBAL(0x9ADAFD, uint8) == 0) {
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
int dl = rideEntry->ride_type[i];
|
|
|
|
if (dl == 0xFF) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
uint8 *typeToRideEntryIndexMap = RCT2_ADDRESS(0x009E32F8, uint8);
|
|
|
|
while (dl >= 0) {
|
|
|
|
if (*typeToRideEntryIndexMap++ == 0xFF) {
|
|
|
|
dl--;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
typeToRideEntryIndexMap--;
|
|
|
|
uint8 previous_entry = entryIndex;
|
|
|
|
while (typeToRideEntryIndexMap < RCT2_ADDRESS(0x9E34E4, uint8)){
|
|
|
|
uint8 backup_entry = *typeToRideEntryIndexMap;
|
|
|
|
*typeToRideEntryIndexMap++ = previous_entry;
|
|
|
|
previous_entry = backup_entry;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// 0x6DEBAA
|
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, sint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int di = rideEntry->ride_type[0] | (rideEntry->ride_type[1] << 8) | (rideEntry->ride_type[2] << 16);
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && !rideTypeShouldLoseSeparateFlag(rideEntry)) {
|
|
|
|
di |= 0x1000000;
|
2015-03-01 15:24:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
RCT2_GLOBAL(0xF433DD, uint32) = di;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_ride_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_ride_type *rideEntry = (rct_ride_type*)objectEntry;
|
|
|
|
rideEntry->name = 0;
|
|
|
|
rideEntry->description = 0;
|
|
|
|
rideEntry->images_offset = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[i];
|
|
|
|
|
|
|
|
rideVehicleEntry->base_image_id = 0;
|
|
|
|
rideVehicleEntry->var_1C = 0;
|
|
|
|
rideVehicleEntry->var_20 = 0;
|
|
|
|
rideVehicleEntry->var_24 = 0;
|
|
|
|
rideVehicleEntry->var_28 = 0;
|
|
|
|
rideVehicleEntry->var_2C = 0;
|
|
|
|
rideVehicleEntry->var_30 = 0;
|
|
|
|
rideVehicleEntry->var_34 = 0;
|
|
|
|
rideVehicleEntry->var_38 = 0;
|
|
|
|
rideVehicleEntry->var_3C = 0;
|
|
|
|
rideVehicleEntry->var_40 = 0;
|
|
|
|
rideVehicleEntry->var_44 = 0;
|
|
|
|
rideVehicleEntry->var_48 = 0;
|
|
|
|
rideVehicleEntry->var_4C = 0;
|
|
|
|
rideVehicleEntry->no_vehicle_images = 0;
|
|
|
|
rideVehicleEntry->var_16 = 0;
|
|
|
|
|
2016-01-09 17:51:23 +01:00
|
|
|
if (!(rideVehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_10)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
rideVehicleEntry->sprite_width = 0;
|
|
|
|
rideVehicleEntry->sprite_height_negative = 0;
|
|
|
|
rideVehicleEntry->sprite_height_positive = 0;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
rideVehicleEntry->var_02 = 0;
|
|
|
|
rideVehicleEntry->var_03 = 0;
|
|
|
|
rideVehicleEntry->peep_loading_positions = 0;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
rideEntry->vehicle_preset_list = NULL;
|
2015-02-26 14:47:34 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_ride_test(void *objectEntry)
|
2015-03-01 22:59:30 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_ride_type* rideEntry = (rct_ride_type*)objectEntry;
|
|
|
|
if (rideEntry->excitement_multipler > 75) return false;
|
|
|
|
if (rideEntry->intensity_multipler > 75) return false;
|
|
|
|
if (rideEntry->nausea_multipler > 75) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_ride_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_ride_type *rideEntry = (rct_ride_type*)objectEntry;
|
|
|
|
int imageId = rideEntry->images_offset;
|
|
|
|
if (rideEntry->ride_type[0] == 0xFF) {
|
|
|
|
imageId++;
|
|
|
|
if (rideEntry->ride_type[1] == 0xFF) {
|
|
|
|
imageId++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gfx_draw_sprite(dpi, imageId, x - 56, y - 56, 0);
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_ride_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_ride_type *rideEntry = (rct_ride_type*)objectEntry;
|
|
|
|
|
|
|
|
// Get description
|
|
|
|
rct_string_id stringId = rideEntry->description;
|
|
|
|
if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(rideEntry)) {
|
|
|
|
uint8 rideType = rideEntry->ride_type[0];
|
|
|
|
if (rideType == 0xFF) {
|
|
|
|
rideType = rideEntry->ride_type[1];
|
|
|
|
if (rideType == 0xFF) {
|
|
|
|
rideType = rideEntry->ride_type[2];
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
stringId = 512 + rideType;
|
|
|
|
}
|
2016-01-07 20:12:59 +01:00
|
|
|
return stringId;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_ride_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_ride_load,
|
|
|
|
object_type_ride_unload,
|
|
|
|
object_type_ride_test,
|
|
|
|
object_type_ride_paint,
|
|
|
|
object_type_ride_desc
|
|
|
|
};
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Small Scenery (rct2: 0x006E3466)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_small_scenery_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x1C);
|
|
|
|
|
|
|
|
sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_SMALL_SCENERY, entryIndex, 0);
|
|
|
|
sceneryEntry->small_scenery.scenery_tab_id = 0xFF;
|
|
|
|
if (*extendedEntryData != 0xFF) {
|
|
|
|
uint8 entry_type, entry_index;
|
|
|
|
if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) {
|
|
|
|
sceneryEntry->small_scenery.scenery_tab_id = entry_index;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += sizeof(rct_object_entry);
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG16){
|
|
|
|
sceneryEntry->small_scenery.var_10 = (uint32)extendedEntryData;
|
|
|
|
while (*++extendedEntryData != 0xFF);
|
|
|
|
extendedEntryData++;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData);
|
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_small_scenery_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
sceneryEntry->name = 0;
|
|
|
|
sceneryEntry->image = 0;
|
|
|
|
sceneryEntry->small_scenery.var_10 = 0;
|
|
|
|
sceneryEntry->small_scenery.scenery_tab_id = 0;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_small_scenery_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (sceneryEntry->small_scenery.price <= 0) return false;
|
|
|
|
if (sceneryEntry->small_scenery.removal_price > 0) return true;
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Make sure you don't make a profit when placing then removing.
|
|
|
|
if (-sceneryEntry->small_scenery.removal_price > sceneryEntry->small_scenery.price) return false;
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_small_scenery_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2016-01-14 21:09:56 +01:00
|
|
|
rct_drawpixelinfo clipDPI;
|
|
|
|
if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = sceneryEntry->image;
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) {
|
|
|
|
imageId |= 0x20D00000;
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) {
|
|
|
|
imageId |= 0x92000000;
|
|
|
|
}
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
x = 56;
|
|
|
|
y = sceneryEntry->small_scenery.height / 4 + 78;
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) {
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) {
|
|
|
|
y -= 12;
|
|
|
|
}
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG10) {
|
|
|
|
imageId = sceneryEntry->image + 0x44500004;
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) {
|
|
|
|
imageId |= 0x92000000;
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG8) {
|
|
|
|
imageId = sceneryEntry->image + 4;
|
|
|
|
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) {
|
|
|
|
imageId |= 0x92000000;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_small_scenery_desc(void *objectEntry)
|
2015-03-01 22:59:30 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_small_scenery_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_small_scenery_load,
|
|
|
|
object_type_small_scenery_unload,
|
|
|
|
object_type_small_scenery_test,
|
|
|
|
object_type_small_scenery_paint,
|
|
|
|
object_type_small_scenery_desc
|
|
|
|
};
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Large Scenery (rct2: 0x006B92A7)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x1A);
|
|
|
|
|
|
|
|
sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_LARGE_SCENERY, entryIndex, 0);
|
|
|
|
sceneryEntry->large_scenery.scenery_tab_id = 0xFF;
|
|
|
|
if (*extendedEntryData != 0xFF) {
|
|
|
|
uint8 entry_type, entry_index;
|
|
|
|
if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) {
|
|
|
|
sceneryEntry->large_scenery.scenery_tab_id = entry_index;
|
2015-03-02 19:21:32 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += sizeof(rct_object_entry);
|
|
|
|
if (sceneryEntry->large_scenery.flags & (1 << 2)) {
|
|
|
|
sceneryEntry->large_scenery.var_12 = (uint32)extendedEntryData;
|
|
|
|
extendedEntryData += 1038;
|
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
sceneryEntry->large_scenery.tiles = (rct_large_scenery_tile*)extendedEntryData;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// skip over large scenery tiles
|
|
|
|
while (*((uint16*)extendedEntryData) != 0xFFFF){
|
|
|
|
extendedEntryData += sizeof(rct_large_scenery_tile);
|
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += 2;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = object_chunk_load_image_directory(&extendedEntryData);
|
|
|
|
if (sceneryEntry->large_scenery.flags & (1 << 2)){
|
|
|
|
sceneryEntry->large_scenery.var_16 = imageId;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
uint8* edx = (uint8*)sceneryEntry->large_scenery.var_12;
|
|
|
|
if (!(edx[0xC] & 1)) {
|
|
|
|
imageId += edx[0xD] * 4;
|
|
|
|
} else{
|
|
|
|
imageId += edx[0xD] * 2;
|
2015-03-02 19:21:32 +01:00
|
|
|
}
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
sceneryEntry->image = imageId;
|
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
2015-03-02 19:21:32 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_large_scenery_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
sceneryEntry->name = 0;
|
|
|
|
sceneryEntry->image = 0;
|
|
|
|
sceneryEntry->large_scenery.tiles = 0;
|
|
|
|
sceneryEntry->large_scenery.scenery_tab_id = 0;
|
|
|
|
sceneryEntry->large_scenery.var_12 = 0;
|
|
|
|
sceneryEntry->large_scenery.var_16 = 0;
|
|
|
|
}
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_large_scenery_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (sceneryEntry->large_scenery.price <= 0) return false;
|
|
|
|
if (sceneryEntry->large_scenery.removal_price > 0) return true;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
// Make sure you don't make a profit when placing then removing.
|
|
|
|
if (-sceneryEntry->large_scenery.removal_price > sceneryEntry->large_scenery.price) return false;
|
2015-03-02 19:21:32 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_large_scenery_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2015-03-01 22:59:30 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = sceneryEntry->image | 0xB2D00000;
|
|
|
|
gfx_draw_sprite(dpi, imageId, x, y - 39, 0);
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_large_scenery_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_large_scenery_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_large_scenery_load,
|
|
|
|
object_type_large_scenery_unload,
|
|
|
|
object_type_large_scenery_test,
|
|
|
|
object_type_large_scenery_paint,
|
|
|
|
object_type_large_scenery_desc
|
|
|
|
};
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Wall (rct2: 0x006E5A25)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_wall_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E);
|
|
|
|
|
|
|
|
sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_WALLS, entryIndex, 0);
|
|
|
|
sceneryEntry->wall.scenery_tab_id = 0xFF;
|
|
|
|
if (*extendedEntryData != 0xFF){
|
|
|
|
uint8 entry_type, entry_index;
|
|
|
|
if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) {
|
|
|
|
sceneryEntry->wall.scenery_tab_id = entry_index;
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += sizeof(rct_object_entry);
|
|
|
|
sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData);
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
2015-03-03 19:25:14 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_wall_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
sceneryEntry->name = 0;
|
|
|
|
sceneryEntry->image = 0;
|
|
|
|
sceneryEntry->wall.scenery_tab_id = 0;
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_wall_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
if (sceneryEntry->wall.price <= 0) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_wall_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2016-01-14 21:09:56 +01:00
|
|
|
rct_drawpixelinfo clipDPI;
|
|
|
|
if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = sceneryEntry->image;
|
|
|
|
imageId |= 0x20D00000;
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) {
|
|
|
|
imageId |= 0x92000000;
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
x = 70;
|
|
|
|
y = sceneryEntry->wall.height * 2 + 72;
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_FLAG2){
|
|
|
|
imageId = sceneryEntry->image + 0x44500006;
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
} else if (sceneryEntry->wall.flags & WALL_SCENERY_FLAG5){
|
|
|
|
imageId++;
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId, x, y, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_wall_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_wall_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_wall_load,
|
|
|
|
object_type_wall_unload,
|
|
|
|
object_type_wall_test,
|
|
|
|
object_type_wall_paint,
|
|
|
|
object_type_wall_desc
|
|
|
|
};
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Banner (rct2: 0x006BA84E)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-03 19:25:14 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_banner_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0C);
|
|
|
|
|
|
|
|
sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_BANNERS, entryIndex, 0);
|
|
|
|
sceneryEntry->banner.scenery_tab_id = 0xFF;
|
|
|
|
if (*extendedEntryData != 0xFF){
|
|
|
|
uint8 entry_type, entry_index;
|
|
|
|
if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)){
|
|
|
|
sceneryEntry->banner.scenery_tab_id = entry_index;
|
2015-03-03 19:25:14 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-01 22:59:30 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += sizeof(rct_object_entry);
|
|
|
|
sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData);
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_banner_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
sceneryEntry->name = 0;
|
|
|
|
sceneryEntry->image = 0;
|
|
|
|
sceneryEntry->banner.scenery_tab_id = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_banner_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
if (sceneryEntry->banner.price <= 0) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_banner_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = sceneryEntry->image | 0x20D00000;
|
|
|
|
gfx_draw_sprite(dpi, imageId, x, y, 0);
|
|
|
|
gfx_draw_sprite(dpi, imageId + 1, x, y, 0);
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_banner_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_banner_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_banner_load,
|
|
|
|
object_type_banner_unload,
|
|
|
|
object_type_banner_test,
|
|
|
|
object_type_banner_paint,
|
|
|
|
object_type_banner_desc
|
|
|
|
};
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Path (rct2: 0x006A8621)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_path_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_path_type *pathEntry = (rct_path_type*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E);
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
pathEntry->string_idx = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PATHS, entryIndex, 0);
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = object_chunk_load_image_directory(&extendedEntryData);
|
|
|
|
pathEntry->image = imageId;
|
|
|
|
pathEntry->bridge_image = imageId + 109;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = 0;
|
|
|
|
// Set the default path for when opening footpath window
|
|
|
|
for (int i = 0; i < object_entry_group_counts[OBJECT_TYPE_PATHS]; i++) {
|
|
|
|
rct_path_type *pathEntry2 = (rct_path_type*)object_entry_groups[OBJECT_TYPE_PATHS].chunks[i];
|
|
|
|
if (pathEntry2 == (rct_path_type*)-1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(pathEntry2->flags & 4)) {
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = i;
|
|
|
|
break;
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = i;
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
|
|
|
|
return true;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_path_unload(void *objectEntry)
|
2015-02-26 14:47:34 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_path_type *pathEntry = (rct_path_type*)objectEntry;
|
|
|
|
pathEntry->string_idx = 0;
|
|
|
|
pathEntry->image = 0;
|
|
|
|
pathEntry->bridge_image = 0;
|
|
|
|
}
|
2015-03-01 15:24:05 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_path_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_path_type *pathEntry = (rct_path_type*)objectEntry;
|
|
|
|
if (pathEntry->var_0A >= 2) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_path_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_path_type *pathEntry = (rct_path_type*)objectEntry;
|
|
|
|
gfx_draw_sprite(dpi, pathEntry->image + 71, x - 49, y - 17, 0);
|
|
|
|
gfx_draw_sprite(dpi, pathEntry->image + 72, x + 4, y - 17, 0);
|
|
|
|
}
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_path_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_path_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_path_load,
|
|
|
|
object_type_path_unload,
|
|
|
|
object_type_path_test,
|
|
|
|
object_type_path_paint,
|
|
|
|
object_type_path_desc
|
|
|
|
};
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Path Item (rct2: 0x006A86E2)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_path_bit_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E);
|
|
|
|
|
|
|
|
sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PATH_BITS, entryIndex, 0);
|
|
|
|
sceneryEntry->path_bit.scenery_tab_id = 0xFF;
|
|
|
|
if (*extendedEntryData != 0xFF) {
|
|
|
|
uint8 entry_type, entry_index;
|
|
|
|
if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)){
|
|
|
|
sceneryEntry->path_bit.scenery_tab_id = entry_index;
|
2015-02-25 15:06:29 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
extendedEntryData += sizeof(rct_object_entry);
|
|
|
|
sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData);
|
2015-03-01 18:45:45 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
2015-03-01 18:45:45 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
2015-02-25 15:52:19 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_path_bit_unload(void *objectEntry)
|
2015-03-01 22:59:30 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
sceneryEntry->name = 0;
|
|
|
|
sceneryEntry->image = 0;
|
|
|
|
sceneryEntry->path_bit.scenery_tab_id = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_path_bit_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
if (sceneryEntry->path_bit.price <= 0) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_path_bit_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry;
|
|
|
|
gfx_draw_sprite(dpi, sceneryEntry->image, x - 22, y - 24, 0);
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_path_bit_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_path_bit_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_path_bit_load,
|
|
|
|
object_type_path_bit_unload,
|
|
|
|
object_type_path_bit_test,
|
|
|
|
object_type_path_bit_paint,
|
|
|
|
object_type_path_bit_desc
|
|
|
|
};
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Scenery Set (rct2: 0x006B93AA)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_scenery_set_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_scenery_set_entry));
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
scenerySetEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_SCENERY_SETS, entryIndex, 0);
|
|
|
|
|
|
|
|
rct_object_entry *entryObjects = NULL;
|
|
|
|
uint8 *eax = RCT2_GLOBAL(0x9ADAF4, uint8*);
|
|
|
|
if ((uint32)eax != 0xFFFFFFFF){
|
|
|
|
*((uint16*)eax) = 0;
|
|
|
|
entryObjects = (rct_object_entry*)(eax + 2);
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
scenerySetEntry->entry_count = 0;
|
|
|
|
scenerySetEntry->var_107 = 0;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
for (; *extendedEntryData != 0xFF; extendedEntryData += sizeof(rct_object_entry)) {
|
|
|
|
scenerySetEntry->var_107++;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (entryObjects != NULL){
|
|
|
|
memcpy(entryObjects, extendedEntryData, sizeof(rct_object_entry));
|
|
|
|
entryObjects++;
|
|
|
|
(*(eax + 1))++;
|
|
|
|
}
|
|
|
|
uint8 entry_type;
|
|
|
|
uint8 entry_index = 0;
|
|
|
|
if (!find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index))
|
|
|
|
continue;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
uint16 scenery_entry = entry_index;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
switch (entry_type){
|
|
|
|
case OBJECT_TYPE_SMALL_SCENERY:
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_LARGE_SCENERY:
|
|
|
|
scenery_entry |= 0x300;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_WALLS:
|
|
|
|
scenery_entry |= 0x200;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_PATH_BITS:
|
|
|
|
scenery_entry |= 0x100;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
scenery_entry |= 0x400;
|
|
|
|
break;
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
|
|
|
|
scenerySetEntry->scenery_entries[scenerySetEntry->entry_count++] = scenery_entry;
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
|
|
|
|
extendedEntryData++;
|
|
|
|
scenerySetEntry->image = object_chunk_load_image_directory(&extendedEntryData);
|
|
|
|
|
|
|
|
return true;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_scenery_set_unload(void *objectEntry)
|
2015-03-01 22:59:30 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry;
|
|
|
|
scenerySetEntry->name = 0;
|
|
|
|
scenerySetEntry->image = 0;
|
|
|
|
scenerySetEntry->entry_count = 0;
|
|
|
|
scenerySetEntry->var_107 = 0;
|
|
|
|
memset(scenerySetEntry->scenery_entries, 0, 256);
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_scenery_set_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_scenery_set_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry;
|
|
|
|
int imageId = scenerySetEntry->image + 0x20600001;
|
|
|
|
gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0);
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_scenery_set_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_scenery_set_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_scenery_set_load,
|
|
|
|
object_type_scenery_set_unload,
|
|
|
|
object_type_scenery_set_test,
|
|
|
|
object_type_scenery_set_paint,
|
|
|
|
object_type_scenery_set_desc
|
|
|
|
};
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Park Entrance (rct2: 0x00666E42)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
bool object_type_park_entrance_load(void *objectEntry, uint32 entryIndex)
|
|
|
|
{
|
|
|
|
rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry;
|
|
|
|
uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_entrance_type));
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
entranceType->string_idx = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PARK_ENTRANCE, entryIndex, 0);
|
|
|
|
entranceType->image_id = object_chunk_load_image_directory(&extendedEntryData);
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x9ADAF4, uint16*) = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_park_entrance_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry;
|
|
|
|
entranceType->string_idx = 0;
|
|
|
|
entranceType->image_id = 0;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_park_entrance_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_park_entrance_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry;
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-14 21:09:56 +01:00
|
|
|
rct_drawpixelinfo clipDPI;
|
|
|
|
if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) {
|
2016-01-06 23:13:49 +01:00
|
|
|
return;
|
2015-03-04 22:22:27 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = entranceType->image_id;
|
2016-01-14 21:09:56 +01:00
|
|
|
gfx_draw_sprite(&clipDPI, imageId + 1, 24, 68, 0);
|
|
|
|
gfx_draw_sprite(&clipDPI, imageId, 56, 84, 0);
|
|
|
|
gfx_draw_sprite(&clipDPI, imageId + 2, 88, 100, 0);
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_park_entrance_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2015-03-01 22:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_park_entrance_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_park_entrance_load,
|
|
|
|
object_type_park_entrance_unload,
|
|
|
|
object_type_park_entrance_test,
|
|
|
|
object_type_park_entrance_paint,
|
|
|
|
object_type_park_entrance_desc
|
|
|
|
};
|
2015-03-04 22:22:27 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Water (rct2: 0x006E6E2A)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_water_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_water_type *waterEntry = (rct_water_type*)objectEntry;
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
uint8 *pStringTable = (uint8*)((size_t)objectEntry + sizeof(rct_water_type));
|
|
|
|
waterEntry->string_idx = object_get_localised_text(&pStringTable, OBJECT_TYPE_WATER, entryIndex, 0);
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
int imageId = object_chunk_load_image_directory(&pStringTable);
|
|
|
|
waterEntry->image_id = imageId;
|
|
|
|
waterEntry->var_06 = imageId + 1;
|
|
|
|
waterEntry->var_0A = imageId + 4;
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x009ADAF4, uint32) != 0xFFFFFFFF) {
|
|
|
|
*RCT2_GLOBAL(0x009ADAF4, uint16*) = 0;
|
2015-03-01 19:08:36 +01:00
|
|
|
}
|
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x009ADAFD, uint8) == 0) {
|
|
|
|
load_palette();
|
|
|
|
gfx_invalidate_screen();
|
2015-03-01 19:08:36 +01:00
|
|
|
}
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_water_unload(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_water_type *waterEntry = (rct_water_type*)objectEntry;
|
|
|
|
waterEntry->string_idx = 0;
|
|
|
|
waterEntry->image_id = 0;
|
|
|
|
waterEntry->var_06 = 0;
|
|
|
|
waterEntry->var_0A = 0;
|
|
|
|
}
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_water_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
return true;
|
2015-02-25 15:06:29 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_water_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2015-02-25 15:24:01 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
// Write (no image)
|
|
|
|
gfx_draw_string_centred(dpi, 3326, x, y, 0, NULL);
|
|
|
|
}
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_water_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
2016-01-07 20:12:59 +01:00
|
|
|
return STR_NONE;
|
2016-01-06 23:13:49 +01:00
|
|
|
}
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_water_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_water_load,
|
|
|
|
object_type_water_unload,
|
|
|
|
object_type_water_test,
|
|
|
|
object_type_water_paint,
|
|
|
|
object_type_water_desc
|
|
|
|
};
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stex (rct2: 0x0066B355)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_stex_load(void *objectEntry, uint32 entryIndex)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry;
|
|
|
|
uint8 *stringTable = (uint8*)((size_t)objectEntry + (size_t)0x08);
|
|
|
|
|
|
|
|
stexEntry->scenario_name = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 0);
|
|
|
|
stexEntry->park_name = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 1);
|
|
|
|
stexEntry->details = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 2);
|
2015-03-01 22:06:51 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
if (RCT2_GLOBAL(0x9ADAF4, int) != -1) {
|
|
|
|
RCT2_GLOBAL(0x9ADAF4, uint16*)[0] = 0;
|
2015-02-25 15:24:01 +01:00
|
|
|
}
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-06 23:13:49 +01:00
|
|
|
return true;
|
2015-02-25 15:24:01 +01:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_stex_unload(void *objectEntry)
|
2015-02-25 15:06:29 +01:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry;
|
|
|
|
stexEntry->scenario_name = 0;
|
|
|
|
stexEntry->park_name = 0;
|
|
|
|
stexEntry->details = 0;
|
|
|
|
}
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static bool object_type_stex_test(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static void object_type_stex_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
// Write (no image)
|
|
|
|
gfx_draw_string_centred(dpi, 3326, x, y, 0, NULL);
|
|
|
|
}
|
2015-03-01 19:08:36 +01:00
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
static rct_string_id object_type_stex_desc(void *objectEntry)
|
2016-01-06 23:13:49 +01:00
|
|
|
{
|
|
|
|
rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry;
|
2016-01-07 20:12:59 +01:00
|
|
|
return stexEntry->details;
|
2014-08-14 19:35:19 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable object_type_stex_vtable[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_stex_load,
|
|
|
|
object_type_stex_unload,
|
|
|
|
object_type_stex_test,
|
|
|
|
object_type_stex_paint,
|
|
|
|
object_type_stex_desc
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
static const object_type_vtable * const object_type_vtables[] = {
|
2016-01-06 23:13:49 +01:00
|
|
|
object_type_ride_vtable,
|
|
|
|
object_type_small_scenery_vtable,
|
|
|
|
object_type_large_scenery_vtable,
|
|
|
|
object_type_wall_vtable,
|
|
|
|
object_type_banner_vtable,
|
|
|
|
object_type_path_vtable,
|
|
|
|
object_type_path_bit_vtable,
|
|
|
|
object_type_scenery_set_vtable,
|
|
|
|
object_type_park_entrance_vtable,
|
|
|
|
object_type_water_vtable,
|
|
|
|
object_type_stex_vtable
|
|
|
|
};
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
bool object_load(int type, void *objectEntry, uint32 entryIndex)
|
2014-05-24 23:14:42 +02:00
|
|
|
{
|
2016-01-06 23:13:49 +01:00
|
|
|
assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT);
|
2016-01-07 20:01:19 +01:00
|
|
|
const object_type_vtable *vtable = object_type_vtables[type];
|
|
|
|
return vtable->load(objectEntry, entryIndex) ? 0 : 1;
|
|
|
|
}
|
2016-01-06 23:13:49 +01:00
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
void object_unload(int type, void *objectEntry)
|
|
|
|
{
|
|
|
|
assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT);
|
2016-01-06 23:13:49 +01:00
|
|
|
const object_type_vtable *vtable = object_type_vtables[type];
|
2016-01-07 20:01:19 +01:00
|
|
|
vtable->unload(objectEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool object_test(int type, void *objectEntry)
|
|
|
|
{
|
|
|
|
assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT);
|
|
|
|
const object_type_vtable *vtable = object_type_vtables[type];
|
|
|
|
return vtable->test(objectEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void object_paint(int type, void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y)
|
|
|
|
{
|
|
|
|
assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT);
|
|
|
|
const object_type_vtable *vtable = object_type_vtables[type];
|
|
|
|
vtable->paint(objectEntry, dpi, x, y);
|
|
|
|
}
|
|
|
|
|
2016-01-07 20:12:59 +01:00
|
|
|
rct_string_id object_desc(int type, void *objectEntry)
|
2016-01-07 20:01:19 +01:00
|
|
|
{
|
|
|
|
assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT);
|
|
|
|
const object_type_vtable *vtable = object_type_vtables[type];
|
2016-01-07 20:12:59 +01:00
|
|
|
return vtable->desc(objectEntry);
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-02-25 15:06:29 +01:00
|
|
|
*
|
2014-05-26 18:59:42 +02:00
|
|
|
* rct2: 0x006A9428
|
|
|
|
*/
|
|
|
|
int object_get_scenario_text(rct_object_entry *entry)
|
|
|
|
{
|
2016-01-06 21:41:21 +01:00
|
|
|
rct_object_entry *installedObject = gInstalledObjects;
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
installedObject = object_list_find(entry);
|
2015-08-04 22:39:44 +02:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
if (installedObject == NULL){
|
|
|
|
log_error("Object not found: %.8s", entry->name);
|
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2015-08-04 22:39:44 +02:00
|
|
|
char path[MAX_PATH];
|
2015-03-07 10:44:34 +01:00
|
|
|
char *objectPath = (char*)installedObject + 16;
|
2015-12-22 16:31:51 +01:00
|
|
|
substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath);
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
rct_object_entry openedEntry;
|
2015-08-29 14:12:52 +02:00
|
|
|
SDL_RWops* rw = SDL_RWFromFile(path, "rb");
|
2015-07-05 06:36:25 +02:00
|
|
|
if (rw != NULL) {
|
|
|
|
SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1);
|
2015-03-07 10:44:34 +01:00
|
|
|
if (object_entry_compare(&openedEntry, entry)) {
|
|
|
|
|
|
|
|
// Skip over the object entry
|
|
|
|
char *pos = (char*)installedObject + sizeof(rct_object_entry);
|
|
|
|
// Skip file name
|
|
|
|
while (*pos++);
|
|
|
|
|
|
|
|
// Read chunk
|
|
|
|
int chunkSize = *((uint32*)pos);
|
|
|
|
|
2015-10-19 20:27:27 +02:00
|
|
|
uint8 *chunk;
|
2015-03-07 10:44:34 +01:00
|
|
|
if (chunkSize == 0xFFFFFFFF) {
|
2016-01-07 23:09:58 +01:00
|
|
|
chunk = (uint8*)malloc(0x600000);
|
2015-07-05 06:36:25 +02:00
|
|
|
chunkSize = sawyercoding_read_chunk(rw, chunk);
|
2015-03-07 10:44:34 +01:00
|
|
|
chunk = realloc(chunk, chunkSize);
|
|
|
|
}
|
|
|
|
else {
|
2016-01-07 23:09:58 +01:00
|
|
|
chunk = (uint8*)malloc(chunkSize);
|
2015-07-05 06:36:25 +02:00
|
|
|
sawyercoding_read_chunk(rw, chunk);
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWclose(rw);
|
2015-03-07 10:44:34 +01:00
|
|
|
|
|
|
|
// Calculate and check checksum
|
|
|
|
if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) {
|
|
|
|
log_error("Opened object failed calculated checksum.");
|
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 2;
|
|
|
|
free(chunk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-07 20:01:19 +01:00
|
|
|
if (!object_test(openedEntry.flags & 0x0F, chunk)) {
|
2015-03-07 10:44:34 +01:00
|
|
|
// This is impossible for STEX entries to fail.
|
2016-01-06 08:58:56 +01:00
|
|
|
log_error("Opened object failed paint test.");
|
2015-03-07 10:44:34 +01:00
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 3;
|
|
|
|
free(chunk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the real total images.
|
|
|
|
int total_no_images = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32);
|
|
|
|
|
|
|
|
// This is being changed to force the images to be loaded into a different
|
|
|
|
// image id.
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = 0x726E;
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, uint32) = (int)chunk;
|
|
|
|
// Not used anywhere.
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_OBJECT, rct_object_entry) = openedEntry;
|
|
|
|
|
|
|
|
// Tell text to be loaded into a different address
|
|
|
|
RCT2_GLOBAL(0x009ADAFC, uint8) = 255;
|
2015-09-07 23:05:36 +02:00
|
|
|
memcpy(gTempObjectLoadName, openedEntry.name, 8);
|
2015-03-07 10:44:34 +01:00
|
|
|
// Not used??
|
|
|
|
RCT2_GLOBAL(0x009ADAFD, uint8) = 1;
|
2016-01-07 20:01:19 +01:00
|
|
|
object_load(openedEntry.flags & 0x0F, chunk, 0);
|
2015-03-07 10:44:34 +01:00
|
|
|
// Tell text to be loaded into normal address
|
|
|
|
RCT2_GLOBAL(0x009ADAFC, uint8) = 0;
|
|
|
|
// Not used??
|
|
|
|
RCT2_GLOBAL(0x009ADAFD, uint8) = 0;
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = total_no_images;
|
|
|
|
return 1;
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
2015-03-07 10:44:34 +01:00
|
|
|
log_error("Opened object didn't match.");
|
2015-07-05 06:36:25 +02:00
|
|
|
SDL_RWclose(rw);
|
2015-03-07 10:44:34 +01:00
|
|
|
return 0;
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
2015-03-07 10:44:34 +01:00
|
|
|
log_error("File failed to open.");
|
2014-05-26 18:59:42 +02:00
|
|
|
RCT2_GLOBAL(0x00F42BD9, uint8) = 0;
|
2014-05-24 23:14:42 +02:00
|
|
|
return 0;
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-02-25 15:06:29 +01:00
|
|
|
*
|
2014-05-26 18:59:42 +02:00
|
|
|
* rct2: 0x006A982D
|
|
|
|
*/
|
|
|
|
void object_free_scenario_text()
|
|
|
|
{
|
2015-03-07 10:44:34 +01:00
|
|
|
if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) != NULL) {
|
2015-06-27 11:30:33 +02:00
|
|
|
free(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*));
|
2015-03-07 10:44:34 +01:00
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) = NULL;
|
2014-05-26 18:59:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int object_get_length(rct_object_entry *entry)
|
|
|
|
{
|
|
|
|
return (int)object_get_next(entry) - (int)entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
rct_object_entry *object_get_next(rct_object_entry *entry)
|
|
|
|
{
|
2014-11-30 22:16:36 +01:00
|
|
|
uint8 *pos = (uint8*)entry;
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2014-09-27 13:59:07 +02:00
|
|
|
// Skip sizeof(rct_object_entry)
|
2014-05-26 18:59:42 +02:00
|
|
|
pos += 16;
|
|
|
|
|
|
|
|
// Skip filename
|
2014-12-07 22:58:19 +01:00
|
|
|
while (*pos++);
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2015-03-01 18:45:45 +01:00
|
|
|
// Skip no of images
|
2014-05-26 18:59:42 +02:00
|
|
|
pos += 4;
|
|
|
|
|
|
|
|
// Skip name
|
2014-12-07 22:58:19 +01:00
|
|
|
while (*pos++);
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2014-09-27 13:59:07 +02:00
|
|
|
// Skip size of chunk
|
2014-05-26 18:59:42 +02:00
|
|
|
pos += 4;
|
|
|
|
|
2015-06-15 21:52:04 +02:00
|
|
|
// Skip required objects
|
2015-04-12 23:26:15 +02:00
|
|
|
pos += *pos * 16 + 1;
|
2014-05-26 18:59:42 +02:00
|
|
|
|
|
|
|
// Skip theme objects
|
2015-04-12 23:26:15 +02:00
|
|
|
pos += *pos * 16 + 1;
|
2014-05-26 18:59:42 +02:00
|
|
|
|
2015-08-04 22:39:44 +02:00
|
|
|
// Skip
|
2014-05-26 18:59:42 +02:00
|
|
|
pos += 4;
|
|
|
|
|
|
|
|
return (rct_object_entry*)pos;
|
2015-02-11 19:54:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char *object_get_name(rct_object_entry *entry)
|
|
|
|
{
|
|
|
|
uint8 *pos = (uint8*)entry;
|
|
|
|
|
|
|
|
// Skip sizeof(rct_object_entry)
|
|
|
|
pos += 16;
|
|
|
|
|
|
|
|
// Skip filename
|
|
|
|
while (*pos++);
|
|
|
|
|
2015-03-07 10:44:34 +01:00
|
|
|
// Skip no of images
|
2015-02-11 19:54:31 +01:00
|
|
|
pos += 4;
|
|
|
|
|
2015-10-19 20:27:27 +02:00
|
|
|
return (char *)pos;
|
2015-06-24 12:41:19 +02:00
|
|
|
}
|