Compare commits
7 Commits
3cb276b19f
...
9da37c198e
Author | SHA1 | Date |
---|---|---|
Xavier Del Campo Romero | 9da37c198e | |
Xavier Del Campo Romero | 8ddea5eef5 | |
Xavier Del Campo Romero | 992e7fb935 | |
Xavier Del Campo Romero | 5ac01ff845 | |
Xavier Del Campo Romero | d140dcd278 | |
Xavier Del Campo Romero | c831272f29 | |
Xavier Del Campo Romero | 7c1795401b |
|
@ -1,22 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
option(PS1_BUILD "Build for the original Sony Playstation" OFF)
|
||||
option(HOST_BUILD "Build for host platform using SDL-1.2" OFF)
|
||||
option(WIN9X_BUILD "Build for Win9x using SDL-1.2" OFF)
|
||||
|
||||
if(NOT PS1_BUILD AND NOT HOST_BUILD AND NOT WIN9X_BUILD)
|
||||
message(STATUS "Assuming native build. "
|
||||
"Please use one of the available options in CMakeLists.txt to "
|
||||
"cross-compile for a specific target.")
|
||||
set(HOST_BUILD ON)
|
||||
endif()
|
||||
|
||||
if(PS1_BUILD)
|
||||
include("cmake/ps1-toolchain.cmake")
|
||||
elseif(WIN9X_BUILD)
|
||||
include("cmake/win9x-toolchain.cmake")
|
||||
endif()
|
||||
|
||||
set(TOOLS_PREFIX ${CMAKE_BINARY_DIR}/tools)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(tools
|
||||
|
@ -26,6 +9,14 @@ ExternalProject_Add(tools
|
|||
|
||||
project(rts)
|
||||
|
||||
if(CMAKE_TOOLCHAIN_FILE MATCHES "ps1")
|
||||
set(PS1_BUILD 1)
|
||||
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "win9x")
|
||||
set(WIN9X_BUILD 1)
|
||||
else()
|
||||
set(HOST_BUILD 1)
|
||||
endif()
|
||||
|
||||
add_executable(${PROJECT_NAME} "src/main.c")
|
||||
set(cdroot ${CMAKE_BINARY_DIR}/cdimg)
|
||||
# Avoid C11 since it is not supported by the i386-mingw32 toolchain.
|
||||
|
|
51
README.md
51
README.md
|
@ -14,11 +14,15 @@ in the likes of several other entries from the mid 90's.
|
|||
The following platforms are either supported or support is expected in
|
||||
the future:
|
||||
|
||||
- Sony PlayStation 1, using a forked version of
|
||||
- Sony® PlayStation® 1, using a forked version of
|
||||
[PSXSDK](https://git.disroot.org/xavi92/psxsdk).
|
||||
- Microsoft Win9x, using a `i386-mingw32` cross-toolchain and SDL-1.2.
|
||||
- Modern Unix-like operating systems such as GNU/Linux or *BSD, using
|
||||
SDL-1.2 (if available). Possibly modern Microsoft Windows versions, too.
|
||||
- Microsoft® Win9x, using a `i386-mingw32` cross-toolchain and SDL-1.2.
|
||||
A `i386-mingw32` cross-toolchain must be already available on the
|
||||
system.
|
||||
- POSIX-compliant operating systems such as GNU/Linux® or *BSD, using
|
||||
SDL-1.2 (if available).
|
||||
- Possibly, modern Microsoft® Windows® versions, too (currently
|
||||
untested).
|
||||
|
||||
## Design goals
|
||||
|
||||
|
@ -29,11 +33,15 @@ between platforms without modifications.
|
|||
- Use modern CMake features for a simplified build process and
|
||||
availability of the `compile_commands.json` database.
|
||||
- Implement any multiplayer capabilities provided by the platform.
|
||||
- Support a wide range of screen resolutions, even portrait resolutions
|
||||
typically used by mobile platforms.
|
||||
- And, above all, provide a fun game that can run even on low-end
|
||||
hardware.
|
||||
|
||||
## Building from source
|
||||
|
||||
### Native build
|
||||
|
||||
A native version of **RTS** can be built using the typical CMake build
|
||||
process:
|
||||
|
||||
|
@ -41,21 +49,25 @@ process:
|
|||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j$(nproc --all)
|
||||
```
|
||||
|
||||
The following options can be otherwise defined:
|
||||
### Cross-compilation
|
||||
|
||||
- `PS1_BUILD`: builds for Sony Playstation 1
|
||||
- `HOST_BUILD`: builds for the host operating system using SDL-1.2
|
||||
- `WIN9X_BUILD`: builds for Microsoft Win9x operating systems using
|
||||
SDL-1.2. A `i386-mingw32` cross-toolchain must be available.
|
||||
[`CMAKE_TOOLCHAIN_FILE`](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html)
|
||||
can be used to set up the cross-toolchain. Files labeled as
|
||||
`cmake/*-toolchain.cmake` can be used as values.
|
||||
|
||||
For example, the Sony PlayStation 1 version can be built using:
|
||||
#### Sony® PlayStation® 1
|
||||
|
||||
For example, the Sony® PlayStation® 1 version can be built using:
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DPS1_BUILD=1 -DVIDEO_MODE=VMODE_PAL
|
||||
cmake .. \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../cmake/ps1-toolchain.cmake \
|
||||
-DVIDEO_MODE=VMODE_PAL # VMODE_NTSC can be otherwise used
|
||||
make -j$(nproc --all)
|
||||
```
|
||||
|
||||
|
@ -63,6 +75,18 @@ This will generate a `.bin`/`.cue` file pair in `build` that can be
|
|||
played on an emulator or burnt into a CD-r in order to play the game
|
||||
on real hardware.
|
||||
|
||||
#### Microsoft® Win9x
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/win9x-toolchain.cmake
|
||||
make -j$(nproc --all)
|
||||
```
|
||||
|
||||
A stripped version of the executable, as well as game assets, will be
|
||||
located in `build/cdimg`.
|
||||
|
||||
## License
|
||||
|
||||
Unless stated otherwise, **RTS** follows the license described by the
|
||||
|
@ -76,3 +100,8 @@ Derivative works have been also created from these files for this
|
|||
project, that are located inside the `res` directory. A `LICENSE`
|
||||
file is also provided to describe the relationship between the
|
||||
original and derived works.
|
||||
|
||||
## Copyright notice
|
||||
|
||||
Microsoft®, Linux®, Sony® and PlayStation® are registered trademarks of
|
||||
their respective owners.
|
||||
|
|
|
@ -3,10 +3,14 @@ if("$ENV{PSXSDK_PATH}" STREQUAL "")
|
|||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${cdroot})
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC $ENV{PSXSDK_PATH}/lib)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -lpsx -lfixmath)
|
||||
|
||||
add_library(psx STATIC IMPORTED)
|
||||
set_property(TARGET psx PROPERTY IMPORTED_LOCATION $ENV{PSXSDK_PATH}/lib/libpsx.a)
|
||||
target_include_directories(psx INTERFACE
|
||||
$ENV{PSXSDK_PATH}/include)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC psx fixmath)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC FIXMATH_FAST_SIN PSXSDK_DEBUG)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE . $ENV{PSXSDK_PATH}/include)
|
||||
add_custom_target(exe ALL elf2exe ${PROJECT_NAME}
|
||||
${cdroot}/${PROJECT_NAME}.exe -mark="A homebrew game created with PSXSDK"
|
||||
DEPENDS ${PROJECT_NAME})
|
||||
|
@ -15,8 +19,6 @@ add_custom_target(iso ALL mkisofs -o ${PROJECT_NAME}.iso -V ${PROJECT_NAME}
|
|||
set(license $ENV{PSXSDK_PATH}/share/licenses/infoeur.dat)
|
||||
add_custom_target(bin_cue ALL mkpsxiso ${PROJECT_NAME}.iso ${PROJECT_NAME}.bin
|
||||
${license} -s DEPENDS iso)
|
||||
# add_custom_target(libpsx ALL DEPENDS $ENV{PSXSDK_PATH}/lib/libpsx.a)
|
||||
# add_dependencies(${PROJECT_NAME} libpsx)
|
||||
|
||||
if(NOT EXISTS "${cdroot}/system.cnf")
|
||||
file(COPY "src/system.cnf" DESTINATION "${cdroot}")
|
||||
|
|
|
@ -35,6 +35,16 @@ struct camera
|
|||
{
|
||||
int last_w, last_h;
|
||||
} screen;
|
||||
|
||||
struct cursor_pos_rt
|
||||
{
|
||||
const struct cursor_pos
|
||||
{
|
||||
unsigned x, y;
|
||||
} *list;
|
||||
|
||||
size_t i, n;
|
||||
} rt;
|
||||
} cursor;
|
||||
};
|
||||
|
||||
|
@ -45,6 +55,7 @@ bool camera_translate(const struct camera *cam, const struct util_rect *dim, sho
|
|||
void cursor_init(struct cursor *c);
|
||||
bool cursor_collision(const struct camera *cam, const struct util_rect *d);
|
||||
void cursor_pos(const struct camera *cam, unsigned long *x, unsigned long *y);
|
||||
void cursor_set_pos_list(struct cursor *c, const struct cursor_pos *pos, size_t n);
|
||||
int cursor_render(const struct cursor *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -63,10 +63,21 @@ int cursor_render(const struct cursor *const c)
|
|||
|
||||
void cursor_init(struct cursor *const c)
|
||||
{
|
||||
c->x = c->x_init = (screen_w / 2) - CAMERA_CURSOR_WIDTH;
|
||||
c->y = c->y_init = (screen_h / 2) - CAMERA_CURSOR_HEIGHT;
|
||||
c->screen.last_w = screen_w;
|
||||
c->screen.last_h = screen_h;
|
||||
const unsigned int x = (screen_w / 2) - CAMERA_CURSOR_WIDTH,
|
||||
y = (screen_h / 2) - CAMERA_CURSOR_HEIGHT;
|
||||
|
||||
*c = (const struct cursor)
|
||||
{
|
||||
.x = x,
|
||||
.x_init = x,
|
||||
.y = y,
|
||||
.y_init = y,
|
||||
.screen =
|
||||
{
|
||||
.last_w = screen_w,
|
||||
.last_h = screen_h
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void camera_update_pos(struct camera *const cam)
|
||||
|
@ -103,6 +114,16 @@ bool camera_translate(const struct camera *const cam, const struct util_rect *co
|
|||
return true;
|
||||
}
|
||||
|
||||
void cursor_set_pos_list(struct cursor *const c,
|
||||
const struct cursor_pos *const pos, const size_t n)
|
||||
{
|
||||
c->rt = (const struct cursor_pos_rt)
|
||||
{
|
||||
.list = pos,
|
||||
.n = n
|
||||
};
|
||||
}
|
||||
|
||||
void camera_update(struct camera *const cam, const union peripheral *const p)
|
||||
{
|
||||
switch (p->common.type)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <gfx.h>
|
||||
#include <util.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void cursor_update(struct camera *const cam, const struct pad *const p)
|
||||
{
|
||||
|
@ -99,9 +100,61 @@ static void update_speed(struct camera *const cam, const struct pad *const p)
|
|||
cam->y_speed = 0;
|
||||
}
|
||||
|
||||
static enum pad_key get_ref_key(struct cursor_pos_rt *const rt,
|
||||
const size_t ref)
|
||||
{
|
||||
enum pad_key key;
|
||||
|
||||
const struct cursor_pos *const cur = &rt->list[rt->i],
|
||||
*const next = &rt->list[ref];
|
||||
const short nx = next->x - cur->x,
|
||||
ny = next->y - cur->y;
|
||||
|
||||
if (abs(nx) > abs(ny))
|
||||
key = nx > 0 ? PAD_KEY_RIGHT : PAD_KEY_LEFT;
|
||||
else
|
||||
key = ny > 0 ? PAD_KEY_DOWN : PAD_KEY_UP;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void cursor_update_fixed(struct camera *const cam,
|
||||
const struct pad *const p)
|
||||
{
|
||||
struct cursor *const c = &cam->cursor;
|
||||
struct cursor_pos_rt *const rt = &c->rt;
|
||||
const size_t next = rt->i + 1;
|
||||
|
||||
if (next < rt->n)
|
||||
{
|
||||
const enum pad_key key = get_ref_key(rt, next);
|
||||
|
||||
if (pad_justpressed(p, key))
|
||||
rt->i = next;
|
||||
}
|
||||
else if (rt->i)
|
||||
{
|
||||
const size_t prev = rt->i - 1;
|
||||
const enum pad_key key = get_ref_key(rt, prev);
|
||||
|
||||
if (pad_justpressed(p, key))
|
||||
rt->i = prev;
|
||||
}
|
||||
|
||||
const struct cursor_pos *const cur = &rt->list[rt->i];
|
||||
|
||||
c->x = cur->x;
|
||||
c->y = cur->y;
|
||||
}
|
||||
|
||||
void camera_update_pad(struct camera *const cam, const struct pad *const p)
|
||||
{
|
||||
cursor_update(cam, p);
|
||||
update_speed(cam, p);
|
||||
camera_update_pos(cam);
|
||||
if (cam->cursor.rt.list)
|
||||
cursor_update_fixed(cam, p);
|
||||
else
|
||||
{
|
||||
cursor_update(cam, p);
|
||||
update_speed(cam, p);
|
||||
camera_update_pos(cam);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,8 @@ int game(void)
|
|||
.n_res = sizeof res / sizeof *res
|
||||
};
|
||||
|
||||
exit |= human_player_update(&humans[i], &o);
|
||||
human_player_update(&humans[i], &o);
|
||||
exit |= humans[i].periph.common.exit;
|
||||
terrain_update(&map);
|
||||
|
||||
if (terrain_render(&map, &h->cam)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
add_library(peripheral "src/peripheral.c")
|
||||
target_include_directories(peripheral PUBLIC "inc")
|
||||
target_link_libraries(peripheral PUBLIC pad mouse keyboard util)
|
||||
target_link_libraries(peripheral PUBLIC pad mouse keyboard util PRIVATE gfx)
|
||||
|
|
|
@ -25,6 +25,7 @@ union peripheral
|
|||
struct peripheral_common
|
||||
{
|
||||
enum peripheral_type type;
|
||||
bool exit;
|
||||
} common;
|
||||
|
||||
struct peripheral_pad
|
||||
|
|
|
@ -1,8 +1,26 @@
|
|||
#include <peripheral.h>
|
||||
#include <gfx.h>
|
||||
#include <keyboard.h>
|
||||
#include <mouse.h>
|
||||
#include <pad.h>
|
||||
|
||||
static void update_pad_common(union peripheral *const p)
|
||||
{
|
||||
if (pad_justpressed(&p->pad.pad, PAD_KEY_EXIT))
|
||||
p->common.exit = true;
|
||||
}
|
||||
|
||||
static void update_kbm_common(union peripheral *const p)
|
||||
{
|
||||
struct peripheral_kbm *const kbm = &p->kbm;
|
||||
struct keyboard *const k = &kbm->keyboard;
|
||||
|
||||
if (keyboard_justpressed(k, &KEYBOARD_COMBO(KEYBOARD_KEY_EXIT)))
|
||||
p->common.exit = true;
|
||||
else if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_F11)))
|
||||
gfx_toggle_fullscreen();
|
||||
}
|
||||
|
||||
void peripheral_update(union peripheral *const p)
|
||||
{
|
||||
switch (p->common.type)
|
||||
|
@ -12,10 +30,12 @@ void peripheral_update(union peripheral *const p)
|
|||
case PERIPHERAL_TYPE_KEYBOARD_MOUSE:
|
||||
mouse_update(&p->kbm.mouse);
|
||||
keyboard_update(&p->kbm.keyboard);
|
||||
update_kbm_common(p);
|
||||
break;
|
||||
|
||||
case PERIPHERAL_TYPE_PAD:
|
||||
pad_update(&p->pad.pad);
|
||||
update_pad_common(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -39,3 +59,8 @@ void peripheral_init(const struct peripheral_cfg *const cfg,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int peripheral_get_default(struct peripheral_cfg *const cfg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ struct human_player
|
|||
};
|
||||
|
||||
int human_player_init(const struct human_player_cfg *cfg, struct human_player *h);
|
||||
bool human_player_update(struct human_player *h, struct player_others *o);
|
||||
void human_player_update(struct human_player *h, struct player_others *o);
|
||||
int human_player_render(const struct human_player *h, const struct player_others *o);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -524,16 +524,12 @@ static void update_target(struct human_player *const h)
|
|||
}
|
||||
}
|
||||
|
||||
static bool update_from_pad(struct human_player *const h,
|
||||
static void update_from_pad(struct human_player *const h,
|
||||
struct player_others *const o)
|
||||
{
|
||||
bool ret = false;
|
||||
struct pad *const p = &h->periph.pad.pad;
|
||||
|
||||
if (pad_justpressed(p, PAD_KEY_OPTIONS)
|
||||
|| pad_justpressed(p, PAD_KEY_EXIT))
|
||||
ret = true;
|
||||
else if (pad_justpressed(p, PAD_KEY_A))
|
||||
if (pad_justpressed(p, PAD_KEY_A))
|
||||
select_instances(h, o, false, false);
|
||||
else if (pad_justpressed(p, PAD_KEY_B))
|
||||
move_units(h, o);
|
||||
|
@ -541,28 +537,12 @@ static bool update_from_pad(struct human_player *const h,
|
|||
deselect_instances(h);
|
||||
else if (pad_justpressed(p, PAD_KEY_E))
|
||||
h->top_gui ^= true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool update_keyboard_mouse_common(const struct mouse *const m,
|
||||
const struct keyboard *const k)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (keyboard_justpressed(k, &KEYBOARD_COMBO(KEYBOARD_KEY_EXIT)))
|
||||
ret = true;
|
||||
else if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_F11)))
|
||||
gfx_toggle_fullscreen();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool update_from_touch(struct human_player *const h,
|
||||
static void update_from_touch(struct human_player *const h,
|
||||
struct player_others *const o)
|
||||
{
|
||||
struct mouse *const m = &h->periph.kbm.mouse;
|
||||
struct keyboard *const k = &h->periph.kbm.keyboard;
|
||||
struct peripheral_kbm *const kbm = &h->periph.kbm;
|
||||
bool *const pan = &h->cam.pan;
|
||||
|
||||
|
@ -587,11 +567,9 @@ static bool update_from_touch(struct human_player *const h,
|
|||
kbm->long_press = false;
|
||||
kbm->lp_t = 0;
|
||||
}
|
||||
|
||||
return update_keyboard_mouse_common(m, k);
|
||||
}
|
||||
|
||||
static bool update_from_keyboard_mouse(struct human_player *const h,
|
||||
static void update_from_keyboard_mouse(struct human_player *const h,
|
||||
struct player_others *const o)
|
||||
{
|
||||
struct mouse *const m = &h->periph.kbm.mouse;
|
||||
|
@ -608,14 +586,11 @@ static bool update_from_keyboard_mouse(struct human_player *const h,
|
|||
}
|
||||
else if (mouse_justreleased(m, MOUSE_BUTTON_RIGHT))
|
||||
move_units(h, o);
|
||||
|
||||
return update_keyboard_mouse_common(m, k);
|
||||
}
|
||||
|
||||
bool human_player_update(struct human_player *const h,
|
||||
void human_player_update(struct human_player *const h,
|
||||
struct player_others *const o)
|
||||
{
|
||||
bool ret = false;
|
||||
struct player *const p = &h->pl;
|
||||
|
||||
if (p->alive)
|
||||
|
@ -628,23 +603,21 @@ bool human_player_update(struct human_player *const h,
|
|||
switch (h->periph.common.type)
|
||||
{
|
||||
case PERIPHERAL_TYPE_PAD:
|
||||
ret = update_from_pad(h, o);
|
||||
update_from_pad(h, o);
|
||||
break;
|
||||
|
||||
case PERIPHERAL_TYPE_TOUCH:
|
||||
ret = update_from_touch(h, o);
|
||||
update_from_touch(h, o);
|
||||
break;
|
||||
|
||||
case PERIPHERAL_TYPE_KEYBOARD_MOUSE:
|
||||
ret = update_from_keyboard_mouse(h, o);
|
||||
update_from_keyboard_mouse(h, o);
|
||||
break;
|
||||
}
|
||||
|
||||
camera_update(&h->cam, &h->periph);
|
||||
player_update(p);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int render_target(const struct human_player *const h)
|
||||
|
|
Loading…
Reference in New Issue