#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
+#include <math.h>
+#include "../libsdl/print.h"
#include "../libcpu/m68k.h"
+#include "../libcpu/m68kcpu.h"
#include "../libcpu/execute.h"
#include "mercenary.h"
/* interrupt CPU execution at special break points and tell emulation what to do */
const struct cpu_stop mercenary_stop_at[] = {
- { 0x59a4e, STOP_AT_WAIT_VBL }, /* done with rendering, waiting for VBL */
- { 0x54c26, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key before showing menu line on benson */
- { 0x55438, STOP_AT_WAIT_VBL }, /* waiting for menu command */
- { 0x54c2e, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key while showing menu line on benson */
- { 0x55446, STOP_AT_WAIT_VBL }, /* after pressing 'RETURN' while game waits for other key to resume */
- { 0x51620, STOP_AT_WAIT_VBL }, /* after dying, waiting for VBL to fade out palette */
- { 0x0, STOP_AT_END }, /* end */
+ { 0x59a4e, STOP_AT_WAIT_VBL }, /* done with rendering, waiting for VBL */
+ { 0x54c26, STOP_AT_WAIT_INPUT }, /* after pressing 'HELP' key before showing menu line on benson */
+ { 0x55438, STOP_AT_WAIT_INPUT }, /* waiting for menu command */
+ { 0x54c2e, STOP_AT_WAIT_INPUT }, /* after pressing 'HELP' key while showing menu line on benson */
+ { 0x55446, STOP_AT_WAIT_INPUT }, /* after pressing 'RETURN' while game waits for other key to resume */
+ { 0x51620, STOP_AT_WAIT_VBL }, /* after dying, waiting for VBL to fade out palette */
+ { 0x596BC, STOP_AT_CLEAR_SCREEN1 }, /* clear the screen (here we know the color 8, this is wy we cannot do it earlier) */
+ { 0x596F4, STOP_AT_CLEAR_SCREEN1 },
+ { 0x59720, STOP_AT_CLEAR_SCREEN1 },
+ { 0x598A8, STOP_AT_CLEAR_SCREEN1 },
+ { 0x598E6, STOP_AT_CLEAR_SCREEN2 }, /* special case where we use color index 15 when we are flying (no raster split for ground color) */
+ { 0x59982, STOP_AT_CLEAR_SCREEN3 }, /* special case where we are in universe and do not have any ground */
+ { 0x55F2E, STOP_AT_DRAW_GROUND }, /* the ground is rendered. the color index is captured at CLEAR_SCREEN */
+ { 0x59710, STOP_AT_DRAW_GROUND }, /* at this point there is ground rendered, because game uses raster split for ground color, but we do render opengl */
+ { 0x531EA, STOP_AT_INFO_OBJECT_MOVING }, /* get ID and position of next object */
+ /* note: there a no fix objects in this game (no taxi/bus/intercity) */
+ { 0x534EA, STOP_AT_TAG_IS_OBJECT_1 }, /* indicates that the next tag is an object */
+ { 0x534EE, STOP_AT_TAG_IS_OBJECT_0 }, /* indicates that the tag of object was rendered */
+ { 0x5346E, STOP_AT_COORD_OBJECT }, /* object coordinates are ready */
+ { 0x534F6, STOP_AT_POLY_OBJECT_M2 }, /* object polygon is rendered */
+ { 0x534F0, STOP_AT_LINE_OBJECT }, /* object line is rendered */
+ { 0x5324A, STOP_AT_COORD_BEACON }, /* beacon's point coordinates are ready */
+ { 0x53284, STOP_AT_POINT_BEACON }, /* becon point is rendered */
+ { 0x53A00, STOP_AT_COORD_BUILDING_EXTERIOR }, /* building (house) coordinates are ready */
+ { 0x53A5C, STOP_AT_POLY_BUILDING_EXTERIOR }, /* building polygons are rendered */
+ { 0x53A54, STOP_AT_LINE_BUILDING_EXTERIOR }, /* lines of building, like radio tower on icarus */
+ { 0x5AA10, STOP_AT_COORD_BUILDING_INTERIOR }, /* building coordinates for interrior */
+ { 0x5B218, STOP_AT_POLY_BUILDING_INTERIOR1 }, /* floor of building will be rendered */
+ { 0x5B1BE, STOP_AT_POLY_BUILDING_INTERIOR2 }, /* ceiling of building will be rendered */
+ { 0x5B154, STOP_AT_POLY_BUILDING_INTERIOR3 }, /* ceiling of window/door will be rendered */
+ { 0x5B0E0, STOP_AT_POLY_BUILDING_INTERIOR4 }, /* floor of window will be rendered */
+ { 0x5B2DE, STOP_AT_POLY_BUILDING_INTERIOR1to4 }, /* ceiling/floor of building is rendered */
+ { 0x5AFF4, STOP_AT_POLY_BUILDING_INTERIOR5 }, /* part above window/door will be rendered */
+ { 0x5AF8A, STOP_AT_POLY_BUILDING_INTERIOR6 }, /* part below window will be rendered */
+ { 0x5B0BE, STOP_AT_POLY_BUILDING_INTERIOR5to6 }, /* part below/above window/door of building is rendered */
+ { 0x5B36C, STOP_AT_WALL_BUILDING }, /* a wall (between floor and ceiling/window/door) is rendered) */
+ { 0x4F462, STOP_AT_COORD_COMET }, /* comet's coordinates are ready */
+ { 0x4F496, STOP_AT_MATRIX_COMET }, /* what rotation matrix to use */
+ { 0x4F4B8, STOP_AT_POLY_COMET }, /* comet's horizontal polygon (without culling no need to render 0x4F4BC) */
+ { 0x4F4C0, STOP_AT_POLY_COMET }, /* comet's vertival polygon (without culling no need to render 0x4F4C4) */
+ { 0x54634, STOP_AT_COORD_LINE_ROADS }, /* road's line coordinates are ready */
+ { 0x54676, STOP_AT_LINE_ROADS }, /* road's and ground surface's polygon */
+ { 0x5469C, STOP_AT_LINE_ROADS },
+ { 0x546B2, STOP_AT_LINE_ROADS },
+ { 0x56496, STOP_AT_LINE_ROADS_CENTER }, /* center line of roads */
+ { 0x56442, STOP_AT_COORD_POLY_ROADS }, /* road's and ground surface's coordinates are ready */
+ { 0x5649C, STOP_AT_POLY_ROADS }, /* road's and ground surface's polygon */
+ { 0x53CB6, STOP_AT_COORD_TAGS }, /* coordinates for tags, like key's marking are ready */
+ /* note: there are no coordinates for large tags in this game (no faces) */
+ /* note: there are no STOP_AT_LINE_TAGS1 and STOP_AT_POLY_TAGS1 in this game(given color) */
+ { 0x53CFA, STOP_AT_LINE_TAGS2 }, /* tag's line is rendered (use last color) */
+ { 0x53CF0, STOP_AT_POLY_TAGS2 }, /* tag's polygon is rendered (use last color) */
+ { 0x52BF4, STOP_AT_COORD_PLANET }, /* planet's coordinates are ready (viewed from ground) */
+ { 0x52C1A, STOP_AT_MATRIX_PLANET }, /* what rotation matrix to use */
+ { 0x52756, STOP_AT_COORD_PLANET }, /* planet's coordinates are ready (viewed from universe) */
+ { 0x5277C, STOP_AT_MATRIX_PLANET }, /* what rotation matrix to use */
+ { 0x52C70, STOP_AT_DRAW_PLANET }, /* planet's sphere is rendered, D0 is color (viewed from ground) */
+ { 0x52B36, STOP_AT_DRAW_PLANET }, /* planet's sphere is rendered, D0 is color (viewed from universe) */
+ { 0x4F4E6, STOP_AT_DRAW_COMET }, /* comet's sphere is rendered */
+ { 0x50006, STOP_AT_DRAW_STARS_SPACE }, /* stars are rendered (viewed from universe) */
+ { 0x4FF4C, STOP_AT_DRAW_STARS_GROUND }, /* stars are rendered (viewed from ground) */
+ { 0x4FE24, STOP_AT_DRAW_STARS_FLYING }, /* stars are rendered (viewed from planet when flying) */
+ { 0x4FCAC, STOP_AT_DRAW_STARS_FLYING2 }, /* same as above, but stars when upside down (above zenit) */
+ { 0x50FC2, STOP_AT_DRAW_STARS_INTERSTELLAR }, /* interstellar star flight */
+ { 0x50BF4, STOP_AT_DRAW_SUN_INTERSTELLAR }, /* draw sun dot while flying interstellar */
+ { 0x50BB8, STOP_AT_CLEAR_SCREEN3 }, /* clear while flying interstellar */
+ { 0x563B8, STOP_AT_COORD_ISLANDS }, /* island's coordinates are ready */
+ { 0x56416, STOP_AT_POLY_ISLANDS }, /* island's polygon is rendered */
+ { 0x56410, STOP_AT_LINE_ISLANDS },
+ { 0x511FE, STOP_AT_DRAW_SIGHTS }, /* when sights are rendered */
+ { 0x5351A, STOP_AT_EXPLOSION }, /* explosion debris */
+ { 0x4C514, STOP_AT_EXPLOSION },
+ { 0x0, STOP_AT_END }, /* end */
};
extern const uint32_t mercenary2_hex[];
void mercenary_patch(void)
{
+ uint32_t address;
+
/* initial stack */
m68k_write_memory_32(0x00000, INITIAL_STACK);
/* reset vector */
m68k_write_memory_32(0x00004, RESET_VECTOR);
+ /* remove function that checks what stars are rendered when flying above plante
+ * instead of just rendering the necessary parts, both parts are always rendered:
+ * 1. stars from horizont up to zenith
+ * 2. stars from zenith up to horizon (upside down)
+ * we need that, so opengl rendering can use wider FOV without missing stars.
+ * the game will actually have no problem with it, except that it requires more cpu cycles
+ */
+ for (address = 0x4FD90; address < 0x4FDB6; address += 2)
+ m68k_write_memory_16(address, 0x4e71); /* nop */
+
/* remove wait for VBL */
m68k_write_memory_16(0x59a54, 0x4e71); /* nop */
/* reduce loop that waits for disk stepper to move */
if (m68k_read_memory_32(0x55398) != 0x0000091b) {
- fprintf(stderr, "expecting loop counter of 0x0000091b here, please fix!\n");
+ print_error("expecting loop counter of 0x0000091b here, please fix!\n");
exit(0);
}
m68k_write_memory_32(0x55398, 1);
/* reduce loop that waits for disk side change */
if (m68k_read_memory_32(0x54ffc) != 0x00000d02) {
- fprintf(stderr, "expecting loop counter of 0x00000d02 here, please fix!\n");
+ print_error("expecting loop counter of 0x00000d02 here, please fix!\n");
exit(0);
}
m68k_write_memory_32(0x54ffc, 1);
}
-uint32_t mercenary_palette(void)
+uint32_t mercenary_palette_view(void)
{
return m68k_read_memory_32(0x007c14);
}
+uint32_t mercenary_palette_render(void)
+{
+ return m68k_read_memory_32(0x007c18);
+}
+
+uint32_t mercenary_palette_predefined(void)
+{
+ return m68k_read_memory_32(0x007a0e);
+}
+
+uint32_t mercenary_palette_stars(void)
+{
+ return 0x500C4+66;
+}
+
+void mercenary_get_orientation(double *roll, double *pitch, double *yaw)
+{
+ int16_t r;
+
+ /* get observer's tilt, pitch, yaw */
+ r = (int16_t)(m68k_read_memory_16(0x007A9E) & 0x3ff);
+ *roll = (double)r / 1024.0 * 2 * M_PI;
+ r = (int16_t)((m68k_read_memory_16(0x007AA0) + 0x201) & 0x3ff); /* add one extra to make view leveled to ground */
+ *pitch = -(double)r / 1024.0 * 2 * M_PI;
+ r = (int16_t)((m68k_read_memory_16(0x007AA2) + 0x200) & 0x3ff);
+ *yaw = -(double)r / 1024.0 * 2 * M_PI;
+}
+
+void mercenary_get_orientation_raw(int16_t *pitch, uint16_t *yaw)
+{
+ *pitch = m68k_read_memory_16(0x007AA0);
+ *yaw = m68k_read_memory_16(0x007AA2);
+}
+
+void mercenary_get_orientation_planet(double *inclination, double *azimuth)
+{
+ int16_t r;
+
+ /* get plant's inclination and rotation */
+ r = (int16_t)((m68k_read_memory_16(0x42C70)) & 0x3ff);
+ *inclination = (double)r / 1024.0 * 2 * M_PI;
+ r = (int16_t)((m68k_read_memory_16(0x42C6c)) & 0x3ff);
+ *azimuth = -(double)r / 1024.0 * 2 * M_PI;
+}
+
+void mercenary_get_location(int32_t *east, int32_t *height, int32_t *north)
+{
+ *east = (int32_t)m68k_read_memory_32(0x7a92);
+ *height = (int32_t)m68k_read_memory_32(0x7a30);
+ *north = (int32_t)m68k_read_memory_32(0x7a9a);
+}
+
+void mercenary_get_object_info(int *id, int32_t *east, int32_t *height, int32_t *north)
+{
+ *id = REG_A[0];
+ *east = (int32_t)m68k_read_memory_32(REG_A[0] + 25512);
+ *height = (int32_t)m68k_read_memory_32(REG_A[0] + 26536);
+ *north = (int32_t)m68k_read_memory_32(REG_A[0] + 27560);
+}
+
+void mercenary_coord_building_interior(int16_t *east, int32_t *height1, int32_t *height2, int32_t *height3, int32_t *height4, int16_t *north)
+{
+ *east = (int16_t)m68k_read_memory_16(5698+REG_A[0]) - (int16_t)REG_A[2];
+ *north = (int16_t)m68k_read_memory_16(6722+REG_A[0]) - (int16_t)REG_A[3];
+ *height1 = -(int16_t)m68k_read_memory_16(0x79AC);
+ *height2 = (int16_t)m68k_read_memory_16(0x7B26) - (int16_t)m68k_read_memory_16(0x79AC);
+ *height3 = (int16_t)m68k_read_memory_16(0x7B28) - (int16_t)m68k_read_memory_16(0x79AC);
+ *height4 = (int16_t)m68k_read_memory_16(0x7B2A) - (int16_t)m68k_read_memory_16(0x79AC);
+}
+
+int mercenary_street_color_index(void)
+{
+ return (m68k_read_memory_16(0x7BE2) >> 5) & 0xf;
+}
+
+int mercenary_line_tags_index(void)
+{
+ return (m68k_read_memory_16(0x7BE2) >> 5) & 0xf;
+}
+
+uint16_t mercenary_poly_tags_color(void)
+{
+ return m68k_read_memory_16(0x7B06);
+}
+
+int mercenary_background_index(void)
+{
+ return m68k_read_memory_16(0x7AEA) >> 2;
+}
+
+uint32_t mercenary_planet_scale_index(void)
+{
+ return 24640;
+}
+
+uint32_t mercenary_star_table(void)
+{
+ return 0x005D8C0;
+}
+
+const char *mercenary_gamesavesuffix = ".m2save";
+