19 Commits

Author SHA1 Message Date
doylet 13af438612 fp: Make players unable to collide with each other 2023-10-20 21:06:56 +11:00
doylet 815d7aa808 fp: Solve the menu problem for multiple players 2023-10-20 21:01:26 +11:00
doylet 3e47bbd704 fp: Add first draft of 2 players 2023-10-20 00:20:41 +11:00
doylet 4b77b034f3 fp: Pull in submodule patches 2023-10-18 23:39:00 +11:00
doylet 49277a4b2d fp: Undo debug change disabling waves 2023-10-18 23:37:56 +11:00
doylet 5faf5948bf fp: Add attack icon for merchant 2023-10-18 23:37:28 +11:00
doylet 270e57acfc fp: Add different bindings for buildings+upgrades 2023-10-18 22:59:40 +11:00
doylet 5159763baa fp: Move the buy menu if it overlaps with player 2023-10-18 21:48:12 +11:00
doylet 49c80e60e8 fp: Simplify camera shake, don't modify main camera, square & cube intensity 2023-10-18 20:34:38 +11:00
Jojangles 4158674031 fp: Add camera shake 2023-10-18 10:28:15 +11:00
doylet 1de986b6ac fp: Add a hit confirmation visual marker 2023-10-18 00:19:09 +11:00
doylet 395e8dc58a fp: Fix camera OOB on startup 2023-10-17 23:56:56 +11:00
doylet 0044b05130 fp: Add camera smoothing movement 2023-10-17 23:49:20 +11:00
doylet 46bf26a7c3 fp: Move away from fixed RNG seed for play testing 2023-10-17 23:27:29 +11:00
doylet 27b9789d7c build: Ignore the version file 2023-10-17 22:11:48 +11:00
doylet 7a1c42ab15 build: Don't check in version otherwise we can never have a clean repo 2023-10-17 22:11:23 +11:00
doylet c73e6e08a8 build: Generate versioning information for the website 2023-10-17 22:07:20 +11:00
doylet 1bb1d71230 fp: Fix bug in platform API for set window title 2023-10-17 12:43:46 +11:00
doylet 0030275bc9 fp: Make the website prettier, set the tab title 2023-10-17 12:30:16 +11:00
18 changed files with 1780 additions and 1501 deletions
+1
View File
@@ -1,3 +1,4 @@
Build/ Build/
Nocheckin/ Nocheckin/
feely_pona_build.exe feely_pona_build.exe
feely_pona_version.txt
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
+6
View File
@@ -6,7 +6,13 @@ set script_dir=%script_dir_backslash:~0,-1%
set build_dir=%script_dir%\Build set build_dir=%script_dir%\Build
set code_dir=%script_dir% set code_dir=%script_dir%
REM Bootstrap a version
git show -s --date=format:%%Y-%%m-%%d --format=%%cd HEAD> feely_pona_version.txt
git rev-parse --short=8 HEAD>> feely_pona_version.txt
git rev-list --count HEAD>> feely_pona_version.txt
REM Bootstrap the build program REM Bootstrap the build program
mkdir %build_dir% 2>nul
pushd %build_dir% pushd %build_dir%
cl /nologo /Z7 /W4 %code_dir%\feely_pona_build.cpp || exit /B 1 cl /nologo /Z7 /W4 %code_dir%\feely_pona_build.cpp || exit /B 1
copy feely_pona_build.exe %code_dir% 1>nul copy feely_pona_build.exe %code_dir% 1>nul
+497 -436
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -52,6 +52,7 @@ struct FP_GlobalAnimations
Dqn_String8 heart = DQN_STRING8("heart"); Dqn_String8 heart = DQN_STRING8("heart");
Dqn_String8 heart_bleed = DQN_STRING8("heart_bleed"); Dqn_String8 heart_bleed = DQN_STRING8("heart_bleed");
Dqn_String8 icon_attack = DQN_STRING8("icon_attack");
Dqn_String8 icon_health = DQN_STRING8("icon_health"); Dqn_String8 icon_health = DQN_STRING8("icon_health");
Dqn_String8 icon_money = DQN_STRING8("icon_money"); Dqn_String8 icon_money = DQN_STRING8("icon_money");
Dqn_String8 icon_phone = DQN_STRING8("icon_phone"); Dqn_String8 icon_phone = DQN_STRING8("icon_phone");
+74 -19
View File
@@ -387,6 +387,22 @@ int main(int argc, char const **argv)
uint64_t feely_pona_emscripten_timings[2] = {}; uint64_t feely_pona_emscripten_timings[2] = {};
if (target_web) { if (target_web) {
Dqn_String8 const raylib_emscripten_lib_name = DQN_STRING8("raylib_emscripten.a"); Dqn_String8 const raylib_emscripten_lib_name = DQN_STRING8("raylib_emscripten.a");
bool debug_build = false;
Dqn_List<Dqn_String8> build_specific_compile_flags = {};
if (debug_build) {
build_specific_compile_flags = Dqn_List_InitCArrayCopy<Dqn_String8>(scratch.arena, 32, {
DQN_STRING8("-s"), DQN_STRING8("ASSERTIONS=2"),
DQN_STRING8("-s"), DQN_STRING8("SAFE_HEAP=0"),
DQN_STRING8("-s"), DQN_STRING8("STACK_OVERFLOW_CHECK=2"),
DQN_STRING8("--profiling-funcs"), // Expose function names in stack trace
DQN_STRING8("-g"), // Debug symbols
});
} else {
build_specific_compile_flags = Dqn_List_InitCArrayCopy<Dqn_String8>(scratch.arena, 32, {
DQN_STRING8("-Os"), // Optimise for size
});
}
// NOTE: Compile each raylib file separately with emcc ===================================== // NOTE: Compile each raylib file separately with emcc =====================================
{ {
@@ -406,8 +422,7 @@ int main(int argc, char const **argv)
build_file.input_file_path = base_file; build_file.input_file_path = base_file;
build_file.output_file_path = Dqn_String8_InitF(scratch.allocator, "raylib_%.*s_emscripten.o", DQN_STRING_FMT(file_stem)); build_file.output_file_path = Dqn_String8_InitF(scratch.allocator, "raylib_%.*s_emscripten.o", DQN_STRING_FMT(file_stem));
raylib_emscripten_build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, {build_file}); Dqn_List<Dqn_String8> compile_flags = Dqn_List_InitCArrayCopy(scratch.arena, 32, {
raylib_emscripten_build_context.compile_flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {
DQN_STRING8("cmd"), DQN_STRING8("cmd"),
DQN_STRING8("/C"), DQN_STRING8("/C"),
DQN_STRING8("emcc.bat"), DQN_STRING8("emcc.bat"),
@@ -417,6 +432,10 @@ int main(int argc, char const **argv)
DQN_STRING8("-D PLATFORM_WEB"), DQN_STRING8("-D PLATFORM_WEB"),
DQN_STRING8("-D GRAPHICS_API_OPENGL_ES2"), DQN_STRING8("-D GRAPHICS_API_OPENGL_ES2"),
}); });
Dqn_List_AddList(&compile_flags, build_specific_compile_flags);
raylib_emscripten_build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, {build_file});
raylib_emscripten_build_context.compile_flags = Dqn_List_ToSliceCopy(&compile_flags, scratch.arena);
raylib_emscripten_build_context.build_dir = build_dir; raylib_emscripten_build_context.build_dir = build_dir;
Dqn_List_Add(&raylib_emscripten_output_files, build_file.output_file_path); Dqn_List_Add(&raylib_emscripten_output_files, build_file.output_file_path);
@@ -446,11 +465,53 @@ int main(int argc, char const **argv)
} }
} }
// NOTE: feely pona emscripten ================================================================= // NOTE: feely pona emscripten =============================================================
{ {
feely_pona_emscripten_timings[0] = Dqn_OS_PerfCounterNow(); feely_pona_emscripten_timings[0] = Dqn_OS_PerfCounterNow();
DQN_DEFER { feely_pona_emscripten_timings[1] = Dqn_OS_PerfCounterNow(); }; DQN_DEFER { feely_pona_emscripten_timings[1] = Dqn_OS_PerfCounterNow(); };
// NOTE: feely pona emscripten shell =======================================================
Dqn_String8 html_shell_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_emscripten_shell.html", DQN_STRING_FMT(build_dir));
{
Dqn_String8 html_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_emscripten_shell.html", DQN_STRING_FMT(code_dir));
Dqn_String8 html_buffer = Dqn_Fs_Read(html_path, scratch.allocator);
if (!DQN_CHECKF(html_buffer.size,
"Failed to read Emscripten HTML shell file. The file at\n\n '%.*s'\n\ndoes not exist or is not readable",
DQN_STRING_FMT(html_path)))
return -1;
Dqn_String8 version_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_version.txt", DQN_STRING_FMT(code_dir));
Dqn_String8 version_buffer = Dqn_Fs_Read(version_path, scratch.allocator);
Dqn_String8SplitAllocResult version_parts = Dqn_String8_SplitAlloc(scratch.allocator, version_buffer, DQN_STRING8("\n"));
if (!DQN_CHECKF(version_parts.size == 3,
"Version file '%.*s' must have 3 lines containing, date, commit hash and number of commits. The buffer we tried extracting information from was\n\n%.*s\n\n",
DQN_STRING_FMT(version_path),
DQN_STRING_FMT(version_buffer))) {
return -1;
}
Dqn_String8 date = Dqn_String8_TrimWhitespaceAround(version_parts.data[0]);
Dqn_String8 commit_hash = Dqn_String8_TrimWhitespaceAround(version_parts.data[1]);
Dqn_String8 commit_count = Dqn_String8_TrimWhitespaceAround(version_parts.data[2]);
Dqn_String8 version_text = Dqn_String8_InitF(scratch.allocator,
"%.*s edition rev. %.*s-%.*s",
DQN_STRING_FMT(date),
DQN_STRING_FMT(commit_count),
DQN_STRING_FMT(commit_hash));
Dqn_String8 html_buffer_processed = Dqn_String8_Replace(html_buffer,
DQN_STRING8("@version@"),
version_text,
0 /*start_index*/,
scratch.allocator);
if (!DQN_CHECKF(Dqn_Fs_Write(html_shell_path,
html_buffer_processed),
"Failed to write Emscripten HTML shell with the project version inserted into it. We were unable to write to the target location\n\n '%.*s'\n",
DQN_STRING_FMT(html_shell_path)))
return -1;
}
// NOTE: Compile with emcc ============================================================= // NOTE: Compile with emcc =============================================================
Dqn_CPPBuildContext build_context = {}; Dqn_CPPBuildContext build_context = {};
build_context.compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_O; build_context.compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_O;
@@ -458,30 +519,24 @@ int main(int argc, char const **argv)
Dqn_CPPBuildCompileFile{{}, Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity_nodll.cpp", DQN_STRING_FMT(code_dir)) }, Dqn_CPPBuildCompileFile{{}, Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity_nodll.cpp", DQN_STRING_FMT(code_dir)) },
}); });
Dqn_String8 prefix = DQN_STRING8("Terry_Cherry"); Dqn_String8 output_name = DQN_STRING8("Terry_Cherry");
build_context.compile_flags = Dqn_Slice_InitCArrayCopy(scratch.arena, { Dqn_List<Dqn_String8> compile_flags = Dqn_List_InitCArrayCopy(scratch.arena, 32, {
DQN_STRING8("cmd"), DQN_STRING8("/C"), DQN_STRING8("emcc.bat"), DQN_STRING8("cmd"), DQN_STRING8("/C"), DQN_STRING8("emcc.bat"),
DQN_STRING8("-o"), Dqn_String8_InitF(scratch.allocator, "%.*s.html", DQN_STRING_FMT(prefix)), DQN_STRING8("-o"), Dqn_String8_InitF(scratch.allocator, "%.*s.html", DQN_STRING_FMT(output_name)),
DQN_STRING8("-Os"), // Optimize for size
DQN_STRING8("-Wall"), DQN_STRING8("-Wall"),
DQN_STRING8("--shell-file"), Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_emscripten_shell.html", DQN_STRING_FMT(code_dir)), DQN_STRING8("--shell-file"), html_shell_path,
Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(raylib_emscripten_lib_name)), Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(raylib_emscripten_lib_name)),
DQN_STRING8("-s"), DQN_STRING8("USE_GLFW=3"), DQN_STRING8("-s"), DQN_STRING8("USE_GLFW=3"),
// DQN_STRING8("-s"), DQN_STRING8("ASSERTIONS=2"),
// DQN_STRING8("-s"), DQN_STRING8("SAFE_HEAP=0"),
DQN_STRING8("-s"), DQN_STRING8("TOTAL_MEMORY=512MB"), DQN_STRING8("-s"), DQN_STRING8("TOTAL_MEMORY=512MB"),
DQN_STRING8("-s"), DQN_STRING8("TOTAL_STACK=32MB"), DQN_STRING8("-s"), DQN_STRING8("TOTAL_STACK=32MB"),
DQN_STRING8("-s"), DQN_STRING8("ALLOW_MEMORY_GROWTH"), DQN_STRING8("-s"), DQN_STRING8("ALLOW_MEMORY_GROWTH"),
// DQN_STRING8("-s"), DQN_STRING8("STACK_OVERFLOW_CHECK=2"),
// DQN_STRING8("--profiling-funcs"), // Expose function names in stack trace
// DQN_STRING8("-g"), // Debug symbols
// NOTE: Must be relative path such that fopen("Data/...") works
// otherwise the VFS will encode the full absolute path to the
// assets
DQN_STRING8("--preload-file"), DQN_STRING8("Data"), DQN_STRING8("--preload-file"), DQN_STRING8("Data"),
DQN_STRING8("-msimd128"), DQN_STRING8("-msimd128"),
DQN_STRING8("-msse2"), DQN_STRING8("-msse2"),
}); });
Dqn_List_AddList(&compile_flags, build_specific_compile_flags);
build_context.compile_flags = Dqn_List_ToSliceCopy(&compile_flags, scratch.arena);
build_context.build_dir = build_dir; build_context.build_dir = build_dir;
if (dry_run) { if (dry_run) {
@@ -492,7 +547,7 @@ int main(int argc, char const **argv)
} }
// NOTE: Move the files to a directory // NOTE: Move the files to a directory
Dqn_String8 folder_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s_Emscripten", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(prefix)); Dqn_String8 folder_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s_Emscripten", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(output_name));
if (!Dqn_Fs_DirExists(folder_path)) { if (!Dqn_Fs_DirExists(folder_path)) {
Dqn_String8 mkdir_cmd = Dqn_String8_InitF(scratch.allocator, "mkdir %.*s", DQN_STRING_FMT(folder_path)); Dqn_String8 mkdir_cmd = Dqn_String8_InitF(scratch.allocator, "mkdir %.*s", DQN_STRING_FMT(folder_path));
Dqn_OS_ExecOrAbort(mkdir_cmd, {}); Dqn_OS_ExecOrAbort(mkdir_cmd, {});
@@ -506,8 +561,8 @@ int main(int argc, char const **argv)
}; };
for (Dqn_String8 file_ext : generated_file_extension) { for (Dqn_String8 file_ext : generated_file_extension) {
Dqn_String8 src_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(prefix), DQN_STRING_FMT(file_ext)); Dqn_String8 src_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STRING_FMT(build_dir), DQN_STRING_FMT(output_name), DQN_STRING_FMT(file_ext));
Dqn_String8 dest_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STRING_FMT(folder_path), DQN_STRING_FMT(prefix), DQN_STRING_FMT(file_ext)); Dqn_String8 dest_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STRING_FMT(folder_path), DQN_STRING_FMT(output_name), DQN_STRING_FMT(file_ext));
Dqn_String8 cmd = Dqn_String8_InitF(scratch.allocator, "cmd /C move /Y %.*s %.*s", DQN_STRING_FMT(src_path), DQN_STRING_FMT(dest_path)); Dqn_String8 cmd = Dqn_String8_InitF(scratch.allocator, "cmd /C move /Y %.*s %.*s", DQN_STRING_FMT(src_path), DQN_STRING_FMT(dest_path));
if (dry_run) { if (dry_run) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STRING_FMT(cmd)); Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STRING_FMT(cmd));
+34 -135
View File
@@ -4,124 +4,49 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>raylib web game</title> <title>Terry Cherry</title>
<meta name="title" content="raylib web game"> <meta name="title" content="Terry Cherry">
<meta name="description" content="New raylib web videogame, developed using raylib videogames library"> <meta name="description" content="Terry fends off the hordes of cherries">
<meta name="keywords" content="raylib, games, html5, programming, C, C++, library, learn, videogames">
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<!-- Open Graph metatags for sharing -->
<meta property="og:title" content="raylib web game">
<meta property="og:image:type" content="image/png">
<meta property="og:image" content="https://www.raylib.com/common/img/raylib_logo.png">
<meta property="og:site_name" content="raylib.com">
<meta property="og:url" content="https://www.raylib.com/games.html">
<meta property="og:description" content="New raylib web videogame, developed using raylib videogames library">
<!-- Twitter metatags for sharing -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@raysan5">
<meta name="twitter:title" content="raylib web game">
<meta name="twitter:image" content="https://www.raylib.com/common/raylib_logo.png">
<meta name="twitter:url" content="https://www.raylib.com/games.html">
<meta name="twitter:description" content="New raylib web game, developed using raylib videogames library">
<!-- Favicon -->
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
<style> <style>
body { body {
font-family: arial; font-family: arial;
margin: 0; margin: 0;
padding: none; padding: none;
background: #301010;
} }
#header { #header {
width: 100%; font-weight: bold;
height: 80px; color: white;
background-color: #888888; height: 30px;
} text-align: center;
padding-left: 5px;
/* NOTE: raylib logo is embedded in the page as base64 png image */ padding-right: 5px;
#logo { padding-top: 5px;
width:64px; padding-bottom: 10px;
height:64px;
float:left;
position:relative;
margin:10px;
background-image:url('data:image/png;base64,\
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADs\
MAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAA7JJREFUaEPtk0FyWzEMQ+37X7fZhxX4\
YY3AD1OKF1nkzTRlSBCCLeVBnvl/AUdaELOunPno1kts1kixdtEZKVs+xIxebBkZsVknn/L5nFGDLR8T4zVC9fX19S/+tTFijr\
YK4jUjbPUtqBHpnEE6PkZD7jQZV8n5Recw1XQKciZuPaEtR6UjNs5ENVGMsBVqpPtER0ZMOhpyp8m4YL4OjD9yxsyZxnQycfMJ\
ETNSzsRE1+dihK3YMiJmpHTW3xpmXPC6BXlCHfqnBlsjY5hxf/6EVEOM2BTEi0fYCX4ONSI6Kq3Blg/prIOMq2CsRur4KQ0x64\
SdjOufEDEdHZGOhmz5RDHCVqhRuQ86YsVskbc+GXchLiHnFyYH+UigQDVGnImbT8hwFkgLg2qiM8JO6Ylx1FNLa3DmYwqCTsZd\
4BPqGJG7MwKzpeiWKTKxXkLMVE3MSOmsdwxLH6Rd/wCCLSNDx6djeKfJuArGeoYamRHpaEjnCBYZVy8hZqo2GI36qPjsiOiMsB\
XGcev4Mx9TLGTchbgEjN/uz6jGrBvDjg+LTNx8Qp2CbG2xMKgmOiPslJ4Yxx+eSnSkzlosZNwFPiHl7FRTkLNRJm4+IeVM0ymI\
H42wE/wcKalQI4MRl4EW3p6VcRWMua8F6WjIlqZDxvVPiHQ6CjVbYkV9ohhhp/Rk1wiYgpyJ78i4CsZbjkb8Qx+ihvzu3RPaKo\
gZkY6GlEeMsKdPSOFIC8VoOusg44L5c+T8ouOoGhWbdWJ8tMi4egkxo4hoh2yNTGf3iIyr5Lyic4bRENXo+lvDjAt4C1Hk/OKt\
UaAj0+n4dMSZ2D+hrYJsaYh2SClG2jV9kJKKzhlGQ1SsW299Mq6C8dYZHTExo8fzieI5ivipYnYy7nwJqGKmOYyRwfiUBXITfh\
5qSHRGWEkfqJqURgvsdHyWYv7Ko8DnYYegk3EB00cxprdrJRzFd7YQzawu8L1GMTYS/KpPaAFTkIn1EmJmspJSs5xBzSyGhlkB\
mlxfNFiP5mw4wlbMh4F5Ddxp5jNINBdCEz9zPOC1zD7Q0HBdmXndwv0TMtydEdzlWJT4VZ8Qt9Qn4/onxMIwa5ZYGJU5yufBiC\
jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaBBfOTCGHM2aEbZi1+gO\
1XTWVXMnzrhAn5DSOZVsiQlHnSITKzGj6DeTcZWc/3oy7h9//PF4PL4BlvsWrb6RE+oAAAAASUVORK5CYII=');
} }
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; } div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; } div.emscripten_border { border: 0px solid black; }
div.emscripten_status { border: 0px solid black; }
/* NOTE: Canvas *must not* have any border or padding, or mouse coords will be wrong */ /* NOTE: Canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { canvas.emscripten {
border: 0px none; border: 0px none;
background: black; background: black;
width: 100%; width: 75vw;
}
.spinner {
height: 30px;
width: 30px;
margin: 0;
margin-top: 20px;
margin-left: 20px;
display: inline-block;
vertical-align: top;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 5px solid black;
border-right: 5px solid black;
border-bottom: 5px solid black;
border-top: 5px solid red;
border-radius: 100%;
background-color: rgb(245, 245, 245);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
} }
#status { #status {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
margin-top: 30px; font-weight: normal;
margin-left: 20px; font-size: 0.8em;
font-weight: bold; color: darkgray;
color: rgb(40, 40, 40);
} }
#progress { #progress {
@@ -133,30 +58,26 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
display: inline-block; display: inline-block;
float: right; float: right;
vertical-align: top; vertical-align: top;
margin-top: 15px;
margin-right: 20px;
} }
#output { #output {
width: 100%; width: 90%;
height: 140px; height: 140px;
margin: 0 auto; margin: 0 auto;
margin-top: 10px; margin-top: 10px;
display: block; display: block;
background-color: black; background-color: black;
color: rgb(37, 174, 38); color: white;
font-family: 'Lucida Console', Monaco, monospace; font-family: 'Lucida Console', Monaco, monospace;
outline: none; outline: none;
} }
input[type=button] { input[type=button] {
background-color: lightgray; background-color: lightgray;
border: 4px solid darkgray;
color: black; color: black;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
width: 140px; width: 140px;
height: 50px;
} }
input[type=button]:hover { input[type=button]:hover {
@@ -167,18 +88,10 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
</head> </head>
<body> <body>
<div id="header"> <div id="header">
<a id="logo" href="https://www.raylib.com"></a> <h1 style="font-size: 1em; text-align: center; margin-top: 0; margin-bottom: 0; padding-bottom: 3px">Terry Cherry</h1>
<div class="spinner" id='spinner'></div>
<div class="emscripten" id="status">Downloading...</div> <div class="emscripten" id="status">Downloading...</div>
<span id='controls'>
<span><input type="button" value="🖵 FULLSCREEN" onclick="Module.requestFullscreen(false, false)"></span>
<span><input type="button" id="btn-audio" value="🔇 SUSPEND" onclick="toggleAudio()"></span>
</span>
<div class="emscripten"> <div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress> <progress value="0" max="100" id="progress" hidden=0></progress>
</div> </div>
</div> </div>
@@ -186,31 +99,17 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div> </div>
<div style="display: flex; justify-content: space-around;">
<span id='controls'>
<span><input type="button" value="🖵 FULLSCREEN" onclick="Module.requestFullscreen(false, false)"></span>
<span><input type="button" id="btn-audio" value="🔇 SUSPEND" onclick="toggleAudio()"></span>
</span>
</div>
<textarea id="output" rows="8"></textarea> <textarea id="output" rows="8"></textarea>
<script type='text/javascript' src="https://cdn.jsdelivr.net/gh/eligrey/FileSaver.js/dist/FileSaver.min.js"> </script>
<script type='text/javascript'>
function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code
{
var isSafari = false; // Not supported, navigator.userAgent access is being restricted
//var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
var data = FS.readFile(memoryFSname);
var blob;
if (isSafari) blob = new Blob([data.buffer], { type: "application/octet-stream" });
else blob = new Blob([data.buffer], { type: "application/octet-binary" });
// NOTE: SaveAsDialog is a browser setting. For example, in Google Chrome,
// in Settings/Advanced/Downloads section you have a setting:
// 'Ask where to save each file before downloading' - which you can set true/false.
// If you enable this setting it would always ask you and bring the SaveAsDialog
saveAs(blob, localFSname);
}
</script>
<script type='text/javascript'> <script type='text/javascript'>
var statusElement = document.querySelector('#status'); var statusElement = document.querySelector('#status');
var progressElement = document.querySelector('#progress'); var progressElement = document.querySelector('#progress');
var spinnerElement = document.querySelector('#spinner');
var Module = { var Module = {
preRun: [], preRun: [],
postRun: [], postRun: [],
@@ -266,15 +165,17 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
progressElement.value = parseInt(m[2])*100; progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100; progressElement.max = parseInt(m[4])*100;
progressElement.hidden = true; progressElement.hidden = true;
spinnerElement.hidden = false;
} else { } else {
progressElement.value = null; progressElement.value = null;
progressElement.max = null; progressElement.max = null;
progressElement.hidden = true; progressElement.hidden = true;
if (!text) spinnerElement.style.display = 'none';
} }
statusElement.innerHTML = text; if (text) {
statusElement.innerHTML = '@version@: ' + text;
} else {
statusElement.innerHTML = '@version@';
}
}, },
totalDependencies: 0, totalDependencies: 0,
monitorRunDependencies: function(left) { monitorRunDependencies: function(left) {
@@ -288,7 +189,6 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
window.onerror = function() { window.onerror = function() {
Module.setStatus('Exception thrown, see JavaScript console'); Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = function(text) { if (text) Module.printErr('[post-exception status] ' + text); }; Module.setStatus = function(text) { if (text) Module.printErr('[post-exception status] ' + text); };
}; };
</script> </script>
@@ -296,7 +196,6 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
<!-- REF: https://developers.google.com/web/updates/2018/11/web-audio-autoplay --> <!-- REF: https://developers.google.com/web/updates/2018/11/web-audio-autoplay -->
<script type='text/javascript'> <script type='text/javascript'>
var audioBtn = document.querySelector('#btn-audio'); var audioBtn = document.querySelector('#btn-audio');
// An array of all contexts to resume on the page // An array of all contexts to resume on the page
const audioContexList = []; const audioContexList = [];
(function() { (function() {
+292
View File
@@ -0,0 +1,292 @@
#if defined(_CLANGD)
#pragma once
#include "feely_pona_unity.h"
#endif
static bool FP_Entity_IsBuildingForMobs(FP_GameEntity *entity)
{
bool result = entity->type == FP_EntityType_AirportTerry ||
entity->type == FP_EntityType_ClubTerry ||
entity->type == FP_EntityType_ChurchTerry ||
entity->type == FP_EntityType_KennelTerry;
return result;
}
static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect)
{
Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game->play, sprite_rect.size.y);
Dqn_f32 result = height.meters / sprite_in_meters;
return result;
}
static FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, uint32_t raw_state, FP_GameDirection direction)
{
FP_EntityRenderData result = {};
switch (type) {
case FP_EntityType_Nil: {
} break;
case FP_EntityType_Map: {
result.height.meters = 41.9f;
result.anim_name = g_anim_names.map;
} break;
case FP_EntityType_Terry: {
result.height.meters = 1.8f;
FP_EntityTerryState state = DQN_CAST(FP_EntityTerryState)raw_state;
switch (state) {
case FP_EntityTerryState_Idle: result.anim_name = g_anim_names.terry_walk_idle; break;
case FP_EntityTerryState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_up; result.height.meters *= 1.5f; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_attack_down; result.height.meters *= 1.6f; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_attack_side; result.height.meters *= 1.5f; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_side; result.height.meters *= 1.5f; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_RangeAttack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_phone_up; result.height.meters *= 1.25f; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_attack_phone_down; result.height.meters *= 1.25f; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_attack_phone_side; result.height.meters *= 1.25f; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; result.height.meters *= 1.25f; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_Dash: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_ghost; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_walk_left; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_DeadGhost: {
result.anim_name = g_anim_names.terry_death; break;
} break;
}
} break;
case FP_EntityType_Smoochie: {
result.height.meters = 1.6f;
FP_EntitySmoochieState state = DQN_CAST(FP_EntitySmoochieState)raw_state;
switch (state) {
case FP_EntitySmoochieState_Idle: result.anim_name = g_anim_names.smoochie_walk_down; break;
case FP_EntitySmoochieState_Attack: result.anim_name = g_anim_names.smoochie_attack_down; break;
case FP_EntitySmoochieState_HurtSide: result.anim_name = g_anim_names.smoochie_hurt_side; result.flip = direction == FP_GameDirection_Right ? TELY_AssetFlip_X : TELY_AssetFlip_No; break;
case FP_EntitySmoochieState_Death: result.anim_name = g_anim_names.smoochie_death; break;
case FP_EntitySmoochieState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.smoochie_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.smoochie_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.smoochie_walk_left; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.smoochie_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_MerchantTerry: {
result.height.meters = 3.66f;
FP_EntityMerchantTerryState state = DQN_CAST(FP_EntityMerchantTerryState)raw_state;
switch (state) {
case FP_EntityMerchantTerryState_Idle: result.anim_name = g_anim_names.merchant_terry; break;
}
} break;
case FP_EntityType_MerchantGraveyard: {
result.height.meters = 3.66f;
FP_EntityMerchantGraveyardState state = DQN_CAST(FP_EntityMerchantGraveyardState)raw_state;
switch (state) {
case FP_EntityMerchantGraveyardState_Idle: result.anim_name = g_anim_names.merchant_graveyard; break;
}
} break;
case FP_EntityType_MerchantGym: {
result.height.meters = 3.66f;
result.anim_name = g_anim_names.merchant_gym;
FP_EntityMerchantGymState state = DQN_CAST(FP_EntityMerchantGymState)raw_state;
switch (state) {
case FP_EntityMerchantGymState_Idle: result.anim_name = g_anim_names.merchant_gym; break;
}
} break;
case FP_EntityType_MerchantPhoneCompany: {
result.height.meters = 5.f;
FP_EntityMerchantPhoneCompanyState state = DQN_CAST(FP_EntityMerchantPhoneCompanyState)raw_state;
switch (state) {
case FP_EntityMerchantPhoneCompanyState_Idle: result.anim_name = g_anim_names.merchant_phone_company; break;
}
} break;
case FP_EntityType_ClubTerry: {
result.height.meters = 4.f;
FP_EntityClubTerryState state = DQN_CAST(FP_EntityClubTerryState)raw_state;
switch (state) {
case FP_EntityClubTerryState_Idle: result.anim_name = g_anim_names.club_terry_dark; break;
case FP_EntityClubTerryState_PartyTime: result.anim_name = g_anim_names.club_terry_alive; break;
}
} break;
case FP_EntityType_Clinger: {
result.height.meters = 1.6f;
FP_EntityClingerState state = DQN_CAST(FP_EntityClingerState)raw_state;
switch (state) {
case FP_EntityClingerState_Idle: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_EntityClingerState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.clinger_attack_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.clinger_attack_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.clinger_attack_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_attack_side; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityClingerState_Death: result.anim_name = g_anim_names.clinger_death; break;
case FP_EntityClingerState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.clinger_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_Heart: {
result.height.meters = 4.f;
FP_EntityHeartState state = DQN_CAST(FP_EntityHeartState)raw_state;
switch (state) {
case FP_EntityHeartState_Idle: result.anim_name = g_anim_names.heart; break;
}
} break;
case FP_EntityType_AirportTerry: {
result.height.meters = 4.f;
FP_EntityAirportTerryState state = DQN_CAST(FP_EntityAirportTerryState)raw_state;
switch (state) {
case FP_EntityAirportTerryState_Idle: result.anim_name = g_anim_names.airport_terry; break;
case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry; break;
}
} break;
case FP_EntityType_Catfish: {
result.height.meters = 1.6f;
FP_EntityCatfishState state = DQN_CAST(FP_EntityCatfishState)raw_state;
switch (state) {
case FP_EntityCatfishState_Idle: result.anim_name = g_anim_names.catfish_walk_down; break;
case FP_EntityCatfishState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_attack_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_attack_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_attack_side; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_attack_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityCatfishState_Death: result.anim_name = g_anim_names.catfish_death; break;
case FP_EntityCatfishState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_walk_side; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_walk_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_ChurchTerry: {
result.height.meters = 4.f;
FP_EntityChurchTerryState state = DQN_CAST(FP_EntityChurchTerryState)raw_state;
switch (state) {
case FP_EntityChurchTerryState_Idle: result.anim_name = g_anim_names.church_terry_dark; break;
case FP_EntityChurchTerryState_ConvertPatron: result.anim_name = g_anim_names.church_terry_alive; break;
}
} break;
case FP_EntityType_KennelTerry: {
result.height.meters = 3.f;
FP_EntityKennelTerryState state = DQN_CAST(FP_EntityKennelTerryState)raw_state;
switch (state) {
case FP_EntityKennelTerryState_Idle: result.anim_name = g_anim_names.kennel_terry; break;
}
} break;
case FP_EntityType_PhoneMessageProjectile: {
result.height.meters = 1.f;
result.anim_name = g_anim_names.terry_attack_phone_message;
} break;
case FP_EntityType_AirportTerryPlane: {
result.height.meters = 1.5f;
result.anim_name = g_anim_names.airport_terry_plane;
} break;
case FP_EntityType_MobSpawner: {
result.height.meters = 3.f;
FP_EntityMobSpawnerState state = DQN_CAST(FP_EntityMobSpawnerState)raw_state;
switch (state) {
case FP_EntityMobSpawnerState_Idle: result.anim_name = g_anim_names.portal; break;
case FP_EntityMobSpawnerState_Shutdown: {
result.anim_name = g_anim_names.portal_break;
result.height.meters = 3.5f;
} break;
}
} break;
case FP_EntityType_PortalMonkey: {
result.height.meters = 1.f;
result.anim_name = g_anim_names.portal_monk; break;
} break;
case FP_EntityType_Billboard: {
result.height.meters = 7.5f;
FP_EntityBillboardState state = DQN_CAST(FP_EntityBillboardState)raw_state;
switch (state) {
case FP_EntityBillboardState_Attack: result.anim_name = g_anim_names.map_billboard_attack; break;
case FP_EntityBillboardState_Dash: result.anim_name = g_anim_names.map_billboard_dash; break;
case FP_EntityBillboardState_Monkey: result.anim_name = g_anim_names.map_billboard_monkey; break;
case FP_EntityBillboardState_RangeAttack: result.anim_name = g_anim_names.map_billboard_range_attack; break;
case FP_EntityBillboardState_Strafe: result.anim_name = g_anim_names.map_billboard_strafe; break;
}
} break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
}
result.sheet = &game->atlas_sprite_sheet;
TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(result.sheet, result.anim_name);
if (sprite_anim) {
result.sheet_rect = result.sheet->rects.data[sprite_anim->index];
Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, result.height, result.sheet_rect);
result.render_size = result.sheet_rect.size * size_scale;
result.sprite = TELY_Asset_MakeAnimatedSprite(result.sheet, result.anim_name, result.flip);
}
return result;
}
-287
View File
@@ -3,293 +3,6 @@
#include "feely_pona_unity.h" #include "feely_pona_unity.h"
#endif #endif
static bool FP_Entity_IsBuildingForMobs(FP_GameEntity *entity)
{
bool result = entity->type == FP_EntityType_AirportTerry ||
entity->type == FP_EntityType_ClubTerry ||
entity->type == FP_EntityType_ChurchTerry ||
entity->type == FP_EntityType_KennelTerry;
return result;
}
static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect)
{
Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game->play, sprite_rect.size.y);
Dqn_f32 result = height.meters / sprite_in_meters;
return result;
}
FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, uint32_t raw_state, FP_GameDirection direction)
{
FP_EntityRenderData result = {};
switch (type) {
case FP_EntityType_Nil: {
} break;
case FP_EntityType_Map: {
result.height.meters = 41.9f;
result.anim_name = g_anim_names.map;
} break;
case FP_EntityType_Terry: {
result.height.meters = 1.8f;
FP_EntityTerryState state = DQN_CAST(FP_EntityTerryState)raw_state;
switch (state) {
case FP_EntityTerryState_Idle: result.anim_name = g_anim_names.terry_walk_idle; break;
case FP_EntityTerryState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_up; result.height.meters *= 1.5f; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_attack_down; result.height.meters *= 1.6f; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_attack_side; result.height.meters *= 1.5f; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_side; result.height.meters *= 1.5f; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_RangeAttack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_phone_up; result.height.meters *= 1.25f; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_attack_phone_down; result.height.meters *= 1.25f; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_attack_phone_side; result.height.meters *= 1.25f; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; result.height.meters *= 1.25f; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_Dash: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_ghost; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_ghost; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_walk_left; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityTerryState_DeadGhost: {
result.anim_name = g_anim_names.terry_death; break;
} break;
}
} break;
case FP_EntityType_Smoochie: {
result.height.meters = 1.6f;
FP_EntitySmoochieState state = DQN_CAST(FP_EntitySmoochieState)raw_state;
switch (state) {
case FP_EntitySmoochieState_Idle: result.anim_name = g_anim_names.smoochie_walk_down; break;
case FP_EntitySmoochieState_Attack: result.anim_name = g_anim_names.smoochie_attack_down; break;
case FP_EntitySmoochieState_HurtSide: result.anim_name = g_anim_names.smoochie_hurt_side; result.flip = direction == FP_GameDirection_Right ? TELY_AssetFlip_X : TELY_AssetFlip_No; break;
case FP_EntitySmoochieState_Death: result.anim_name = g_anim_names.smoochie_death; break;
case FP_EntitySmoochieState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.smoochie_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.smoochie_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.smoochie_walk_left; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.smoochie_walk_right; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_MerchantTerry: {
result.height.meters = 3.66f;
FP_EntityMerchantTerryState state = DQN_CAST(FP_EntityMerchantTerryState)raw_state;
switch (state) {
case FP_EntityMerchantTerryState_Idle: result.anim_name = g_anim_names.merchant_terry; break;
}
} break;
case FP_EntityType_MerchantGraveyard: {
result.height.meters = 3.66f;
FP_EntityMerchantGraveyardState state = DQN_CAST(FP_EntityMerchantGraveyardState)raw_state;
switch (state) {
case FP_EntityMerchantGraveyardState_Idle: result.anim_name = g_anim_names.merchant_graveyard; break;
}
} break;
case FP_EntityType_MerchantGym: {
result.height.meters = 3.66f;
result.anim_name = g_anim_names.merchant_gym;
FP_EntityMerchantGymState state = DQN_CAST(FP_EntityMerchantGymState)raw_state;
switch (state) {
case FP_EntityMerchantGymState_Idle: result.anim_name = g_anim_names.merchant_gym; break;
}
} break;
case FP_EntityType_MerchantPhoneCompany: {
result.height.meters = 5.f;
FP_EntityMerchantPhoneCompanyState state = DQN_CAST(FP_EntityMerchantPhoneCompanyState)raw_state;
switch (state) {
case FP_EntityMerchantPhoneCompanyState_Idle: result.anim_name = g_anim_names.merchant_phone_company; break;
}
} break;
case FP_EntityType_ClubTerry: {
result.height.meters = 4.f;
FP_EntityClubTerryState state = DQN_CAST(FP_EntityClubTerryState)raw_state;
switch (state) {
case FP_EntityClubTerryState_Idle: result.anim_name = g_anim_names.club_terry_dark; break;
case FP_EntityClubTerryState_PartyTime: result.anim_name = g_anim_names.club_terry_alive; break;
}
} break;
case FP_EntityType_Clinger: {
result.height.meters = 1.6f;
FP_EntityClingerState state = DQN_CAST(FP_EntityClingerState)raw_state;
switch (state) {
case FP_EntityClingerState_Idle: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_EntityClingerState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.clinger_attack_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.clinger_attack_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.clinger_attack_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_attack_side; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityClingerState_Death: result.anim_name = g_anim_names.clinger_death; break;
case FP_EntityClingerState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.clinger_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_walk_down; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_Heart: {
result.height.meters = 4.f;
FP_EntityHeartState state = DQN_CAST(FP_EntityHeartState)raw_state;
switch (state) {
case FP_EntityHeartState_Idle: result.anim_name = g_anim_names.heart; break;
}
} break;
case FP_EntityType_AirportTerry: {
result.height.meters = 4.f;
FP_EntityAirportTerryState state = DQN_CAST(FP_EntityAirportTerryState)raw_state;
switch (state) {
case FP_EntityAirportTerryState_Idle: result.anim_name = g_anim_names.airport_terry; break;
case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry; break;
}
} break;
case FP_EntityType_Catfish: {
result.height.meters = 1.6f;
FP_EntityCatfishState state = DQN_CAST(FP_EntityCatfishState)raw_state;
switch (state) {
case FP_EntityCatfishState_Idle: result.anim_name = g_anim_names.catfish_walk_down; break;
case FP_EntityCatfishState_Attack: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_attack_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_attack_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_attack_side; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_attack_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
case FP_EntityCatfishState_Death: result.anim_name = g_anim_names.catfish_death; break;
case FP_EntityCatfishState_Run: {
switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_walk_up; break;
case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_walk_down; break;
case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_walk_side; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_walk_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} break;
}
} break;
case FP_EntityType_ChurchTerry: {
result.height.meters = 4.f;
FP_EntityChurchTerryState state = DQN_CAST(FP_EntityChurchTerryState)raw_state;
switch (state) {
case FP_EntityChurchTerryState_Idle: result.anim_name = g_anim_names.church_terry_dark; break;
case FP_EntityChurchTerryState_ConvertPatron: result.anim_name = g_anim_names.church_terry_alive; break;
}
} break;
case FP_EntityType_KennelTerry: {
result.height.meters = 3.f;
FP_EntityKennelTerryState state = DQN_CAST(FP_EntityKennelTerryState)raw_state;
switch (state) {
case FP_EntityKennelTerryState_Idle: result.anim_name = g_anim_names.kennel_terry; break;
}
} break;
case FP_EntityType_PhoneMessageProjectile: {
result.height.meters = 1.f;
result.anim_name = g_anim_names.terry_attack_phone_message;
} break;
case FP_EntityType_AirportTerryPlane: {
result.height.meters = 1.5f;
result.anim_name = g_anim_names.airport_terry_plane;
} break;
case FP_EntityType_MobSpawner: {
result.height.meters = 3.f;
FP_EntityMobSpawnerState state = DQN_CAST(FP_EntityMobSpawnerState)raw_state;
switch (state) {
case FP_EntityMobSpawnerState_Idle: result.anim_name = g_anim_names.portal; break;
case FP_EntityMobSpawnerState_Shutdown: {
result.anim_name = g_anim_names.portal_break;
result.height.meters = 3.5f;
} break;
}
} break;
case FP_EntityType_PortalMonkey: {
result.height.meters = 1.f;
result.anim_name = g_anim_names.portal_monk; break;
} break;
case FP_EntityType_Billboard: {
result.height.meters = 7.5f;
FP_EntityBillboardState state = DQN_CAST(FP_EntityBillboardState)raw_state;
switch (state) {
case FP_EntityBillboardState_Attack: result.anim_name = g_anim_names.map_billboard_attack; break;
case FP_EntityBillboardState_Dash: result.anim_name = g_anim_names.map_billboard_dash; break;
case FP_EntityBillboardState_Monkey: result.anim_name = g_anim_names.map_billboard_monkey; break;
case FP_EntityBillboardState_RangeAttack: result.anim_name = g_anim_names.map_billboard_range_attack; break;
case FP_EntityBillboardState_Strafe: result.anim_name = g_anim_names.map_billboard_strafe; break;
}
} break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
}
result.sheet = &game->atlas_sprite_sheet;
TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(result.sheet, result.anim_name);
if (sprite_anim) {
result.sheet_rect = result.sheet->rects.data[sprite_anim->index];
Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, result.height, result.sheet_rect);
result.render_size = result.sheet_rect.size * size_scale;
result.sprite = TELY_Asset_MakeAnimatedSprite(result.sheet, result.anim_name, result.flip);
}
return result;
}
static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle handle) static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle handle)
{ {
FP_GameEntity *entity = FP_Game_GetEntity(game, handle); FP_GameEntity *entity = FP_Game_GetEntity(game, handle);
+223 -15
View File
@@ -3,14 +3,6 @@
#include "feely_pona_unity.h" #include "feely_pona_unity.h"
#endif #endif
#define FP_Game_MetersToPixelsNx1(game, val) ((val) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsV2(game, xy) (xy * (game).meters_to_pixels)
#define FP_Game_PixelsToMetersNx1(game, val) ((val) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersV2(game, xy) (xy * (1.f/(game).meters_to_pixels))
static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs) static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs)
{ {
bool result = lhs.id == rhs.id; bool result = lhs.id == rhs.id;
@@ -23,13 +15,6 @@ static bool operator!=(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const
return result; return result;
} }
// TODO(doyle): Use this
struct FP_GameCameraM2x3
{
Dqn_M2x3 model_view;
Dqn_M2x3 view_model;
};
static FP_GameCameraM2x3 FP_Game_CameraModelViewM2x3(FP_GameCamera camera) static FP_GameCameraM2x3 FP_Game_CameraModelViewM2x3(FP_GameCamera camera)
{ {
FP_GameCameraM2x3 result = {}; FP_GameCameraM2x3 result = {};
@@ -932,3 +917,226 @@ static void FP_GameRenderScanlines(TELY_Renderer *renderer,
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.1f), scanline_thickness); TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.1f), scanline_thickness);
} }
} }
static FP_GameCanMoveToPositionResult FP_Game_CanEntityMoveToPosition(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_V2 delta_pos)
{
FP_GameCanMoveToPositionResult result = {};
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
if (FP_Game_IsNilEntity(entity))
return result;
Dqn_Rect const entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 const entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
Dqn_f32 const SENTINEL_T = 999.f;
Dqn_f32 global_earliest_t = SENTINEL_T;
Dqn_V2 global_earliest_pos_just_before_collide = {};
Dqn_V2 const entity_new_pos = entity_pos + delta_pos;
if ((entity->flags & FP_GameEntityFlag_NoClip) == 0) {
for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->play.root_entity);) {
FP_GameEntity *collider = collider_it.entity;
if (collider->handle == entity->handle)
continue;
// TODO(doyle): Calculate the list of collidables at the start of the frame
if ((collider->flags & FP_GameEntityFlag_NonTraversable) == 0)
continue;
bool skip_colliding_with_player = false;
for (FP_GameEntityHandle player : game->play.players) {
if (player == collider->handle) {
skip_colliding_with_player = true;
break;
}
}
if (skip_colliding_with_player)
continue;
bool entity_collides_with_collider = true;
switch (entity->type) {
case FP_EntityType_Catfish: /*FALLTHRU*/
case FP_EntityType_Smoochie: /*FALLTHRU*/
case FP_EntityType_Clinger: {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish) {
entity_collides_with_collider = false;
} else if (FP_Entity_IsBuildingForMobs(collider)) {
#if 0
// NOTE: We disable collision on buildings we have visited to avoid some
// problems ...
if (FP_SentinelList_Find(&entity->buildings_visited, collider->handle)) {
entity_collides_with_collider = false;
}
#else
entity_collides_with_collider = false;
#endif
} else if (collider->type == FP_EntityType_Heart ||
collider->type == FP_EntityType_MerchantGym ||
collider->type == FP_EntityType_MerchantTerry ||
collider->type == FP_EntityType_MerchantGraveyard ||
collider->type == FP_EntityType_MerchantPhoneCompany) {
entity_collides_with_collider = false;
}
} break;
case FP_EntityType_Terry: {
// NOTE: Don't collide with mobs when dashing (e.g. phase through)
FP_EntityTerryState state = *DQN_CAST(FP_EntityTerryState *)&entity->action.state;
if (state == FP_EntityTerryState_Dash || state == FP_EntityTerryState_DeadGhost) {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
entity_collides_with_collider = false;
}
} break;
case FP_EntityType_Nil: break;
case FP_EntityType_MerchantTerry: break;
case FP_EntityType_Count: break;
case FP_EntityType_ClubTerry: break;
case FP_EntityType_Map: break;
case FP_EntityType_MerchantGraveyard: break;
case FP_EntityType_MerchantGym: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break;
case FP_EntityType_AirportTerry: break;
case FP_EntityType_ChurchTerry: break;
case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
case FP_EntityType_AirportTerryPlane:
case FP_EntityType_MobSpawner:
case FP_EntityType_PortalMonkey: break;
case FP_EntityType_Billboard: break;
}
if (!entity_collides_with_collider)
continue;
// NOTE: Sweep collider with half the radius of the source entity
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
if (Dqn_V2_Area(collider_world_hit_box.size) <= 0)
continue;
Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
swept_collider_world_hit_box.size += entity_world_hit_box.size;
if (!Dqn_Rect_ContainsPoint(swept_collider_world_hit_box, entity_new_pos))
continue;
Dqn_f32 collider_left_wall_x = swept_collider_world_hit_box.pos.x;
Dqn_f32 collider_right_wall_x = swept_collider_world_hit_box.pos.x + swept_collider_world_hit_box.size.w;
Dqn_f32 collider_top_wall_y = swept_collider_world_hit_box.pos.y;
Dqn_f32 collider_bottom_wall_y = swept_collider_world_hit_box.pos.y + swept_collider_world_hit_box.size.h;
Dqn_V2 o = entity_pos;
Dqn_V2 d = delta_pos;
// NOTE: Solve collision by determining the 't' value at which
// we hit one of the walls of the collider and move the entity
// at exactly that point.
// O + td = x
// td = x - O
// t = (x - O) / d
Dqn_f32 earliest_t = SENTINEL_T;
if (d.x != 0.f) {
Dqn_f32 left_t = (collider_left_wall_x - o.x) / d.x;
Dqn_f32 right_t = (collider_right_wall_x - o.x) / d.x;
if (left_t >= 0.f && left_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, left_t);
if (right_t >= 0.f && right_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, right_t);
}
if (d.y != 0.f) {
Dqn_f32 top_t = (collider_top_wall_y - o.y) / d.y;
Dqn_f32 bottom_t = (collider_bottom_wall_y - o.y) / d.y;
if (top_t >= 0.f && top_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, top_t);
if (bottom_t >= 0.f && bottom_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, bottom_t);
}
if (earliest_t < global_earliest_t) {
global_earliest_t = earliest_t;
global_earliest_pos_just_before_collide = entity_pos + (d * earliest_t);
}
}
}
result.yes = global_earliest_t == SENTINEL_T;
if (!result.yes)
result.next_closest_valid_move = delta_pos * global_earliest_t;
return result;
}
static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_V2 acceleration_meters_per_s)
{
// f"(t) = a
// f'(t) = at + v
// f (t) = 0.5f*a(t^2) + vt + p
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
if (FP_Game_IsNilEntity(entity))
return;
Dqn_f32 t = DQN_CAST(Dqn_f32)DQN_SQUARED(FP_GAME_PHYSICS_STEP);
Dqn_f32 t_squared = DQN_SQUARED(t);
Dqn_f32 velocity_falloff_coefficient = 0.82f;
Dqn_f32 acceleration_feel_good_factor = 15'000.f;
Dqn_V2 acceleration = FP_Game_MetersToPixelsV2(game->play, acceleration_meters_per_s) * acceleration_feel_good_factor;
entity->velocity = (acceleration * t) + entity->velocity * velocity_falloff_coefficient;
// NOTE: Zero out velocity with epsilon
if (DQN_ABS(entity->velocity.x) < 5.f)
entity->velocity.x = 0.f;
if (DQN_ABS(entity->velocity.y) < 5.f)
entity->velocity.y = 0.f;
Dqn_V2 const delta_pos = (acceleration * 0.5f * t_squared) + (entity->velocity * t);
Dqn_Rect const entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 const entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
Dqn_V2 const entity_new_pos = entity_pos + delta_pos;
FP_GameCanMoveToPositionResult move_to_result = FP_Game_CanEntityMoveToPosition(game, entity->handle, delta_pos);
if (move_to_result.yes) {
entity->local_pos += delta_pos;
} else {
entity->local_pos += move_to_result.next_closest_valid_move;
}
}
static Dqn_Rect FP_Game_GetBuildingPlacementRectForEntity(FP_Game *game, FP_GamePlaceableBuilding placeable_building, FP_GameEntityHandle handle)
{
Dqn_Rect result = {};
FP_GameEntity *entity = FP_Game_GetEntity(game, handle);
if (FP_Game_IsNilEntity(entity))
return result;
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, placeable_building.type, placeable_building.state, entity->direction);
Dqn_Rect box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 build_p = {};
switch (entity->direction) {
case FP_GameDirection_Up: {
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 0.f)) - Dqn_V2_InitNx2(0.f, render_data.render_size.h * .5f + 10.f);
} break;
case FP_GameDirection_Down: {
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 1.f)) + Dqn_V2_InitNx2(0.f, render_data.render_size.h * .5f + 10.f);
} break;
case FP_GameDirection_Left: {
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.0f, 0.5f)) - Dqn_V2_InitNx2(render_data.render_size.w * .5f + 10.f, 0);
} break;
case FP_GameDirection_Right: {
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(1.f, 0.5f)) + Dqn_V2_InitNx2(render_data.render_size.w * .5f + 10.f, 0);
} break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
result.size = render_data.render_size;
result.pos = build_p - (render_data.render_size * .5f);
return result;
}
+68 -31
View File
@@ -158,6 +158,34 @@ enum FP_GameEntityFaction
FP_GameEntityFaction_Foe, FP_GameEntityFaction_Foe,
}; };
enum FP_GameInGameMenu
{
FP_GameInGameMenu_Nil,
FP_GameInGameMenu_Build,
FP_GameInGameMenu_Merchant,
};
struct FP_GameKeyBind
{
TELY_PlatformInputScanCode scan_code;
TELY_PlatformInputGamepadKey gamepad_key;
};
struct FP_GameControls
{
FP_GameKeyBind up;
FP_GameKeyBind down;
FP_GameKeyBind left;
FP_GameKeyBind right;
FP_GameKeyBind attack;
FP_GameKeyBind buy_building;
FP_GameKeyBind buy_upgrade;
FP_GameKeyBind range_attack;
FP_GameKeyBind build_mode;
FP_GameKeyBind strafe;
FP_GameKeyBind dash;
};
struct FP_GameEntity struct FP_GameEntity
{ {
FP_GameEntity *next; FP_GameEntity *next;
@@ -191,10 +219,12 @@ struct FP_GameEntity
// NOTE: The entity hit box is positioned at the center of the entity. // NOTE: The entity hit box is positioned at the center of the entity.
Dqn_V2 local_hit_box_size; Dqn_V2 local_hit_box_size;
Dqn_V2 local_hit_box_offset; Dqn_V2 local_hit_box_offset;
Dqn_f32 trauma01;
Dqn_V2 attack_box_size; Dqn_V2 attack_box_size;
Dqn_V2 attack_box_offset; Dqn_V2 attack_box_offset;
bool attack_processed; bool attack_processed;
Dqn_usize hit_on_clock_ms;
bool is_dying; bool is_dying;
uint64_t last_attack_timestamp; uint64_t last_attack_timestamp;
uint64_t attack_cooldown_ms; uint64_t attack_cooldown_ms;
@@ -238,6 +268,17 @@ struct FP_GameEntity
Dqn_FArray<FP_GameEntityHandle, 3> building_queue; Dqn_FArray<FP_GameEntityHandle, 3> building_queue;
uint64_t building_queue_next_sort_timestamp_ms; uint64_t building_queue_next_sort_timestamp_ms;
FP_GameEntityHandle queued_at_building; FP_GameEntityHandle queued_at_building;
FP_GameInGameMenu in_game_menu;
bool build_mode_can_place_building;
Dqn_usize build_mode_building_index;
FP_GameControls controls;
Dqn_V2 merchant_terry_menu_pos;
Dqn_V2 merchant_graveyard_menu_pos;
Dqn_V2 merchant_gym_menu_pos;
Dqn_V2 merchant_phone_company_menu_pos;
}; };
struct FP_GameEntityIterator struct FP_GameEntityIterator
@@ -257,6 +298,7 @@ struct FP_GameCamera
{ {
Dqn_V2 size; Dqn_V2 size;
Dqn_V2 world_pos; Dqn_V2 world_pos;
Dqn_V2 world_pos_target;
Dqn_f32 rotate_rads; Dqn_f32 rotate_rads;
Dqn_V2 scale; Dqn_V2 scale;
}; };
@@ -281,13 +323,6 @@ enum FP_GameAudio
FP_GameAudio_Count, FP_GameAudio_Count,
}; };
enum FP_GameInGameMenu
{
FP_GameInGameMenu_Nil,
FP_GameInGameMenu_Build,
FP_GameInGameMenu_Merchant,
};
enum FP_GameState enum FP_GameState
{ {
FP_GameState_IntroScreen, FP_GameState_IntroScreen,
@@ -310,7 +345,7 @@ struct FP_GamePlay
FP_GameEntity *entity_free_list; FP_GameEntity *entity_free_list;
FP_GameEntity *map; FP_GameEntity *map;
FP_GameEntityHandle player; Dqn_FArray<FP_GameEntityHandle, 2> players;
FP_GameRenderSprite player_merchant_menu; FP_GameRenderSprite player_merchant_menu;
uint64_t player_trigger_purchase_upgrade_timestamp; uint64_t player_trigger_purchase_upgrade_timestamp;
uint64_t player_trigger_purchase_building_timestamp; uint64_t player_trigger_purchase_building_timestamp;
@@ -328,6 +363,7 @@ struct FP_GamePlay
FP_GameEntityHandle prev_hot_entity; FP_GameEntityHandle prev_hot_entity;
FP_GameEntityHandle prev_active_entity; FP_GameEntityHandle prev_active_entity;
Dqn_FArray<FP_GameEntityHandle, 2> camera_tracking_entity;
FP_GameCamera camera; FP_GameCamera camera;
Dqn_f32 meters_to_pixels; Dqn_f32 meters_to_pixels;
uint64_t clock_ms; uint64_t clock_ms;
@@ -337,9 +373,6 @@ struct FP_GamePlay
bool debug_ui; bool debug_ui;
bool debug_hide_hud; bool debug_hide_hud;
bool god_mode; bool god_mode;
FP_GameInGameMenu in_game_menu;
bool build_mode_can_place_building;
Dqn_usize build_mode_building_index;
Dqn_FArray<FP_GameEntityHandle, 4> mob_spawners; Dqn_FArray<FP_GameEntityHandle, 4> mob_spawners;
Dqn_FArray<FP_GameEntityHandle, 3> portal_monkeys; Dqn_FArray<FP_GameEntityHandle, 3> portal_monkeys;
@@ -352,25 +385,6 @@ struct FP_GamePlay
FP_GameState state; FP_GameState state;
}; };
struct FP_GameKeyBind
{
TELY_PlatformInputScanCode scan_code;
TELY_PlatformInputGamepadKey gamepad_key;
};
struct FP_GameControls
{
FP_GameKeyBind up;
FP_GameKeyBind down;
FP_GameKeyBind left;
FP_GameKeyBind right;
FP_GameKeyBind attack;
FP_GameKeyBind range_attack;
FP_GameKeyBind build_mode;
FP_GameKeyBind strafe;
FP_GameKeyBind dash;
};
struct FP_Game struct FP_Game
{ {
TELY_AssetFontHandle inter_regular_font_large; TELY_AssetFontHandle inter_regular_font_large;
@@ -384,7 +398,6 @@ struct FP_Game
TELY_AssetSpriteSheet atlas_sprite_sheet; TELY_AssetSpriteSheet atlas_sprite_sheet;
TELY_RFui rfui; TELY_RFui rfui;
FP_GamePlay play; FP_GamePlay play;
FP_GameControls controls;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode
@@ -415,3 +428,27 @@ FP_GamePlaceableBuilding const PLACEABLE_BUILDINGS[] = {
{FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle}, {FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle},
{FP_EntityType_KennelTerry, FP_EntityKennelTerryState_Idle}, {FP_EntityType_KennelTerry, FP_EntityKennelTerryState_Idle},
}; };
struct FP_GameCanMoveToPositionResult
{
bool yes;
Dqn_V2 next_closest_valid_move;
};
struct FP_GameCameraM2x3
{
Dqn_M2x3 model_view;
Dqn_M2x3 view_model;
};
Dqn_f32 const FP_GAME_PHYSICS_STEP = 1 / 60.f;
#define FP_Game_MetersToPixelsNx1(game, val) ((val) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsV2(game, xy) (xy * (game).meters_to_pixels)
#define FP_Game_PixelsToMetersNx1(game, val) ((val) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersV2(game, xy) (xy * (1.f/(game).meters_to_pixels))
+1
View File
@@ -67,6 +67,7 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte
#include "feely_pona_entity.h" #include "feely_pona_entity.h"
#include "feely_pona_game.h" #include "feely_pona_game.h"
#include "feely_pona_entity.cpp"
#include "feely_pona_game.cpp" #include "feely_pona_game.cpp"
#include "feely_pona_entity_create.cpp" #include "feely_pona_entity_create.cpp"
#include "feely_pona_misc.cpp" #include "feely_pona_misc.cpp"
+3 -1
View File
@@ -84,6 +84,7 @@ DQN_GCC_WARNING_DISABLE(-Wunused-function)
#include "feely_pona_entity.h" #include "feely_pona_entity.h"
#include "feely_pona_game.h" #include "feely_pona_game.h"
#include "feely_pona_entity.cpp"
#include "feely_pona_game.cpp" #include "feely_pona_game.cpp"
#include "feely_pona_entity_create.cpp" #include "feely_pona_entity_create.cpp"
#include "feely_pona_misc.cpp" #include "feely_pona_misc.cpp"
@@ -92,7 +93,8 @@ DQN_MSVC_WARNING_POP
DQN_GCC_WARNING_POP DQN_GCC_WARNING_POP
#if defined(DQN_PLATFORM_EMSCRIPTEN) #if defined(DQN_PLATFORM_EMSCRIPTEN)
#include <emscripten.h> #include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#endif #endif
// NOTE: TELY_Platform ============================================================================= // NOTE: TELY_Platform =============================================================================
BIN
View File
Binary file not shown.