mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-07-28 07:54:08 +00:00
Compare commits
5 commits
9e21838a9d
...
ad4fc4b481
Author | SHA1 | Date | |
---|---|---|---|
|
ad4fc4b481 | ||
|
035b2c2848 | ||
|
20be51bb72 | ||
|
203a4a1180 | ||
|
5f259b572e |
|
@ -35,6 +35,7 @@ cache:
|
||||||
# - cargo test --verbose --all --no-fail-fast
|
# - cargo test --verbose --all --no-fail-fast
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
|
- set DRS_BUILD_VERSION_OVERRIDE=%APPVEYOR_BUILD_VERSION%
|
||||||
- cargo build --release --bin doukutsu-rs
|
- cargo build --release --bin doukutsu-rs
|
||||||
- mkdir release
|
- mkdir release
|
||||||
- copy target\release\doukutsu-rs.exe release
|
- copy target\release\doukutsu-rs.exe release
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
authors = ["Alula <julekonopinska@gmail.com>"]
|
authors = ["Alula"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "doukutsu-rs"
|
name = "doukutsu-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -11,16 +11,18 @@ layout (std140) uniform Globals {
|
||||||
|
|
||||||
layout (std140) uniform WaterShaderParams {
|
layout (std140) uniform WaterShaderParams {
|
||||||
vec2 u_Resolution;
|
vec2 u_Resolution;
|
||||||
|
vec2 u_FramePos;
|
||||||
float u_Tick;
|
float u_Tick;
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 wave = v_Uv;
|
vec2 wave = v_Uv;
|
||||||
wave.x += sin(v_Uv.x * 40.0 + u_Tick / 20.0) * (sin(u_Tick / 10.0) * 0.01);
|
wave.x += sin((-u_FramePos.y / u_Resolution.y + v_Uv.x * 16.0) + u_Tick / 20.0) * 2.0 / u_Resolution.x;
|
||||||
wave.y -= cos(v_Uv.y * 20.0 + u_Tick / 5.0) * (sin(u_Tick / 20.0) * 0.01);
|
wave.y -= cos((-u_FramePos.x / u_Resolution.x + v_Uv.y * 16.0) + u_Tick / 5.0) * 2.0 / u_Resolution.y;
|
||||||
float off = 0.4 / u_Resolution.y;
|
float off = 0.4 / u_Resolution.y;
|
||||||
vec4 color = texture(t_Texture, wave);
|
vec4 color = texture(t_Texture, wave);
|
||||||
color.r = texture(t_Texture, wave + off).r;
|
color.r = texture(t_Texture, wave + off).r;
|
||||||
color.b = texture(t_Texture, wave - off).b;
|
color.b = texture(t_Texture, wave - off).b;
|
||||||
Target0 = vec4(0.7, 0.8, 1.2, 1.0) * color * v_Color;
|
|
||||||
|
Target0 = (vec4(0.4, 0.6, 0.8, 1.0) * 0.3) + (color * v_Color * 0.7);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use num_traits::{AsPrimitive, Num};
|
use num_traits::{AsPrimitive, Num};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde::de::{SeqAccess, Visitor};
|
||||||
|
use serde::ser::SerializeTupleStruct;
|
||||||
|
|
||||||
use crate::bitfield;
|
use crate::bitfield;
|
||||||
|
|
||||||
/// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this to get
|
/// Multiply cave story degrees (0-255, which corresponds to 0°-360°) with this to get
|
||||||
/// respective value in radians.
|
/// respective value in radians.
|
||||||
pub const CDEG_RAD: f64 = std::f64::consts::PI / 128.0;
|
pub const CDEG_RAD: f64 = std::f64::consts::PI / 128.0;
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref VERSION_BANNER: String = {
|
||||||
|
let version = option_env!("DRS_BUILD_VERSION_OVERRIDE").unwrap_or(env!("CARGO_PKG_VERSION"));
|
||||||
|
format!("doukutsu-rs {}", version)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -217,7 +227,7 @@ impl Direction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
|
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
|
||||||
pub left: T,
|
pub left: T,
|
||||||
pub top: T,
|
pub top: T,
|
||||||
|
@ -279,6 +289,63 @@ impl<T: Num + PartialOrd + Copy + AsPrimitive<f32>> Into<ggez::graphics::Rect> f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Num + PartialOrd + Copy + Serialize> Serialize for Rect<T> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_tuple_struct("Rect", 4)?;
|
||||||
|
state.serialize_field(&self.left)?;
|
||||||
|
state.serialize_field(&self.top)?;
|
||||||
|
state.serialize_field(&self.right)?;
|
||||||
|
state.serialize_field(&self.bottom)?;
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro_rules! rect_deserialze {
|
||||||
|
($num_type: ident) => {
|
||||||
|
impl<'de> Deserialize<'de> for Rect<$num_type> {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Rect<$num_type>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct RectVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for RectVisitor {
|
||||||
|
type Value = Rect<$num_type>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("Expected Rect structure.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: SeqAccess<'de>
|
||||||
|
{
|
||||||
|
let invalid_length = || {
|
||||||
|
de::Error::invalid_length(0, &self)
|
||||||
|
};
|
||||||
|
|
||||||
|
let left = seq.next_element()?.ok_or_else(invalid_length)?;
|
||||||
|
let top = seq.next_element()?.ok_or_else(invalid_length)?;
|
||||||
|
let right = seq.next_element()?.ok_or_else(invalid_length)?;
|
||||||
|
let bottom = seq.next_element()?.ok_or_else(invalid_length)?;
|
||||||
|
|
||||||
|
Ok(Rect { left, top, right, bottom })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_tuple_struct("Rect", 4, RectVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rect_deserialze!(u8);
|
||||||
|
rect_deserialze!(u16);
|
||||||
|
rect_deserialze!(isize);
|
||||||
|
rect_deserialze!(usize);
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fix9_scale(val: isize, scale: f32) -> f32 {
|
pub fn fix9_scale(val: isize, scale: f32) -> f32 {
|
||||||
(val as f64 * scale as f64 / 512.0).floor() as f32 / scale
|
(val as f64 * scale as f64 / 512.0).floor() as f32 / scale
|
||||||
|
|
|
@ -163,7 +163,6 @@ impl Game {
|
||||||
fn key_down_event(&mut self, key_code: KeyCode, _key_mod: KeyMods, repeat: bool) {
|
fn key_down_event(&mut self, key_code: KeyCode, _key_mod: KeyMods, repeat: bool) {
|
||||||
if repeat { return; }
|
if repeat { return; }
|
||||||
|
|
||||||
// todo: proper keymaps?
|
|
||||||
let state = &mut self.state;
|
let state = &mut self.state;
|
||||||
match key_code {
|
match key_code {
|
||||||
KeyCode::F7 => { state.set_speed(1.0) }
|
KeyCode::F7 => { state.set_speed(1.0) }
|
||||||
|
|
|
@ -318,6 +318,10 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_npc_collisions(&mut self, id: TargetPlayer, state: &mut SharedGameState, npc_map: &mut NPCMap, inventory: &mut Inventory) {
|
pub fn tick_npc_collisions(&mut self, id: TargetPlayer, state: &mut SharedGameState, npc_map: &mut NPCMap, inventory: &mut Inventory) {
|
||||||
|
if !self.cond.alive() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for npc_cell in npc_map.npcs.values() {
|
for npc_cell in npc_map.npcs.values() {
|
||||||
let mut npc = npc_cell.borrow_mut();
|
let mut npc = npc_cell.borrow_mut();
|
||||||
if !npc.cond.alive() { continue; }
|
if !npc.cond.alive() { continue; }
|
||||||
|
|
|
@ -649,8 +649,11 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_water(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn draw_water(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
|
||||||
|
|
||||||
{
|
{
|
||||||
state.shaders.water_shader_params.resolution = [state.canvas_size.0, state.canvas_size.1];
|
state.shaders.water_shader_params.resolution = [state.canvas_size.0, state.canvas_size.1];
|
||||||
|
state.shaders.water_shader_params.frame_pos = [frame_x, frame_y];
|
||||||
state.shaders.water_shader_params.t = self.tick as f32;
|
state.shaders.water_shader_params.t = self.tick as f32;
|
||||||
let _lock = graphics::use_shader(ctx, &state.shaders.water_shader);
|
let _lock = graphics::use_shader(ctx, &state.shaders.water_shader);
|
||||||
state.shaders.water_shader.send(ctx, state.shaders.water_shader_params)?;
|
state.shaders.water_shader.send(ctx, state.shaders.water_shader_params)?;
|
||||||
|
@ -666,8 +669,6 @@ impl GameScene {
|
||||||
// cheap, clones a reference underneath
|
// cheap, clones a reference underneath
|
||||||
let mut tmp_batch = SpriteBatch::new(state.tmp_canvas.image().clone());
|
let mut tmp_batch = SpriteBatch::new(state.tmp_canvas.image().clone());
|
||||||
|
|
||||||
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
|
|
||||||
|
|
||||||
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize;
|
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize;
|
||||||
let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize;
|
let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize;
|
||||||
let tile_end_x = clamp((self.frame.x / 0x200 + 8 + state.canvas_size.0 as isize) / 16 + 1, 0, self.stage.map.width as isize) as usize;
|
let tile_end_x = clamp((self.frame.x / 0x200 + 8 + state.canvas_size.0 as isize) / 16 + 1, 0, self.stage.map.width as isize) as usize;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use ggez::{Context, GameResult, graphics};
|
use ggez::{Context, GameResult, graphics};
|
||||||
use ggez::graphics::Color;
|
use ggez::graphics::Color;
|
||||||
|
|
||||||
use crate::common::Rect;
|
use crate::common::{Rect, VERSION_BANNER};
|
||||||
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::shared_game_state::{SharedGameState, TimingMode};
|
use crate::shared_game_state::{SharedGameState, TimingMode};
|
||||||
|
@ -75,7 +75,6 @@ impl TitleScene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ENGINE_VERSION: &str = "doukutsu-rs 0.1.0";
|
|
||||||
// asset copyright for freeware version
|
// asset copyright for freeware version
|
||||||
static COPYRIGHT_PIXEL: &str = "2004.12 Studio Pixel";
|
static COPYRIGHT_PIXEL: &str = "2004.12 Studio Pixel";
|
||||||
// asset copyright for Nicalis
|
// asset copyright for Nicalis
|
||||||
|
@ -235,7 +234,7 @@ impl Scene for TitleScene {
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_text_centered(ENGINE_VERSION, state.canvas_size.1 - 15.0, state, ctx)?;
|
self.draw_text_centered(VERSION_BANNER.as_str(), state.canvas_size.1 - 15.0, state, ctx)?;
|
||||||
|
|
||||||
if state.constants.is_switch {
|
if state.constants.is_switch {
|
||||||
self.draw_text_centered(COPYRIGHT_NICALIS_SWITCH, state.canvas_size.1 - 30.0, state, ctx)?;
|
self.draw_text_centered(COPYRIGHT_NICALIS_SWITCH, state.canvas_size.1 - 30.0, state, ctx)?;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use ggez::{Context, GameResult};
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
constant WaterShaderParams {
|
constant WaterShaderParams {
|
||||||
resolution: [f32; 2] = "u_Resolution",
|
resolution: [f32; 2] = "u_Resolution",
|
||||||
|
frame_pos: [f32; 2] = "u_FramePos",
|
||||||
t: f32 = "u_Tick",
|
t: f32 = "u_Tick",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +20,7 @@ impl Shaders {
|
||||||
let water_shader_params = WaterShaderParams {
|
let water_shader_params = WaterShaderParams {
|
||||||
t: 0.0,
|
t: 0.0,
|
||||||
resolution: [0.0, 0.0],
|
resolution: [0.0, 0.0],
|
||||||
|
frame_pos: [0.0, 0.0],
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Shaders {
|
Ok(Shaders {
|
||||||
|
|
Loading…
Reference in a new issue