sdl_runtime_compiler git · main
SDL3 game for running and compiling code at runtime
C++ 72.3% C 26.2%git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gzFix shootdown whitespace And Start fixing shoot down token by angel bug
src/states/game_state.cpp | 4 +-- src/systems/input_system.cpp | 16 +++++------ src/systems/input_system.hpp | 6 ++--- src/systems/projectile_system.cpp | 57 +++++++++------------------------------ src/systems/projectile_system.hpp | 2 -- src/text/handler.cpp | 25 +++++++++++++++-- src/utils/config.hpp | 1 - 7 files changed, 48 insertions(+), 63 deletions(-) diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp index 454d3ac..45d1b0c 100644 --- a/src/states/game_state.cpp +++ b/src/states/game_state.cpp @@ -337,7 +337,7 @@ GameState::on_ShootOne() Aim::Result aim = Aim::crosshair_Target(*_ctx.camera, _ctx.words, _ctx.scenery, _text_walls, World::get_BoxScale()); _projectiles_sys->launch(_projectiles, std::move(single), - _ctx.camera->fwd, _ctx.camera->pos, aim); + _ctx.camera->fwd, aim); if (!_carried.empty() && _carried.last && _carried.last->word) { Wall::show_TokenInfo(_wall_info, _carried.last->word->text); @@ -373,7 +373,7 @@ GameState::on_ShootAll() aim = Aim::crosshair_Target(*_ctx.camera, _ctx.words, _ctx.scenery, _text_walls, World::get_BoxScale()); _projectiles_sys->launch(_projectiles, std::move(all_words), - _ctx.camera->fwd, _ctx.camera->pos, aim); + _ctx.camera->fwd, aim); _level_director->show_Details(_ctx); _level_director->record_Shot (); } diff --git a/src/systems/input_system.cpp b/src/systems/input_system.cpp index 01dab3f..07ab859 100644 --- a/src/systems/input_system.cpp +++ b/src/systems/input_system.cpp @@ -37,11 +37,10 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) } case SDL_EVENT_KEY_DOWN: { SDL_Keycode sym = e.key.key; + const bool ctrl = (e.key.mod & SDL_KMOD_CTRL); - if (input.capture_vim && !input.normal_keys) { - const bool ctrl = (e.key.mod & SDL_KMOD_CTRL); - - if (ctrl) { input.normal_keys = true; break; } + if (input.capture_vim && !input.vim_normal_keys) { + if (ctrl) { input.vim_normal_keys = true; break; } if (sym == SDLK_RETURN) input.vim_keys.push_back(-1); else if (sym == SDLK_ESCAPE) input.vim_keys.push_back(-2); @@ -50,7 +49,6 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) break; } if (input.capture_typing) { - const bool ctrl = (e.key.mod & SDL_KMOD_CTRL); if (ctrl) { switch (sym) { case SDLK_W: input.forward = true; break; @@ -90,7 +88,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) case SDLK_E: input.pick = true; break; case SDLK_X: if (!e.key.repeat) input.commands.push_back(InputCommand::FocusToggle); - break; + break; case SDLK_F1: game.change_State(cpputils::make_unique<GameState>()); break; case SDLK_F2: input.commands.push_back(InputCommand::SandboxRestore);break; @@ -103,7 +101,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) case SDLK_T: input.commands.push_back(InputCommand::TypingStart); break; case SDLK_LSHIFT: case SDLK_RSHIFT: input.commands.push_back(InputCommand::FreelookStart); break; - case SDLK_ESCAPE: game.change_State(cpputils::make_unique<MenuState>()); break; + case SDLK_ESCAPE: if (ctrl) game.change_State(cpputils::make_unique<MenuState>()); break; case SDLK_PLUS: if (e.key.mod & SDL_KMOD_CTRL) { input.commands.push_back(InputCommand::NumberInc); } break; @@ -124,7 +122,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) case SDLK_D: input.right = false; break; case SDLK_E: input.pick = false; break; - case SDLK_LCTRL: input.normal_keys = false; break; + case SDLK_LCTRL: input.vim_normal_keys = false; break; case SDLK_LSHIFT: case SDLK_RSHIFT: @@ -136,7 +134,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) } case SDL_EVENT_TEXT_INPUT: - if (input.capture_vim && !input.normal_keys) { + if (input.capture_vim && !input.vim_normal_keys) { for (const char* p = e.text.text; *p; ++p) input.vim_keys.push_back((unsigned char)*p); } diff --git a/src/systems/input_system.hpp b/src/systems/input_system.hpp index 53ed353..7fbabcb 100644 --- a/src/systems/input_system.hpp +++ b/src/systems/input_system.hpp @@ -40,10 +40,10 @@ struct FrameInput bool pick = false; bool shoot = false;// X held: focus the faced wall - bool normal_keys = false; + bool vim_normal_keys = false; - bool capture_typing = false; - bool capture_vim = false; + bool capture_typing = false; + bool capture_vim = false; bool typing_mode = false; bool typing_commit = false; diff --git a/src/systems/projectile_system.cpp b/src/systems/projectile_system.cpp index bb90fcd..58f7c75 100644 --- a/src/systems/projectile_system.cpp +++ b/src/systems/projectile_system.cpp @@ -238,26 +238,13 @@ beginEditorStick(Projectile& projectile, Wall::Position hit_pos) const double dot = cr_x * wt_x + cr_z * wt_z; const double sign = (dot >= 0.0) ? 1.0 : -1.0; - const Vec3 c_pos = Text::Token::Data::words_centroid(projectile.words); - const double plane = wallPlaneCoord(hit_pos, World::get_BoxScale()); - const bool x_wall = (hit_pos == Wall::Position::NegX || hit_pos == Wall::Position::PosX); - - const double cam_coord = x_wall ? projectile.cam_origin.x : projectile.cam_origin.z; - const double dir_coord = x_wall ? projectile.dir.x : projectile.dir.z; - - Vec3 aim; - if (SDL_fabs(dir_coord) > 1e-6) { - const double t = (plane - cam_coord) / dir_coord; - aim = Vec3{ projectile.cam_origin.x + projectile.dir.x * t, - projectile.cam_origin.y + projectile.dir.y * t, - projectile.cam_origin.z + projectile.dir.z * t }; - } - else { - aim = c_pos; - } - - const double c_tan = wallTangent(hit_pos, aim.x, aim.z); - const double c_y = aim.y; + // Stick where the phrase actually is — its current centroid — NOT where the + // original launch ray would cross the wall. The launch ray ignores the gravity + // arc and is meaningless after a bounce (it would teleport the word, which is + // why bounced shots used to respawn near the world centre). + const Vec3 c_pos = Text::Token::Data::words_centroid(projectile.words); + const double c_tan = wallTangent(hit_pos, c_pos.x, c_pos.z); + const double c_y = c_pos.y; for (Text::TokenPtr& w : projectile.words) { if (!w || w->type != ObjectType::Text) continue; @@ -334,23 +321,6 @@ bounceOffWall(Projectile& projectile, Wall::Position hit_pos, double ws, } -static double -editorAimY(const Projectile& projectile, double plane_x) -{ - if (SDL_fabs(projectile.dir.x) <= 1e-6) return Text::Token::Data::words_centroid(projectile.words).y; - const double param_dist = (plane_x - projectile.cam_origin.x) / projectile.dir.x; - return projectile.cam_origin.y + projectile.dir.y * param_dist; -} - -static double -editorAimZ(const Projectile& projectile, double plane_x) -{ - if (SDL_fabs(projectile.dir.x) <= 1e-6) return Text::Token::Data::words_centroid(projectile.words).z; - const double param_dist = (plane_x - projectile.cam_origin.x) / projectile.dir.x; - return projectile.cam_origin.z + projectile.dir.z * param_dist; -} - - static bool handleWallHit(Projectile& projectile, const Vec3& centroid, Wall::Position hit_pos, double dt,double ws, @@ -364,9 +334,10 @@ handleWallHit(Projectile& projectile, const Vec3& centroid, Wall::Position hit_p } const bool editor = (Wall::role_Of(hit_pos) == Wall::Role::Editor); - const double plane = wallPlaneCoord(hit_pos, ws); - const double aim_y = editor ? editorAimY(projectile, plane) : 0.0; - const double aim_z = editor ? editorAimZ(projectile, plane) : 0.0; + // Aim at where the phrase ACTUALLY is (its current centroid), so the gravity + // arc and any prior bounce are respected. The old launch-ray aim ignored both. + const double aim_y = editor ? centroid.y : 0.0; + const double aim_z = editor ? centroid.z : 0.0; size_t hit_idx = 0; if (projectile.words.size() == 1 && @@ -395,7 +366,6 @@ void ProjectileSystem::launch(DynArray<Projectile>& out, DynArray<Text::TokenPtr> words, const Vec3& fwd, - const Vec3& eye, const Aim::Result& aim) { if (words.empty()) return; @@ -443,7 +413,6 @@ ProjectileSystem::launch(DynArray<Projectile>& out, proj.words = std::move(words); proj.dir = fwd; proj.launch_origin = centroid; - proj.cam_origin = eye; proj.prev_centroid = centroid; if (aim.track) { @@ -457,8 +426,8 @@ ProjectileSystem::launch(DynArray<Projectile>& out, void -ProjectileSystem::update(DynArray<Projectile>& projectiles, - DynArray<ProjectileResult>& results, +ProjectileSystem::update(DynArray<Projectile>& projectiles, + DynArray<ProjectileResult>& results, const DynArray<WallTextHitTest>& wall_text_hits, double dt, bool program_running) { diff --git a/src/systems/projectile_system.hpp b/src/systems/projectile_system.hpp index 2859e71..c57a3f9 100644 --- a/src/systems/projectile_system.hpp +++ b/src/systems/projectile_system.hpp @@ -31,7 +31,6 @@ struct Projectile Vec3 dir{}; Vec3 prev_centroid{}; Vec3 launch_origin{}; - Vec3 cam_origin {}; Vec3 track_local {}; Vec3 track_last {}; @@ -82,7 +81,6 @@ struct ProjectileSystem void launch(DynArray<Projectile>& out, DynArray<Text::TokenPtr> words, const Vec3& fwd, - const Vec3& eye, const Aim::Result& aim); void update(DynArray<Projectile>& projectiles, diff --git a/src/text/handler.cpp b/src/text/handler.cpp index c3be681..e519633 100644 --- a/src/text/handler.cpp +++ b/src/text/handler.cpp @@ -576,14 +576,35 @@ Handler::classify_Impact(const Vec3& impact) const const double vcf = (_code_left_z - impact.z) / _char_w; // fractional visual column int vcol = 0; size_t b = 0; size_t k = 0; + + // Split exactly like relayout_Mono: each space/tab is one cell, and a + // non-whitespace run is lexically split into word / operator-group / + // single-punctuation sub-tokens. This keeps `k` in lock-step with + // line.tokens, so a DropToken's token_idx points at the token actually + // aimed at — previously a run was one coarse cell, so token_idx skewed and + // the caller detached the wrong token (often whitespace, esp. in sandbox). + auto is_word = [](char cc) { + return (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z') + || (cc >= '0' && cc <= '9') || cc == '_'; + }; + auto is_op = [](char cc) { + for (const char* o = "+-*/%=<>!&|^~.:?"; *o; ++o) if (*o == cc) return true; + return false; + }; + while (b < s.size()) { const char c = s[b]; int b0 = static_cast<int>(b), b1, vc = vcol, vs; bool ws; if (c == ' ') { b1 = b0 + 1; vs = 1; ws = true; ++b; } else if (c == '\t') { b1 = b0 + 1; vs = 4 - (vcol%4); ws = true; ++b; } - else { size_t s0 = b; while (b < s.size() && s[b] != ' ' && s[b] != '\t') ++b; - b1 = static_cast<int>(b); vs = static_cast<int>(b - s0); ws = false; } + else { + const size_t s0 = b; + if (is_word(c)) { while (b < s.size() && is_word(s[b])) ++b; } + else if (is_op(c)) { while (b < s.size() && is_op(s[b])) ++b; } + else { ++b; } // single bracket / ; , quote … + b1 = static_cast<int>(b); vs = static_cast<int>(b - s0); ws = false; + } if (vcf >= vc && vcf < vc + vs) { if (ws) { hit.kind = HitKind::Insert; hit.col = b1; return hit; } // split: word after the space diff --git a/src/utils/config.hpp b/src/utils/config.hpp index 4b6c66d..c61dc7f 100644 --- a/src/utils/config.hpp +++ b/src/utils/config.hpp @@ -12,7 +12,6 @@ Config namespace Game { -static constexpr int max_substeps = 4; static constexpr float world_box_scale = 16.f; }