mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-07 14:28:12 +03:00
This implements SetPassCursor/GetPartsPassCursor HLL functions. The pass_cursor flag controls whether the cursor "passes through" a component to reach parts behind it. Key changes to input processing: - Iteration order changed from back-to-front to front-to-back for proper cursor consumption - MOUSE_ENTER / MOUSE_LEAVE now fire for all parts regardless of clickable - Click hit test uses clickable || !pass_cursor pre-filter - pass_cursor=false parts consume the cursor, preventing hover and click events from reaching parts behind them
718 lines
20 KiB
C
718 lines
20 KiB
C
/* Copyright (C) 2023 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
|
*
|
|
* This program 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "system4.h"
|
|
#include "system4/string.h"
|
|
|
|
#include "vm/page.h"
|
|
#include "parts.h"
|
|
#include "parts_internal.h"
|
|
#include "../hll/iarray.h"
|
|
|
|
#define CURRENT_SAVE_VERSION 3
|
|
|
|
static void save_parts_params(struct iarray_writer *w, struct parts_params *params)
|
|
{
|
|
iarray_write(w, params->z);
|
|
iarray_write_point(w, ¶ms->pos);
|
|
iarray_write(w, params->show);
|
|
iarray_write(w, params->alpha);
|
|
iarray_write_float(w, params->scale.x);
|
|
iarray_write_float(w, params->scale.y);
|
|
iarray_write_float(w, params->rotation.x);
|
|
iarray_write_float(w, params->rotation.y);
|
|
iarray_write_float(w, params->rotation.z);
|
|
iarray_write_color(w, ¶ms->add_color);
|
|
iarray_write_color(w, ¶ms->multiply_color);
|
|
}
|
|
|
|
static void load_parts_params(struct iarray_reader *r, struct parts_params *params)
|
|
{
|
|
params->z = iarray_read(r);
|
|
iarray_read_point(r, ¶ms->pos);
|
|
params->show = iarray_read(r);
|
|
params->alpha = iarray_read(r);
|
|
params->scale.x = iarray_read_float(r);
|
|
params->scale.y = iarray_read_float(r);
|
|
params->rotation.x = iarray_read_float(r);
|
|
params->rotation.y = iarray_read_float(r);
|
|
params->rotation.z = iarray_read_float(r);
|
|
iarray_read_color(r, ¶ms->add_color);
|
|
iarray_read_color(r, ¶ms->multiply_color);
|
|
}
|
|
|
|
static void save_parts_cg(struct iarray_writer *w, struct parts_cg *cg)
|
|
{
|
|
iarray_write(w, cg->no);
|
|
iarray_write_string_or_null(w, cg->name);
|
|
}
|
|
|
|
static void load_parts_cg(struct iarray_reader *r, struct parts *parts, struct parts_cg *cg)
|
|
{
|
|
int no = iarray_read(r);
|
|
struct string *name = iarray_read_string_or_null(r);
|
|
if (name) {
|
|
parts_cg_set(parts, cg, name);
|
|
} else if (no) {
|
|
parts_cg_set_by_index(parts, cg, no);
|
|
}
|
|
}
|
|
|
|
static void save_parts_text(struct iarray_writer *w, struct parts_text *text)
|
|
{
|
|
iarray_write(w, text->line_space);
|
|
iarray_write_text_style(w, &text->ts);
|
|
iarray_write(w, text->nr_lines);
|
|
for (unsigned i = 0; i < text->nr_lines; i++) {
|
|
struct string *s = parts_text_line_get(&text->lines[i]);
|
|
iarray_write_string(w, s);
|
|
free_string(s);
|
|
}
|
|
}
|
|
|
|
static void load_parts_text(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_text *text)
|
|
{
|
|
// FIXME: this won't accurately restore the text state if the text style
|
|
// varies per-character
|
|
text->line_space = iarray_read(r);
|
|
iarray_read_text_style(r, &text->ts);
|
|
|
|
text->nr_lines = 0;
|
|
text->lines = NULL;
|
|
text->cursor.x = 0;
|
|
text->cursor.y = 0;
|
|
|
|
int nr_lines = iarray_read(r);
|
|
for (unsigned i = 0; i < nr_lines; i++) {
|
|
struct string *line = iarray_read_string(r);
|
|
parts_text_append(parts, text, line);
|
|
}
|
|
}
|
|
|
|
static void save_parts_animation(struct iarray_writer *w, struct parts_animation *anim)
|
|
{
|
|
iarray_write_string_or_null(w, anim->cg_name);
|
|
iarray_write(w, anim->start_no);
|
|
iarray_write(w, anim->nr_frames);
|
|
iarray_write(w, anim->frame_time);
|
|
iarray_write(w, anim->elapsed);
|
|
iarray_write(w, anim->current_frame);
|
|
}
|
|
|
|
static void load_parts_animation(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_animation *anim)
|
|
{
|
|
struct string *cg_name = iarray_read_string_or_null(r);
|
|
int start_no = iarray_read(r);
|
|
int nr_frames = iarray_read(r);
|
|
int frame_time = iarray_read(r);
|
|
|
|
if (cg_name) {
|
|
parts_animation_set_cg(parts, anim, cg_name, start_no, nr_frames, frame_time);
|
|
free_string(cg_name);
|
|
} else {
|
|
parts_animation_set_cg_by_index(parts, anim, start_no, nr_frames, frame_time);
|
|
}
|
|
|
|
anim->elapsed = iarray_read(r);
|
|
anim->current_frame = iarray_read(r);
|
|
}
|
|
|
|
static void save_parts_numeral(struct iarray_writer *w, struct parts_numeral *num)
|
|
{
|
|
iarray_write(w, num->have_num);
|
|
iarray_write(w, num->num);
|
|
iarray_write(w, num->space);
|
|
iarray_write(w, num->show_comma);
|
|
iarray_write(w, num->length);
|
|
iarray_write(w, num->font_no);
|
|
}
|
|
|
|
static void load_parts_numeral(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_numeral *num)
|
|
{
|
|
num->have_num = iarray_read(r);
|
|
num->num = iarray_read(r);
|
|
num->space = iarray_read(r);
|
|
num->show_comma = iarray_read(r);
|
|
num->length = iarray_read(r);
|
|
num->font_no = iarray_read(r);
|
|
|
|
if (num->have_num)
|
|
parts_numeral_set_number(parts, num, num->num);
|
|
}
|
|
|
|
static void save_parts_gauge(struct iarray_writer *w, struct parts_gauge *gauge)
|
|
{
|
|
iarray_write(w, gauge->cg_no);
|
|
iarray_write_float(w, gauge->rate);
|
|
}
|
|
|
|
static void load_parts_gauge(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_gauge *gauge, bool vert)
|
|
{
|
|
gauge->cg_no = iarray_read(r);
|
|
gauge->rate = iarray_read_float(r);
|
|
|
|
if (gauge->cg_no >= 0)
|
|
parts_gauge_set_cg_by_index(parts, gauge, gauge->cg_no);
|
|
if (vert)
|
|
parts_vgauge_set_rate(parts, gauge, gauge->rate);
|
|
else
|
|
parts_hgauge_set_rate(parts, gauge, gauge->rate);
|
|
}
|
|
|
|
static void save_parts_cp_op(struct iarray_writer *w, struct parts_cp_op *op)
|
|
{
|
|
iarray_write(w, op->type);
|
|
switch (op->type) {
|
|
case PARTS_CP_CREATE:
|
|
case PARTS_CP_CREATE_PIXEL_ONLY:
|
|
iarray_write(w, op->create.w);
|
|
iarray_write(w, op->create.h);
|
|
break;
|
|
case PARTS_CP_CG:
|
|
iarray_write(w, op->cg.no);
|
|
break;
|
|
case PARTS_CP_FILL:
|
|
case PARTS_CP_FILL_ALPHA_COLOR:
|
|
case PARTS_CP_FILL_AMAP:
|
|
case PARTS_CP_FILL_WITH_ALPHA:
|
|
case PARTS_CP_DRAW_RECT:
|
|
iarray_write(w, op->fill.x);
|
|
iarray_write(w, op->fill.y);
|
|
iarray_write(w, op->fill.w);
|
|
iarray_write(w, op->fill.h);
|
|
iarray_write(w, op->fill.r);
|
|
iarray_write(w, op->fill.g);
|
|
iarray_write(w, op->fill.b);
|
|
iarray_write(w, op->fill.a);
|
|
break;
|
|
case PARTS_CP_DRAW_CUT_CG:
|
|
case PARTS_CP_COPY_CUT_CG:
|
|
iarray_write(w, op->cut_cg.cg_no);
|
|
iarray_write(w, op->cut_cg.dx);
|
|
iarray_write(w, op->cut_cg.dy);
|
|
iarray_write(w, op->cut_cg.dw);
|
|
iarray_write(w, op->cut_cg.dh);
|
|
iarray_write(w, op->cut_cg.sx);
|
|
iarray_write(w, op->cut_cg.sy);
|
|
iarray_write(w, op->cut_cg.sw);
|
|
iarray_write(w, op->cut_cg.sh);
|
|
iarray_write(w, op->cut_cg.interp_type);
|
|
break;
|
|
case PARTS_CP_DRAW_TEXT:
|
|
case PARTS_CP_COPY_TEXT:
|
|
iarray_write_string(w, op->text.text);
|
|
iarray_write(w, op->text.x);
|
|
iarray_write(w, op->text.y);
|
|
iarray_write(w, op->text.line_space);
|
|
iarray_write_text_style(w, &op->text.style);
|
|
break;
|
|
case PARTS_CP_GRAY_FILTER:
|
|
iarray_write(w, op->filter.x);
|
|
iarray_write(w, op->filter.y);
|
|
iarray_write(w, op->filter.w);
|
|
iarray_write(w, op->filter.h);
|
|
iarray_write(w, op->filter.full_size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static struct parts_cp_op *load_parts_cp_op(struct iarray_reader *r)
|
|
{
|
|
struct parts_cp_op *op = xcalloc(1, sizeof(struct parts_cp_op));
|
|
op->type = iarray_read(r);
|
|
switch (op->type) {
|
|
case PARTS_CP_CREATE:
|
|
case PARTS_CP_CREATE_PIXEL_ONLY:
|
|
op->create.w = iarray_read(r);
|
|
op->create.h = iarray_read(r);
|
|
break;
|
|
case PARTS_CP_CG:
|
|
op->cg.no = iarray_read(r);
|
|
break;
|
|
case PARTS_CP_FILL:
|
|
case PARTS_CP_FILL_ALPHA_COLOR:
|
|
case PARTS_CP_FILL_AMAP:
|
|
case PARTS_CP_FILL_WITH_ALPHA:
|
|
case PARTS_CP_DRAW_RECT:
|
|
op->fill.x = iarray_read(r);
|
|
op->fill.y = iarray_read(r);
|
|
op->fill.w = iarray_read(r);
|
|
op->fill.h = iarray_read(r);
|
|
op->fill.r = iarray_read(r);
|
|
op->fill.g = iarray_read(r);
|
|
op->fill.b = iarray_read(r);
|
|
op->fill.a = iarray_read(r);
|
|
break;
|
|
case PARTS_CP_DRAW_CUT_CG:
|
|
case PARTS_CP_COPY_CUT_CG:
|
|
op->cut_cg.cg_no = iarray_read(r);
|
|
op->cut_cg.dx = iarray_read(r);
|
|
op->cut_cg.dy = iarray_read(r);
|
|
op->cut_cg.dw = iarray_read(r);
|
|
op->cut_cg.dh = iarray_read(r);
|
|
op->cut_cg.sx = iarray_read(r);
|
|
op->cut_cg.sy = iarray_read(r);
|
|
op->cut_cg.sw = iarray_read(r);
|
|
op->cut_cg.sh = iarray_read(r);
|
|
op->cut_cg.interp_type = iarray_read(r);
|
|
break;
|
|
case PARTS_CP_DRAW_TEXT:
|
|
case PARTS_CP_COPY_TEXT:
|
|
op->text.text = iarray_read_string(r);
|
|
op->text.x = iarray_read(r);
|
|
op->text.y = iarray_read(r);
|
|
op->text.line_space = iarray_read(r);
|
|
iarray_read_text_style(r, &op->text.style);
|
|
break;
|
|
case PARTS_CP_GRAY_FILTER:
|
|
op->filter.x = iarray_read(r);
|
|
op->filter.y = iarray_read(r);
|
|
op->filter.w = iarray_read(r);
|
|
op->filter.h = iarray_read(r);
|
|
op->filter.full_size = !!iarray_read(r);
|
|
break;
|
|
}
|
|
return op;
|
|
}
|
|
|
|
static void save_parts_construction_process(struct iarray_writer *w,
|
|
struct parts_construction_process *cproc)
|
|
{
|
|
unsigned ops_count_pos = iarray_writer_pos(w);
|
|
iarray_write(w, 0); // size of ops list
|
|
|
|
unsigned ops_count = 0;
|
|
struct parts_cp_op *op;
|
|
TAILQ_FOREACH(op, &cproc->ops, entry) {
|
|
save_parts_cp_op(w, op);
|
|
ops_count++;
|
|
}
|
|
|
|
iarray_write_at(w, ops_count_pos, ops_count);
|
|
}
|
|
|
|
static void load_parts_construction_process(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_construction_process *cproc)
|
|
{
|
|
int ops_count = iarray_read(r);
|
|
for (int i = 0; i < ops_count; i++) {
|
|
struct parts_cp_op *op = load_parts_cp_op(r);
|
|
parts_add_cp_op(cproc, op);
|
|
}
|
|
parts_build_construction_process(parts, cproc);
|
|
}
|
|
|
|
static void save_parts_flash(struct iarray_writer *w, struct parts_flash *flash)
|
|
{
|
|
iarray_write_string_or_null(w, flash->name);
|
|
iarray_write(w, flash->stopped);
|
|
iarray_write(w, flash->current_frame);
|
|
}
|
|
|
|
static void load_parts_flash(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_flash *flash)
|
|
{
|
|
struct string *name = iarray_read_string_or_null(r);
|
|
parts_flash_load(parts, flash, name);
|
|
free_string(name);
|
|
flash->stopped = !!iarray_read(r);
|
|
parts_flash_seek(flash, iarray_read(r));
|
|
}
|
|
|
|
static void save_parts_flat(struct iarray_writer *w, struct parts_flat *flat)
|
|
{
|
|
iarray_write_string_or_null(w, flat->name);
|
|
}
|
|
|
|
static void load_parts_flat(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_flat *flat)
|
|
{
|
|
struct string *name = iarray_read_string_or_null(r);
|
|
parts_flat_load(parts, flat, name);
|
|
free_string(name);
|
|
flat->needs_advance = true;
|
|
}
|
|
|
|
static void save_parts_state(struct iarray_writer *w, struct parts_state *state)
|
|
{
|
|
iarray_write(w, state->type);
|
|
iarray_write(w, state->common.w);
|
|
iarray_write(w, state->common.h);
|
|
iarray_write_point(w, &state->common.origin_offset);
|
|
iarray_write_rectangle(w, &state->common.hitbox);
|
|
iarray_write_rectangle(w, &state->common.surface_area);
|
|
switch (state->type) {
|
|
case PARTS_UNINITIALIZED:
|
|
break;
|
|
case PARTS_CG:
|
|
save_parts_cg(w, &state->cg);
|
|
break;
|
|
case PARTS_TEXT:
|
|
save_parts_text(w, &state->text);
|
|
break;
|
|
case PARTS_ANIMATION:
|
|
save_parts_animation(w, &state->anim);
|
|
break;
|
|
case PARTS_NUMERAL:
|
|
save_parts_numeral(w, &state->num);
|
|
break;
|
|
case PARTS_HGAUGE:
|
|
case PARTS_VGAUGE:
|
|
save_parts_gauge(w, &state->gauge);
|
|
break;
|
|
case PARTS_CONSTRUCTION_PROCESS:
|
|
save_parts_construction_process(w, &state->cproc);
|
|
break;
|
|
case PARTS_FLASH:
|
|
save_parts_flash(w, &state->flash);
|
|
break;
|
|
case PARTS_FLAT:
|
|
save_parts_flat(w, &state->flat);
|
|
break;
|
|
case PARTS_MOVIE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void load_parts_state(struct iarray_reader *r, struct parts *parts,
|
|
struct parts_state *state)
|
|
{
|
|
parts_state_reset(state, iarray_read(r));
|
|
state->common.w = iarray_read(r);
|
|
state->common.h = iarray_read(r);
|
|
iarray_read_point(r, &state->common.origin_offset);
|
|
iarray_read_rectangle(r, &state->common.hitbox);
|
|
iarray_read_rectangle(r, &state->common.surface_area);
|
|
switch (state->type) {
|
|
case PARTS_UNINITIALIZED:
|
|
break;
|
|
case PARTS_CG:
|
|
load_parts_cg(r, parts, &state->cg);
|
|
break;
|
|
case PARTS_TEXT:
|
|
load_parts_text(r, parts, &state->text);
|
|
break;
|
|
case PARTS_ANIMATION:
|
|
load_parts_animation(r, parts, &state->anim);
|
|
break;
|
|
case PARTS_NUMERAL:
|
|
load_parts_numeral(r, parts, &state->num);
|
|
break;
|
|
case PARTS_HGAUGE:
|
|
load_parts_gauge(r, parts, &state->gauge, false);
|
|
break;
|
|
case PARTS_VGAUGE:
|
|
load_parts_gauge(r, parts, &state->gauge, true);
|
|
break;
|
|
case PARTS_CONSTRUCTION_PROCESS:
|
|
load_parts_construction_process(r, parts, &state->cproc);
|
|
break;
|
|
case PARTS_FLASH:
|
|
load_parts_flash(r, parts, &state->flash);
|
|
break;
|
|
case PARTS_FLAT:
|
|
load_parts_flat(r, parts, &state->flat);
|
|
break;
|
|
case PARTS_MOVIE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void save_parts_motion(struct iarray_writer *w, struct parts_motion *motion)
|
|
{
|
|
iarray_write(w, motion->type);
|
|
switch (motion->type) {
|
|
case PARTS_MOTION_POS:
|
|
iarray_write(w, motion->begin.x);
|
|
iarray_write(w, motion->begin.y);
|
|
iarray_write(w, motion->end.x);
|
|
iarray_write(w, motion->end.y);
|
|
break;
|
|
case PARTS_MOTION_ALPHA:
|
|
case PARTS_MOTION_CG:
|
|
case PARTS_MOTION_NUMERAL_NUMBER:
|
|
iarray_write(w, motion->begin.i);
|
|
iarray_write(w, motion->end.i);
|
|
break;
|
|
case PARTS_MOTION_HGAUGE_RATE:
|
|
case PARTS_MOTION_VGAUGE_RATE:
|
|
case PARTS_MOTION_MAG_X:
|
|
case PARTS_MOTION_MAG_Y:
|
|
case PARTS_MOTION_ROTATE_X:
|
|
case PARTS_MOTION_ROTATE_Y:
|
|
case PARTS_MOTION_ROTATE_Z:
|
|
iarray_write_float(w, motion->begin.f);
|
|
iarray_write_float(w, motion->end.f);
|
|
break;
|
|
case PARTS_MOTION_VIBRATION_SIZE:
|
|
iarray_write(w, motion->begin.x);
|
|
iarray_write(w, motion->begin.y);
|
|
break;
|
|
}
|
|
iarray_write(w, motion->begin_time);
|
|
iarray_write(w, motion->end_time);
|
|
}
|
|
|
|
static struct parts_motion *load_parts_motion(struct iarray_reader *r)
|
|
{
|
|
struct parts_motion *motion = xcalloc(1, sizeof(struct parts_motion));
|
|
motion->type = iarray_read(r);
|
|
switch (motion->type) {
|
|
case PARTS_MOTION_POS:
|
|
motion->begin.x = iarray_read(r);
|
|
motion->begin.y = iarray_read(r);
|
|
motion->end.x = iarray_read(r);
|
|
motion->end.y = iarray_read(r);
|
|
break;
|
|
case PARTS_MOTION_ALPHA:
|
|
case PARTS_MOTION_CG:
|
|
case PARTS_MOTION_NUMERAL_NUMBER:
|
|
motion->begin.i = iarray_read(r);
|
|
motion->end.i = iarray_read(r);
|
|
break;
|
|
case PARTS_MOTION_HGAUGE_RATE:
|
|
case PARTS_MOTION_VGAUGE_RATE:
|
|
case PARTS_MOTION_MAG_X:
|
|
case PARTS_MOTION_MAG_Y:
|
|
case PARTS_MOTION_ROTATE_X:
|
|
case PARTS_MOTION_ROTATE_Y:
|
|
case PARTS_MOTION_ROTATE_Z:
|
|
motion->begin.f = iarray_read_float(r);
|
|
motion->end.f = iarray_read_float(r);
|
|
break;
|
|
case PARTS_MOTION_VIBRATION_SIZE:
|
|
motion->begin.x = iarray_read(r);
|
|
motion->begin.y = iarray_read(r);
|
|
break;
|
|
}
|
|
motion->begin_time = iarray_read(r);
|
|
motion->end_time = iarray_read(r);
|
|
return motion;
|
|
}
|
|
|
|
static void save_parts(struct iarray_writer *w, struct parts *parts)
|
|
{
|
|
iarray_write(w, parts->no);
|
|
iarray_write(w, parts->state);
|
|
for (int i = 0; i < PARTS_NR_STATES; i++) {
|
|
save_parts_state(w, &parts->states[i]);
|
|
}
|
|
|
|
save_parts_params(w, &parts->local);
|
|
save_parts_params(w, &parts->global);
|
|
iarray_write(w, parts->parent ? parts->parent->no : -1);
|
|
iarray_write(w, parts->delegate_index);
|
|
iarray_write(w, parts->sprite_deform);
|
|
iarray_write(w, parts->clickable);
|
|
iarray_write(w, parts->on_cursor_sound);
|
|
iarray_write(w, parts->on_click_sound);
|
|
iarray_write(w, parts->origin_mode);
|
|
// XXX: no need to save pending parent since we called UpdateComponent first
|
|
iarray_write(w, parts->linked_to);
|
|
iarray_write(w, parts->linked_from);
|
|
iarray_write(w, parts->draw_filter);
|
|
iarray_write(w, parts->message_window);
|
|
iarray_write(w, parts->alpha_clipper_parts_no);
|
|
// TODO: once the Rance 9 save format stabilizes, bump save version
|
|
// and save unconditionally
|
|
if (parts_multi_controller) {
|
|
iarray_write(w, parts->controller_no);
|
|
iarray_write(w, parts->pass_cursor);
|
|
}
|
|
|
|
unsigned motion_count_pos = iarray_writer_pos(w);
|
|
iarray_write(w, 0); // size of motion list
|
|
|
|
unsigned motion_count = 0;
|
|
struct parts_motion *motion;
|
|
TAILQ_FOREACH(motion, &parts->motion, entry) {
|
|
save_parts_motion(w, motion);
|
|
motion_count++;
|
|
}
|
|
|
|
iarray_write_at(w, motion_count_pos, motion_count);
|
|
}
|
|
|
|
static void load_parts(struct iarray_reader *r, int version)
|
|
{
|
|
int no = iarray_read(r);
|
|
struct parts *parts = parts_get(no);
|
|
parts->state = iarray_read(r);
|
|
for (int i = 0; i < PARTS_NR_STATES; i++) {
|
|
load_parts_state(r, parts, &parts->states[i]);
|
|
}
|
|
|
|
load_parts_params(r, &parts->local);
|
|
load_parts_params(r, &parts->global);
|
|
parts->pending_parent = iarray_read(r);
|
|
parts->delegate_index = iarray_read(r);
|
|
parts->sprite_deform = iarray_read(r);
|
|
parts->clickable = iarray_read(r);
|
|
parts->on_cursor_sound = iarray_read(r);
|
|
parts->on_click_sound = iarray_read(r);
|
|
parts->origin_mode = iarray_read(r);
|
|
parts->linked_to = iarray_read(r);
|
|
parts->linked_from = iarray_read(r);
|
|
parts->draw_filter = iarray_read(r);
|
|
if (version > 0)
|
|
parts->message_window = iarray_read(r);
|
|
if (version > 2)
|
|
parts->alpha_clipper_parts_no = iarray_read(r);
|
|
// TODO: once the Rance 9 save format stabilizes, bump save version
|
|
// and load based on version check
|
|
if (parts_multi_controller) {
|
|
parts->controller_no = iarray_read(r);
|
|
parts->pass_cursor = iarray_read(r);
|
|
}
|
|
int motion_count = iarray_read(r);
|
|
for (int i = 0; i < motion_count; i++) {
|
|
struct parts_motion *motion = load_parts_motion(r);
|
|
parts_add_motion(parts, motion);
|
|
}
|
|
|
|
parts_list_resort(parts);
|
|
parts_component_dirty(parts);
|
|
parts_recalculate_hitbox(parts);
|
|
}
|
|
|
|
static void save_numeral_fonts(struct iarray_writer *w)
|
|
{
|
|
iarray_write(w, parts_nr_numeral_fonts);
|
|
for (int i = 0; i < parts_nr_numeral_fonts; i++) {
|
|
struct parts_numeral_font *font = &parts_numeral_fonts[i];
|
|
iarray_write(w, font->type);
|
|
iarray_write(w, font->cg_no);
|
|
for (int i = 0; i < 12; i++) {
|
|
iarray_write(w, font->width[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void load_numeral_fonts(struct iarray_reader *r)
|
|
{
|
|
parts_nr_numeral_fonts = iarray_read(r);
|
|
parts_numeral_fonts = xcalloc(parts_nr_numeral_fonts, sizeof(struct parts_numeral_font));
|
|
for (int i = 0; i < parts_nr_numeral_fonts; i++) {
|
|
struct parts_numeral_font *font = &parts_numeral_fonts[i];
|
|
font->type = iarray_read(r);
|
|
font->cg_no = iarray_read(r);
|
|
for (int i = 0; i < 12; i++) {
|
|
font->width[i] = iarray_read(r);
|
|
}
|
|
parts_numeral_font_init(font);
|
|
}
|
|
}
|
|
|
|
static bool parts_engine_save(struct page **buffer, bool save_hidden)
|
|
{
|
|
// get parts into clean state first
|
|
PE_UpdateComponent(0);
|
|
|
|
struct iarray_writer w;
|
|
iarray_init_writer(&w, "XPE");
|
|
iarray_write(&w, CURRENT_SAVE_VERSION);
|
|
if (CURRENT_SAVE_VERSION > 1)
|
|
save_numeral_fonts(&w);
|
|
|
|
// TODO: once the Rance 9 save format stabilizes, bump save version
|
|
// and save unconditionally
|
|
if (parts_multi_controller) {
|
|
iarray_write(&w, ctrl_stack.active);
|
|
iarray_write(&w, ctrl_stack.nr_controllers);
|
|
}
|
|
|
|
unsigned count_pos = iarray_writer_pos(&w);
|
|
iarray_write(&w, 0); // size of parts list
|
|
|
|
unsigned count = 0;
|
|
struct parts *parts;
|
|
PARTS_LIST_FOREACH(parts) {
|
|
if (!save_hidden && !parts->global.show)
|
|
continue;
|
|
save_parts(&w, parts);
|
|
count++;
|
|
}
|
|
|
|
iarray_write_at(&w, count_pos, count);
|
|
|
|
if (*buffer) {
|
|
delete_page_vars(*buffer);
|
|
free_page(*buffer);
|
|
}
|
|
*buffer = iarray_to_page(&w);;
|
|
iarray_free_writer(&w);
|
|
return true;
|
|
|
|
}
|
|
|
|
bool PE_SaveWithoutHideParts(struct page **buffer)
|
|
{
|
|
return parts_engine_save(buffer, false);
|
|
}
|
|
|
|
bool PE_Save(struct page **buffer)
|
|
{
|
|
return parts_engine_save(buffer, true);
|
|
}
|
|
|
|
bool PE_Load(struct page **buffer)
|
|
{
|
|
if (!(*buffer)) {
|
|
WARNING("savedata array is empty");
|
|
return false;
|
|
}
|
|
|
|
struct iarray_reader r;
|
|
if (!iarray_init_reader(&r, *buffer, "XPE")) {
|
|
WARNING("unrecognized savedata magic");
|
|
return false;
|
|
}
|
|
int version = iarray_read(&r);
|
|
if (version > CURRENT_SAVE_VERSION) {
|
|
WARNING("unrecognized savedata version");
|
|
return false;
|
|
}
|
|
|
|
parts_release_all();
|
|
|
|
if (version > 1)
|
|
load_numeral_fonts(&r);
|
|
|
|
// TODO: once the Rance 9 save format stabilizes, bump save version
|
|
// and load based on version check
|
|
if (parts_multi_controller) {
|
|
ctrl_stack.active = iarray_read(&r);
|
|
ctrl_stack.nr_controllers = iarray_read(&r);
|
|
}
|
|
|
|
int nr_parts = iarray_read(&r);
|
|
if (nr_parts < 0) {
|
|
WARNING("invalid parts count");
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < nr_parts; i++) {
|
|
load_parts(&r, version);
|
|
}
|
|
|
|
parts_engine_clean();
|
|
return true;
|
|
}
|