Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions assets/elements/item/periscope/bullet/periscope.bullet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
lifetime: 1.0
speed: 600
body_diameter: 15
atlas: ./periscope_bullet.atlas.yaml

explosion_fps: 12
explosion_frames: 3
explosion_volume: 0.025
explosion_lifetime: 0.4
explosion_sound: ../explosion/bullet_hit_dull.ogg
explosion_atlas: ../explosion/explosion.atlas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
image: ./periscope_bullet.png
tile_size: [15, 15]
rows: 1
columns: 1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
4 changes: 4 additions & 0 deletions assets/elements/item/periscope/explosion/explosion.atlas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
image: ./explosion.png
tile_size: [21, 21]
rows: 1
columns: 4
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/elements/item/periscope/periscope.atlas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
image: ./periscope.png
tile_size: [50, 74]
rows: 1
columns: 1
3 changes: 3 additions & 0 deletions assets/elements/item/periscope/periscope.element.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: Periscope
category: Weapons
data: periscope.yaml
Binary file added assets/elements/item/periscope/periscope.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions assets/elements/item/periscope/periscope.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
atlas: ./periscope.atlas.yaml

max_ammo: 6
cooldown: 700ms
bullet_meta: ./bullet/periscope.bullet.yaml

shoot_fps: 15
shoot_frames: 3
shoot_lifetime: 0.2
shoot_sound_volume: 0.1
shoot_sound: ./shoot/shoot.ogg
empty_shoot_sound_volume: 0.1
empty_shoot_sound: ./shoot/gun_empty.ogg
shoot_atlas: ./shoot/periscope_shoot.atlas.yaml

bounciness: 0.3
can_rotate: true
body_size: [32, 44]
fin_anim: grab_2
angular_velocity: 0.1
throw_velocity: 180
grab_offset: [-2, 24]
kickback: 0
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
image: ./periscope_fire.png
tile_size: [25, 30]
rows: 1
columns: 4
Binary file added assets/elements/item/periscope/shoot/shoot.ogg
Binary file not shown.
1 change: 1 addition & 0 deletions assets/game.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ core:
- /elements/item/mine/mine.element.yaml
- /elements/item/musket/musket.element.yaml
- /elements/item/buss/buss.element.yaml
- /elements/item/periscope/periscope.element.yaml
- /elements/item/stomp_boots/stomp_boots.element.yaml
- /elements/item/sword/sword.element.yaml
- /elements/item/sniper_rifle/sniper_rifle.element.yaml
Expand Down
2 changes: 1 addition & 1 deletion assets/map/levels/level_7.map.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,7 @@ layers:
- pos:
- 712.0
- 182.5
element: /elements/item/buss/buss.element.yaml
element: /elements/item/periscope/periscope.element.yaml
- pos:
- 552.0
- 438.5
Expand Down
7 changes: 5 additions & 2 deletions src/core/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod jellyfish;
pub mod kick_bomb;
pub mod mine;
pub mod musket;
pub mod periscope;
pub mod player_spawner;
pub mod slippery;
pub mod slippery_seaweed;
Expand All @@ -30,8 +31,9 @@ pub mod urchin;
pub mod prelude {
pub use super::{
buss::*, crab::*, crate_item::*, decoration::*, fish_school::*, grenade::*, jellyfish::*,
kick_bomb::*, mine::*, musket::*, player_spawner::*, slippery::*, slippery_seaweed::*,
snail::*, spike::*, sproinger::*, stomp_boots::*, sword::*, urchin::*, *,
kick_bomb::*, mine::*, musket::*, periscope::*, player_spawner::*, slippery::*,
slippery_seaweed::*, snail::*, spike::*, sproinger::*, stomp_boots::*, sword::*, urchin::*,
*,
};
}

