From e80673ecb59c57674d8ed753b09a81f757bb2062 Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Mon, 16 Aug 2021 19:12:00 +0200 Subject: [PATCH] lua api for lighting --- src/scene/game_scene.rs | 39 +++++++++++++++++++----------- src/scripting/boot.lua | 39 ++++++++++++++++++++++++++++++ src/scripting/doukutsu.d.ts | 27 +++++++++++++++++++++ src/scripting/doukutsu.rs | 48 +++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 14 deletions(-) diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 28a36a2..8d3c3e7 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -57,6 +57,7 @@ pub struct GameScene { pub npc_list: NPCList, pub boss: BossNPC, pub bullet_manager: BulletManager, + pub lighting_mode: LightingMode, pub intro_mode: bool, tex_background_name: String, tex_tileset_name: String, @@ -75,6 +76,14 @@ pub enum TileLayer { Snack, } + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum LightingMode { + None, + BackgroundOnly, + Ambient, +} + const FACE_TEX: &str = "Face"; const SWITCH_FACE_TEX: [&str; 4] = ["Face1", "Face2", "Face3", "Face4"]; const P2_LEFT_TEXT: &str = "< P2"; @@ -141,6 +150,7 @@ impl GameScene { npc_list: NPCList::new(), boss: BossNPC::new(), bullet_manager: BulletManager::new(), + lighting_mode: LightingMode::None, intro_mode: false, tex_background_name, tex_tileset_name, @@ -1779,6 +1789,19 @@ impl Scene for GameScene { self.frame.target_y = self.player1.y; self.frame.immediate_update(state, &self.stage); + self.lighting_mode = match () { + _ if self.intro_mode => LightingMode::None, + _ if !state.constants.is_switch && (self.stage.data.background_type == BackgroundType::Black + || self.stage.data.background.name() == "bkBlack") => LightingMode::Ambient, + _ if state.constants.is_switch && (self.stage.data.background_type == BackgroundType::Black + || self.stage.data.background.name() == "bkBlack") => LightingMode::None, + _ if self.stage.data.background_type != BackgroundType::Black + && self.stage.data.background_type != BackgroundType::Outside + && self.stage.data.background_type != BackgroundType::OutsideWind + && self.stage.data.background.name() != "bkBlack" => LightingMode::BackgroundOnly, + _ => LightingMode::None, + }; + Ok(()) } @@ -1925,12 +1948,7 @@ impl Scene for GameScene { self.draw_npc_layer(state, ctx, NPCLayer::Background)?; self.draw_tiles(state, ctx, TileLayer::Middleground)?; - if state.settings.shader_effects - && self.stage.data.background_type != BackgroundType::Black - && self.stage.data.background_type != BackgroundType::Outside - && self.stage.data.background_type != BackgroundType::OutsideWind - && self.stage.data.background.name() != "bkBlack" - { + if state.settings.shader_effects && self.lighting_mode == LightingMode::BackgroundOnly { self.draw_light_map(state, ctx)?; } @@ -1947,18 +1965,11 @@ impl Scene for GameScene { self.player1.popup.draw(state, ctx, &self.frame)?; self.player2.popup.draw(state, ctx, &self.frame)?; - if !self.intro_mode - && state.settings.shader_effects - && (self.stage.data.background_type == BackgroundType::Black - || self.stage.data.background.name() == "bkBlack") - { + if state.settings.shader_effects && self.lighting_mode == LightingMode::Ambient { self.draw_light_map(state, ctx)?; } self.flash.draw(state, ctx, &self.frame)?; - /*graphics::set_canvas(ctx, None); - state.game_canvas.draw(ctx, DrawParam::new() - .scale(Vector2::new(1.0 / state.scale, 1.0 / state.scale)))?;*/ self.draw_black_bars(state, ctx)?; match state.textscript_vm.mode { diff --git a/src/scripting/boot.lua b/src/scripting/boot.lua index 7c9a7ad..3c14922 100644 --- a/src/scripting/boot.lua +++ b/src/scripting/boot.lua @@ -49,6 +49,16 @@ ModCS = { Sound = {}, } +__doukutsu_rs_runtime_dont_touch._known_settings = { + ["doukutsu-rs.intro.event_id"] = 0x1000, + ["doukutsu-rs.intro.stage_id"] = 0x1001, + ["doukutsu-rs.intro.pos"] = 0x1002, + ["doukutsu-rs.new_game.event_id"] = 0x1003, + ["doukutsu-rs.new_game.stage_id"] = 0x1004, + ["doukutsu-rs.new_game.pos"] = 0x1005, + ["doukutsu-rs.font_scale"] = 0x2000, +} + __doukutsu_rs_runtime_dont_touch._requires = {} require = function(modname) @@ -332,6 +342,26 @@ end __doukutsu_rs_runtime_dont_touch._playerRef0 = __doukutsu_rs_runtime_dont_touch._createPlayerRef(0) __doukutsu_rs_runtime_dont_touch._playerRef1 = __doukutsu_rs_runtime_dont_touch._createPlayerRef(1) +doukutsu.rs = {} +setmetatable(doukutsu.rs, { + __index = function(self, property) + if property == "lightingMode" then + return __doukutsu_rs:stageCommand(0x01) + elseif property == "lightingEnabled" then + return __doukutsu_rs:stageCommand(0x02) + else + return nil + end + end, + __newindex = function(self, property, val) + if property == "lightingMode" then + __doukutsu_rs:stageCommand(0x101, val) + end + + return nil + end, +}) + doukutsu.player = __doukutsu_rs_runtime_dont_touch._playerRef0 function doukutsu.playSfx(id) @@ -350,6 +380,15 @@ function doukutsu.players() return { __doukutsu_rs_runtime_dont_touch._playerRef0, __doukutsu_rs_runtime_dont_touch._playerRef1 } end +function doukutsu.setSetting(key, value) + assert(type(key) == "string", "key must be a string.") + + local id = __doukutsu_rs_runtime_dont_touch._known_settings[key] + if id ~= nil then + __doukutsu_rs:setEngineConstant(id, value) + end +end + function doukutsu.setNPCHandler(npc_type, handler) assert(type(npc_type) == "number", "npc type must be an integer.") diff --git a/src/scripting/doukutsu.d.ts b/src/scripting/doukutsu.d.ts index c6f9805..3b05c91 100644 --- a/src/scripting/doukutsu.d.ts +++ b/src/scripting/doukutsu.d.ts @@ -181,6 +181,21 @@ declare interface DoukutsuPlayer { damage(value: number): void; } +declare interface DoukutsuRSApi { + /** + * Lighting mode of current stage. + * "none" - no lighting, similar to vanilla. + * "backgroundOnly" - lighting only affects background layer, similar to Switch version. + * "ambient" - lighting affects everything. + */ + lightingMode: "none" | "backgroundOnly" | "ambient"; + + /** + * This property is true if lighting is enabled in settings. + */ + readonly lightingEnabled: boolean; +} + declare namespace doukutsu { /** * A reference to main locally controlled player. @@ -188,6 +203,11 @@ declare namespace doukutsu { */ const player: DoukutsuPlayer; + /** + * Helper property for doukutsu-rs specific APIs. + */ + const rs: DoukutsuRSApi; + /** * Plays a sound effect with specified ID. */ @@ -248,6 +268,13 @@ declare namespace doukutsu { */ function setSetting(name: string, value: any): void; + /** + * Sets an implementation-defined stage parameter. + * @param name + * @param value + */ + function setStageParam(name: string, value: any): void; + /** * Sets the handler override for specified NPC type. Passing a null removes the handler. * @param npcType diff --git a/src/scripting/doukutsu.rs b/src/scripting/doukutsu.rs index 1867510..6418988 100644 --- a/src/scripting/doukutsu.rs +++ b/src/scripting/doukutsu.rs @@ -7,6 +7,7 @@ use crate::common::{Direction, Rect}; use crate::framework::filesystem; use crate::rng::RNG; use crate::scripting::{check_status, LuaScriptingState, DRS_RUNTIME_GLOBAL}; +use crate::scene::game_scene::LightingMode; pub struct Doukutsu { pub ptr: *mut LuaScriptingState, @@ -153,6 +154,14 @@ impl Doukutsu { game_state.constants.game.new_game_player_pos = (ng_x as i16, ng_y as i16); } } + 0x2000 => { + // font scale + if let Some(font_scale) = state.to_float(3) { + if font_scale > 0.0 { + game_state.constants.font_scale = font_scale; + } + } + } _ => {} } } @@ -414,6 +423,44 @@ impl Doukutsu { 1 } + unsafe fn lua_stage_command(&self, state: &mut State) -> c_int { + if (*self.ptr).game_scene.is_null() { + state.push_nil(); + return 1; + } + + if let Some(param_type) = state.to_int(2) { + let game_scene = &mut *(*self.ptr).game_scene; + let game_state = &mut *(*self.ptr).state_ptr; + + match param_type { + 0x01 => state.push(match game_scene.lighting_mode { + LightingMode::None => "none", + LightingMode::BackgroundOnly => "backgroundOnly", + LightingMode::Ambient => "ambient", + }), + 0x02 => state.push(game_state.settings.shader_effects), + 0x101 => { + if let Some(v) = state.to_str(4) { + game_scene.lighting_mode = match v { + "none" => LightingMode::None, + "backgroundOnly" => LightingMode::BackgroundOnly, + "ambient" => LightingMode::Ambient, + _ => game_scene.lighting_mode, + }; + } + + state.push_nil(); + } + _ => state.push_nil(), + } + } else { + state.push_nil() + } + + 1 + } + unsafe fn lua_load_script(&mut self, state: &mut State) -> c_int { let lua_state = &mut (*self.ptr); @@ -478,6 +525,7 @@ impl LuaObject for Doukutsu { lua_method!("setEngineConstant", Doukutsu, Doukutsu::lua_set_engine_constant), lua_method!("playerCommand", Doukutsu, Doukutsu::lua_player_command), lua_method!("npcCommand", Doukutsu, Doukutsu::lua_npc_command), + lua_method!("stageCommand", Doukutsu, Doukutsu::lua_stage_command), lua_method!("loadScript", Doukutsu, Doukutsu::lua_load_script), ] }