Expand Down Expand Up @@ -317,6 +319,7 @@ install_plugins!(
musket,
buss,
player_spawner,
periscope,
slippery_seaweed,
slippery,
snail,
Expand Down
288 changes: 288 additions & 0 deletions src/core/elements/periscope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
use crate::prelude::*;

#[derive(HasSchema, Default, Debug, Clone)]
#[type_data(metadata_asset("periscope"))]
#[repr(C)]
pub struct PeriscopeMeta {
pub grab_offset: Vec2,
pub fin_anim: Ustr,

pub body_size: Vec2,
pub bounciness: f32,
pub can_rotate: bool,
pub throw_velocity: f32,
pub angular_velocity: f32,
pub atlas: Handle<Atlas>,

pub max_ammo: u32,
pub cooldown: Duration,
pub bullet_meta: Handle<BulletMeta>,
pub kickback: f32,

pub shoot_fps: f32,
pub shoot_lifetime: f32,
pub shoot_frames: u32,
pub shoot_sound_volume: f64,
pub empty_shoot_sound_volume: f64,
pub shoot_atlas: Handle<Atlas>,
pub shoot_sound: Handle<AudioSource>,
pub empty_shoot_sound: Handle<AudioSource>,
}

pub fn game_plugin(game: &mut Game) {
PeriscopeMeta::register_schema();
game.init_shared_resource::<AssetServer>();
}

pub fn session_plugin(session: &mut Session) {
session
.stages
.add_system_to_stage(CoreStage::PreUpdate, hydrate)
.add_system_to_stage(CoreStage::PostUpdate, update);
}

#[derive(Clone, Debug, HasSchema, Default)]
pub struct Periscope {
pub ammo: u32,
pub cooldown: Timer,
}

fn hydrate(
game_meta: Root<GameMeta>,
mut entities: ResMutInit<Entities>,
mut hydrated: CompMut<MapElementHydrated>,
mut element_handles: CompMut<ElementHandle>,
assets: Res<AssetServer>,
mut periscopes: CompMut<Periscope>,
mut atlas_sprites: CompMut<AtlasSprite>,
mut bodies: CompMut<KinematicBody>,
mut transforms: CompMut<Transform>,
mut items: CompMut<Item>,
mut item_throws: CompMut<ItemThrow>,
mut item_grabs: CompMut<ItemGrab>,
mut respawn_points: CompMut<DehydrateOutOfBounds>,
mut spawner_manager: SpawnerManager,
) {
let mut not_hydrated_bitset = hydrated.bitset().clone();
not_hydrated_bitset.bit_not();
not_hydrated_bitset.bit_and(element_handles.bitset());

let spawner_entities = entities
.iter_with_bitset(&not_hydrated_bitset)
.collect::<Vec<_>>();

for spawner_ent in spawner_entities {
let transform = *transforms.get(spawner_ent).unwrap();
let element_handle = *element_handles.get(spawner_ent).unwrap();
let element_meta = assets.get(element_handle.0);

if let Ok(PeriscopeMeta {
atlas,
fin_anim,
grab_offset,
max_ammo,
body_size,
can_rotate,
bounciness,
throw_velocity,
angular_velocity,
..
}) = assets.get(element_meta.data).try_cast_ref()
{
hydrated.insert(spawner_ent, MapElementHydrated);

let entity = entities.create();
items.insert(entity, Item);
item_throws.insert(
entity,
ItemThrow::strength(*throw_velocity)
.with_spin(*angular_velocity)
.with_system(periscope_drop(entity, *max_ammo)),
);
item_grabs.insert(
entity,
ItemGrab {
fin_anim: *fin_anim,
sync_animation: false,
grab_offset: *grab_offset,
},
);
periscopes.insert(
entity,
Periscope {
ammo: *max_ammo,
cooldown: Timer::new(Duration::from_millis(0), TimerMode::Once),
},
);
atlas_sprites.insert(entity, AtlasSprite::new(*atlas));
respawn_points.insert(entity, DehydrateOutOfBounds(spawner_ent));
transforms.insert(entity, transform);
element_handles.insert(entity, element_handle);
hydrated.insert(entity, MapElementHydrated);
bodies.insert(
entity,
KinematicBody {
shape: ColliderShape::Rectangle { size: *body_size },
has_mass: true,
has_friction: true,
can_rotate: *can_rotate,
bounciness: *bounciness,
gravity: game_meta.core.physics.gravity,
..default()
},
);
spawner_manager.create_spawner(spawner_ent, vec![entity])
}
}
}

fn update(
entities: Res<Entities>,
mut commands: Commands,
element_handles: Comp<ElementHandle>,
assets: Res<AssetServer>,

mut periscopes: CompMut<Periscope>,
transforms: CompMut<Transform>,
mut sprites: CompMut<AtlasSprite>,
mut audio_center: ResMut<AudioCenter>,

player_inventories: PlayerInventories,
mut items_used: CompMut<ItemUsed>,
items_dropped: CompMut<ItemDropped>,
time: Res<Time>,

mut bodies: CompMut<KinematicBody>,
) {
for (entity, (periscope, element_handle)) in
entities.iter_with((&mut periscopes, &element_handles))
{
let element_meta = assets.get(element_handle.0);

let asset = assets.get(element_meta.data);
let Ok(PeriscopeMeta {
max_ammo,
shoot_fps,
shoot_atlas,
shoot_frames,
shoot_lifetime,
cooldown,
bullet_meta,
shoot_sound,
empty_shoot_sound,
shoot_sound_volume,
empty_shoot_sound_volume,
kickback,
..
}) = asset.try_cast_ref()
else {
unreachable!();
};

periscope.cooldown.tick(time.delta());

// If the item is being held
if let Some(Inv { player, .. }) = player_inventories.find_item(entity) {
// If the item is being used
let item_used = items_used.remove(entity).is_some();
if item_used && periscope.cooldown.finished() {
// Empty
if periscope.ammo.eq(&0) {
audio_center.play_sound(*empty_shoot_sound, *empty_shoot_sound_volume);
continue;
}

// Reset fire cooldown and subtract ammo
periscope.cooldown = Timer::new(*cooldown, TimerMode::Once);
periscope.ammo = periscope.ammo.saturating_sub(1).clamp(0, periscope.ammo);
audio_center.play_sound(*shoot_sound, *shoot_sound_volume);

let player_sprite = sprites.get_mut(player).unwrap();
let player_flip_x = player_sprite.flip_x;
let player_body = bodies.get_mut(player).unwrap();

//Set kickback
player_body.velocity.x = if player_flip_x { 1.0 } else { -1.0 } * kickback;

let mut shoot_animation_transform = *transforms.get(entity).unwrap();
shoot_animation_transform.translation.z += 1.0;
shoot_animation_transform.translation.y += 25.0;
shoot_animation_transform.translation.x +=
if player_sprite.flip_x { -30.0 } else { 30.0 };

let shoot_fps = *shoot_fps;
let shoot_frames = *shoot_frames;
let shoot_lifetime = *shoot_lifetime;
let shoot_atlas = *shoot_atlas;

let bullet_meta = *bullet_meta;

commands.add(
move |mut entities: ResMutInit<Entities>,
mut lifetimes: CompMut<Lifetime>,
mut sprites: CompMut<AtlasSprite>,
mut transforms: CompMut<Transform>,
mut bullets: CompMut<Bullet>,
mut bullet_handles: CompMut<BulletHandle>,
mut animated_sprites: CompMut<AnimatedSprite>| {
// spawn fire animation
{
let ent = entities.create();
transforms.insert(ent, shoot_animation_transform);
sprites.insert(
ent,
AtlasSprite {
flip_x: player_flip_x,
atlas: shoot_atlas,
..default()
},
);

animated_sprites.insert(
ent,
AnimatedSprite {
frames: (0..shoot_frames).collect(),
fps: shoot_fps,
repeat: false,
..default()
},
);
lifetimes.insert(ent, Lifetime::new(shoot_lifetime));
}

// spawn bullet
{
let ent = entities.create();
bullets.insert(
ent,
Bullet {
owner: player,
direction: if player_flip_x {
vec2(-1.0, 0.0)
} else {
vec2(1.0, 0.0)
},
},
);
transforms.insert(ent, shoot_animation_transform);
bullet_handles.insert(ent, BulletHandle(bullet_meta));
}
},
);
}
}

// If the item was dropped
if items_dropped.get(entity).is_some() {
// reload gun
periscope.ammo = *max_ammo;
}
}
}

fn periscope_drop(entity: Entity, max_ammo: u32) -> StaticSystem<(), ()> {
(move |mut periscopes: CompMut<Periscope>| {
periscopes.get_mut(entity).unwrap().ammo = max_ammo;
})
.system()
}