mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-12-02 01:18:37 +00:00
make some of the NPCs aware of second player
This commit is contained in:
parent
d6d2df53f7
commit
87b2df2ade
|
|
@ -92,6 +92,7 @@ bitfield! {
|
|||
pub credits_running, set_credits_running: 3; // 0x08
|
||||
|
||||
// engine specific flags
|
||||
pub friendly_fire, set_friendly_fire: 14;
|
||||
pub wind, set_wind: 15;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub struct HUD {
|
|||
pub alignment: Alignment,
|
||||
pub weapon_x_pos: usize,
|
||||
pub visible: bool,
|
||||
pub has_player2: bool,
|
||||
ammo: u16,
|
||||
max_ammo: u16,
|
||||
xp: u16,
|
||||
|
|
@ -35,6 +36,7 @@ impl HUD {
|
|||
alignment,
|
||||
weapon_x_pos: 16,
|
||||
visible: false,
|
||||
has_player2: false,
|
||||
ammo: 0,
|
||||
max_ammo: 0,
|
||||
xp: 0,
|
||||
|
|
@ -114,6 +116,14 @@ impl GameEntity<(&Player, &Inventory)> for HUD {
|
|||
Alignment::Left => (0.0, 0.0, 0.0),
|
||||
Alignment::Right => (state.canvas_size.0 - 112.0, state.canvas_size.0 - 48.0, state.canvas_size.0 - 104.0),
|
||||
};
|
||||
let air_offset = if self.has_player2 {
|
||||
50.0 * match self.alignment {
|
||||
Alignment::Left => -1.0,
|
||||
Alignment::Right => 1.0,
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
if self.max_ammo == 0 {
|
||||
batch.add_rect(bar_offset + weap_x + 48.0, 16.0,
|
||||
|
|
@ -165,7 +175,7 @@ impl GameEntity<(&Player, &Inventory)> for HUD {
|
|||
Rect::new_size(112, 80, 32, 8)
|
||||
};
|
||||
|
||||
batch.add_rect((state.canvas_size.0 / 2.0).floor() - 40.0,
|
||||
batch.add_rect((state.canvas_size.0 / 2.0).floor() - 40.0 + air_offset,
|
||||
(state.canvas_size.1 / 2.0).floor(), &rect);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +213,7 @@ impl GameEntity<(&Player, &Inventory)> for HUD {
|
|||
batch.draw(ctx)?;
|
||||
|
||||
if self.air_counter > 0 && self.air_counter % 6 < 4 {
|
||||
draw_number((state.canvas_size.0 / 2.0).floor() + 8.0,
|
||||
draw_number((state.canvas_size.0 / 2.0).floor() + 8.0 + air_offset,
|
||||
(state.canvas_size.1 / 2.0).floor(),
|
||||
(self.air / 10) as usize, Alignment::Left, state, ctx)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n010_balrog_shooting(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n010_balrog_shooting(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -201,11 +203,13 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n012_balrog_cutscene(&mut self, state: &mut SharedGameState, player: &Player, map: &BTreeMap<u16, RefCell<NPC>>, stage: &mut Stage) -> GameResult {
|
||||
pub(crate) fn tick_n012_balrog_cutscene(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], map: &BTreeMap<u16, RefCell<NPC>>, stage: &mut Stage) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
if self.direction == Direction::FacingPlayer {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
|
|
@ -233,6 +237,8 @@ impl NPC {
|
|||
10 | 11 => {
|
||||
if self.action_num == 10 {
|
||||
if self.direction == Direction::FacingPlayer {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
|
|
@ -269,6 +275,8 @@ impl NPC {
|
|||
20 | 21 => {
|
||||
if self.action_num == 20 {
|
||||
if self.direction == Direction::FacingPlayer {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
|
|
@ -332,6 +340,8 @@ impl NPC {
|
|||
40 | 41 => {
|
||||
if self.action_num == 40 {
|
||||
if self.direction == Direction::FacingPlayer {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
|
|
@ -354,6 +364,8 @@ impl NPC {
|
|||
42 | 43 => {
|
||||
if self.action_num == 42 {
|
||||
if self.direction == Direction::FacingPlayer {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x <= player.x {
|
||||
self.direction = Direction::Right;
|
||||
} else {
|
||||
|
|
@ -645,7 +657,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n036_balrog_hover(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n036_balrog_hover(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -799,7 +813,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n068_balrog_running(&mut self, state: &mut SharedGameState, player: &mut Player) -> GameResult {
|
||||
pub(crate) fn tick_n068_balrog_running(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ use crate::player::Player;
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n029_cthulhu(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n029_cthulhu(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_num = 0;
|
||||
self.anim_counter = 0;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if abs(self.x - player.x) < 48 * 0x200 && self.y - 48 * 0x200 < player.y && self.y + 16 * 0x200 > player.y {
|
||||
self.anim_num = 1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n005_green_critter(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n005_green_critter(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -105,6 +105,8 @@ impl NPC {
|
|||
self.anim_rect = state.constants.npc.n005_green_critter[self.anim_num as usize + if self.direction == Direction::Right { 3 } else { 0 }];
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x > player.x {
|
||||
self.direction = Direction::Left;
|
||||
} else {
|
||||
|
|
@ -307,9 +309,10 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n007_basil(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n007_basil(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
self.x = player.x;
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
|
|
@ -321,6 +324,7 @@ impl NPC {
|
|||
1 => {
|
||||
self.vel_x -= 0x40;
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if self.x < (player.x - 192 * 0x200) {
|
||||
self.action_num = 2;
|
||||
}
|
||||
|
|
@ -333,6 +337,7 @@ impl NPC {
|
|||
2 => {
|
||||
self.vel_x += 0x40;
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if self.x > (player.x + 192 * 0x200) {
|
||||
self.action_num = 1;
|
||||
}
|
||||
|
|
@ -368,9 +373,11 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n008_blue_beetle(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n008_blue_beetle(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if player.x < self.x + 16 * 0x200 && player.x > self.x - 16 * 0x200 {
|
||||
self.npc_flags.set_shootable(true);
|
||||
self.vel_y = -0x100;
|
||||
|
|
@ -401,6 +408,8 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
1 => {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.x > player.x {
|
||||
self.direction = Direction::Left;
|
||||
self.vel_x -= 0x10;
|
||||
|
|
@ -535,7 +544,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n058_basu(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n058_basu(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 => {
|
||||
if player.x < self.x + 16 * 0x200 && player.x > self.x - 16 * 0x200 {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ use crate::player::Player;
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n024_power_critter(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n024_power_critter(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -140,7 +142,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n026_bat_flying(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n026_bat_flying(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -215,7 +219,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n028_flying_critter(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n028_flying_critter(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -349,7 +355,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n031_bat_hanging(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n031_bat_hanging(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -779,7 +787,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n104_frog(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n104_frog(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
|
|
@ -1068,7 +1078,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n109_malco_powered_on(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n109_malco_powered_on(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -1088,6 +1098,8 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if abs(self.x - player.x) < 32 * 0x200
|
||||
&& self.y - 32 * 0x200 < player.y
|
||||
&& self.y + 16 * 0x200 > player.y {
|
||||
|
|
@ -1134,7 +1146,9 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n110_puchi(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n110_puchi(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n079_mahin(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n079_mahin(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
|
|
@ -224,6 +224,7 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if (self.x - (32 * 0x200) < player.x) && (self.x + (32 * 0x200) > player.x)
|
||||
&& (self.y - (32 * 0x200) < player.y) && (self.y + (16 * 0x200) > player.y) {
|
||||
if self.x > player.x {
|
||||
|
|
@ -258,7 +259,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n080_gravekeeper(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n080_gravekeeper(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -270,6 +271,7 @@ impl NPC {
|
|||
|
||||
self.anim_num = 0;
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if abs(player.x - self.x) < 128 * 0x200
|
||||
&& self.y - 48 * 0x200 < player.y && self.y + 32 * 0x200 > player.y {
|
||||
self.anim_counter = 0;
|
||||
|
|
@ -295,6 +297,7 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if abs(player.x - self.x) < 16 * 0x200 {
|
||||
self.hit_bounds.left = 18 * 0x200;
|
||||
self.action_counter = 0;
|
||||
|
|
@ -356,7 +359,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n081_giant_pignon(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n081_giant_pignon(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 6 };
|
||||
|
||||
match self.action_num {
|
||||
|
|
@ -441,6 +444,7 @@ impl NPC {
|
|||
}
|
||||
|
||||
if self.shock > 0 && [1, 2, 4].contains(&self.action_num) {
|
||||
let player = self.get_closest_player_mut(players);
|
||||
self.vel_x = if self.x < player.x { 0x100 } else { -0x100 };
|
||||
self.vel_y = -0x200;
|
||||
self.anim_num = 5;
|
||||
|
|
|
|||
|
|
@ -528,9 +528,11 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n046_hv_trigger(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n046_hv_trigger(&mut self, players: [&mut Player; 2]) -> GameResult {
|
||||
self.npc_flags.set_event_when_touched(true);
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
if self.x < player.x {
|
||||
self.x += 0x5ff;
|
||||
|
|
@ -643,10 +645,12 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n085_terminal(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n085_terminal(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.anim_num = 0;
|
||||
let player = self.get_closest_player_mut(players);
|
||||
|
||||
if abs(player.x - self.x) < 8 * 0x200 && player.y < self.y + 8 * 0x200 && player.y > self.y - 16 * 0x200 {
|
||||
state.sound_manager.play_sfx(43);
|
||||
self.action_num = 1;
|
||||
|
|
@ -667,7 +671,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n096_fan_left(&mut self, state: &mut SharedGameState, player: &mut Player) -> GameResult {
|
||||
pub(crate) fn tick_n096_fan_left(&mut self, state: &mut SharedGameState, mut players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 && self.direction == Direction::Right {
|
||||
|
|
@ -686,19 +690,27 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
if abs(player.x - self.x) < 480 * 0x200 && abs(player.y - self.y) < 240 * 0x200
|
||||
&& state.game_rng.range(0..5) == 1 {
|
||||
let mut particle = NPCMap::create_npc(199, &state.npc_table);
|
||||
particle.cond.set_alive(true);
|
||||
particle.direction = Direction::Left;
|
||||
particle.x = self.x;
|
||||
particle.y = self.y + (state.game_rng.range(-8..8) * 0x200) as isize;
|
||||
state.new_npcs.push(particle);
|
||||
{
|
||||
if abs(players[0].x - self.x) < 480 * 0x200 && abs(players[0].y - self.y) < 240 * 0x200
|
||||
&& state.game_rng.range(0..5) == 1 {
|
||||
let mut particle = NPCMap::create_npc(199, &state.npc_table);
|
||||
particle.cond.set_alive(true);
|
||||
particle.direction = Direction::Left;
|
||||
particle.x = self.x;
|
||||
particle.y = self.y + (state.game_rng.range(-8..8) * 0x200) as isize;
|
||||
state.new_npcs.push(particle);
|
||||
}
|
||||
}
|
||||
|
||||
if abs(player.y - self.y) < 8 * 0x200 && player.x < self.x && player.x > self.x - 96 * 0x200 {
|
||||
player.vel_x -= 0x88;
|
||||
player.cond.set_increase_acceleration(true);
|
||||
for player in players.iter_mut() {
|
||||
if !player.cond.alive() || player.cond.hidden() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if abs(player.y - self.y) < 8 * 0x200 && player.x < self.x && player.x > self.x - 96 * 0x200 {
|
||||
player.vel_x -= 0x88;
|
||||
player.cond.set_increase_acceleration(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use num_traits::abs;
|
|||
|
||||
use crate::bitfield;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, fix9_scale, interpolate_fix9_scale, Rect};
|
||||
use crate::common::{Condition, interpolate_fix9_scale, Rect};
|
||||
use crate::common::Direction;
|
||||
use crate::common::Flag;
|
||||
use crate::entity::GameEntity;
|
||||
|
|
@ -37,6 +37,7 @@ pub mod maze;
|
|||
pub mod mimiga_village;
|
||||
pub mod misc;
|
||||
pub mod misery;
|
||||
pub mod npc_utils;
|
||||
pub mod pickups;
|
||||
pub mod quote;
|
||||
pub mod sand_zone;
|
||||
|
|
@ -163,22 +164,22 @@ impl NPC {
|
|||
}
|
||||
}
|
||||
|
||||
impl GameEntity<(&mut Player, &BTreeMap<u16, RefCell<NPC>>, &mut Stage)> for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player, map, stage): (&mut Player, &BTreeMap<u16, RefCell<NPC>>, &mut Stage)) -> GameResult {
|
||||
impl GameEntity<([&mut Player; 2], &BTreeMap<u16, RefCell<NPC>>, &mut Stage)> for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (players, map, stage): ([&mut Player; 2], &BTreeMap<u16, RefCell<NPC>>, &mut Stage)) -> GameResult {
|
||||
match self.npc_type {
|
||||
0 => self.tick_n000_null(),
|
||||
1 => self.tick_n001_experience(state),
|
||||
2 => self.tick_n002_behemoth(state),
|
||||
3 => self.tick_n003_dead_enemy(),
|
||||
4 => self.tick_n004_smoke(state),
|
||||
5 => self.tick_n005_green_critter(state, player),
|
||||
5 => self.tick_n005_green_critter(state, players),
|
||||
6 => self.tick_n006_green_beetle(state),
|
||||
7 => self.tick_n007_basil(state, player),
|
||||
8 => self.tick_n008_blue_beetle(state, player),
|
||||
7 => self.tick_n007_basil(state, players),
|
||||
8 => self.tick_n008_blue_beetle(state, players),
|
||||
9 => self.tick_n009_balrog_falling_in(state),
|
||||
10 => self.tick_n010_balrog_shooting(state, player),
|
||||
10 => self.tick_n010_balrog_shooting(state, players),
|
||||
11 => self.tick_n011_balrogs_projectile(state),
|
||||
12 => self.tick_n012_balrog_cutscene(state, player, map, stage),
|
||||
12 => self.tick_n012_balrog_cutscene(state, players, map, stage),
|
||||
13 => self.tick_n013_forcefield(state),
|
||||
14 => self.tick_n014_key(state),
|
||||
15 => self.tick_n015_chest_closed(state),
|
||||
|
|
@ -190,89 +191,89 @@ impl GameEntity<(&mut Player, &BTreeMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
21 => self.tick_n021_chest_open(state),
|
||||
22 => self.tick_n022_teleporter(state),
|
||||
23 => self.tick_n023_teleporter_lights(state),
|
||||
24 => self.tick_n024_power_critter(state, player),
|
||||
24 => self.tick_n024_power_critter(state, players),
|
||||
25 => self.tick_n025_lift(state),
|
||||
26 => self.tick_n026_bat_flying(state, player),
|
||||
26 => self.tick_n026_bat_flying(state, players),
|
||||
27 => self.tick_n027_death_trap(state),
|
||||
28 => self.tick_n028_flying_critter(state, player),
|
||||
29 => self.tick_n029_cthulhu(state, player),
|
||||
28 => self.tick_n028_flying_critter(state, players),
|
||||
29 => self.tick_n029_cthulhu(state, players),
|
||||
30 => self.tick_n030_gunsmith(state),
|
||||
31 => self.tick_n031_bat_hanging(state, player),
|
||||
31 => self.tick_n031_bat_hanging(state, players),
|
||||
32 => self.tick_n032_life_capsule(state),
|
||||
33 => self.tick_n033_balrog_bouncing_projectile(state),
|
||||
34 => self.tick_n034_bed(state),
|
||||
35 => self.tick_n035_mannan(state),
|
||||
36 => self.tick_n036_balrog_hover(state, player),
|
||||
36 => self.tick_n036_balrog_hover(state, players),
|
||||
37 => self.tick_n037_sign(state),
|
||||
38 => self.tick_n038_fireplace(state),
|
||||
39 => self.tick_n039_save_sign(state),
|
||||
40 => self.tick_n040_santa(state, player),
|
||||
40 => self.tick_n040_santa(state, players),
|
||||
41 => self.tick_n041_busted_door(state),
|
||||
42 => self.tick_n042_sue(state, player, map),
|
||||
42 => self.tick_n042_sue(state, players[0], map),
|
||||
43 => self.tick_n043_chalkboard(state),
|
||||
46 => self.tick_n046_hv_trigger(state, player),
|
||||
46 => self.tick_n046_hv_trigger(players),
|
||||
52 => self.tick_n052_sitting_blue_robot(state),
|
||||
55 => self.tick_n055_kazuma(state),
|
||||
58 => self.tick_n058_basu(state, player),
|
||||
59 => self.tick_n059_eye_door(state, player),
|
||||
60 => self.tick_n060_toroko(state, player),
|
||||
58 => self.tick_n058_basu(state, players),
|
||||
59 => self.tick_n059_eye_door(state, players[0]),
|
||||
60 => self.tick_n060_toroko(state, players[0]),
|
||||
61 => self.tick_n061_king(state),
|
||||
62 => self.tick_n062_kazuma_computer(state),
|
||||
63 => self.tick_n063_toroko_stick(state),
|
||||
64 => self.tick_n064_first_cave_critter(state, player),
|
||||
65 => self.tick_n065_first_cave_bat(state, player),
|
||||
64 => self.tick_n064_first_cave_critter(state, players[0]),
|
||||
65 => self.tick_n065_first_cave_bat(state, players[0]),
|
||||
66 => self.tick_n066_misery_bubble(state, map),
|
||||
67 => self.tick_n067_misery_floating(state),
|
||||
68 => self.tick_n068_balrog_running(state, player),
|
||||
68 => self.tick_n068_balrog_running(state, players),
|
||||
69 => self.tick_n069_pignon(state),
|
||||
70 => self.tick_n070_sparkle(state),
|
||||
71 => self.tick_n071_chinfish(state),
|
||||
72 => self.tick_n072_sprinkler(state, player),
|
||||
72 => self.tick_n072_sprinkler(state, players[0]),
|
||||
73 => self.tick_n073_water_droplet(state, stage),
|
||||
74 => self.tick_n074_jack(state),
|
||||
75 => self.tick_n075_kanpachi(state, player),
|
||||
75 => self.tick_n075_kanpachi(state, players[0]),
|
||||
76 => self.tick_n076_flowers(),
|
||||
77 => self.tick_n077_yamashita(state),
|
||||
78 => self.tick_n078_pot(state),
|
||||
79 => self.tick_n079_mahin(state, player),
|
||||
80 => self.tick_n080_gravekeeper(state, player),
|
||||
81 => self.tick_n081_giant_pignon(state, player),
|
||||
79 => self.tick_n079_mahin(state, players),
|
||||
80 => self.tick_n080_gravekeeper(state, players),
|
||||
81 => self.tick_n081_giant_pignon(state, players),
|
||||
82 => self.tick_n082_misery_standing(state),
|
||||
83 => self.tick_n083_igor_cutscene(state),
|
||||
84 => self.tick_n084_basu_projectile(state),
|
||||
85 => self.tick_n085_terminal(state, player),
|
||||
85 => self.tick_n085_terminal(state, players),
|
||||
86 => self.tick_n086_missile_pickup(state),
|
||||
87 => self.tick_n087_heart_pickup(state),
|
||||
88 => self.tick_n088_igor_boss(state, player),
|
||||
89 => self.tick_n089_igor_dead(state, player),
|
||||
88 => self.tick_n088_igor_boss(state, players[0]),
|
||||
89 => self.tick_n089_igor_dead(state, players[0]),
|
||||
91 => self.tick_n091_mimiga_cage(state),
|
||||
92 => self.tick_n092_sue_at_pc(state),
|
||||
93 => self.tick_n093_chaco(state, player),
|
||||
94 => self.tick_n094_kulala(state, player),
|
||||
93 => self.tick_n093_chaco(state, players[0]),
|
||||
94 => self.tick_n094_kulala(state, players[0]),
|
||||
95 => self.tick_n095_jelly(state),
|
||||
96 => self.tick_n096_fan_left(state, player),
|
||||
97 => self.tick_n097_fan_up(state, player),
|
||||
98 => self.tick_n098_fan_right(state, player),
|
||||
99 => self.tick_n099_fan_down(state, player),
|
||||
96 => self.tick_n096_fan_left(state, players),
|
||||
97 => self.tick_n097_fan_up(state, players[0]),
|
||||
98 => self.tick_n098_fan_right(state, players[0]),
|
||||
99 => self.tick_n099_fan_down(state, players[0]),
|
||||
100 => self.tick_n100_grate(state),
|
||||
101 => self.tick_n101_malco_screen(state),
|
||||
102 => self.tick_n102_malco_computer_wave(state),
|
||||
103 => self.tick_n103_mannan_projectile(state),
|
||||
104 => self.tick_n104_frog(state, player),
|
||||
104 => self.tick_n104_frog(state, players),
|
||||
105 => self.tick_n105_hey_bubble_low(state),
|
||||
106 => self.tick_n106_hey_bubble_high(state),
|
||||
107 => self.tick_n107_malco_broken(state),
|
||||
108 => self.tick_n108_balfrog_projectile(state),
|
||||
109 => self.tick_n109_malco_powered_on(state, player),
|
||||
110 => self.tick_n110_puchi(state, player),
|
||||
111 => self.tick_n111_quote_teleport_out(state, player),
|
||||
112 => self.tick_n112_quote_teleport_in(state, player),
|
||||
114 => self.tick_n114_press(state, player),
|
||||
109 => self.tick_n109_malco_powered_on(state, players),
|
||||
110 => self.tick_n110_puchi(state, players),
|
||||
111 => self.tick_n111_quote_teleport_out(state, players),
|
||||
112 => self.tick_n112_quote_teleport_in(state, players),
|
||||
114 => self.tick_n114_press(state, players[0]),
|
||||
129 => self.tick_n129_fireball_snake_trail(state),
|
||||
149 => self.tick_n149_horizontal_moving_block(state, player),
|
||||
150 => self.tick_n150_quote(state, player),
|
||||
149 => self.tick_n149_horizontal_moving_block(state, players[0]),
|
||||
150 => self.tick_n150_quote(state, players[0]),
|
||||
154 => self.tick_n154_gaudi_dead(state),
|
||||
157 => self.tick_n157_vertical_moving_block(state, player),
|
||||
157 => self.tick_n157_vertical_moving_block(state, players[0]),
|
||||
192 => self.tick_n192_scooter(state),
|
||||
193 => self.tick_n193_broken_scooter(state),
|
||||
194 => self.tick_n194_broken_blue_robot(state),
|
||||
|
|
@ -281,7 +282,7 @@ impl GameEntity<(&mut Player, &BTreeMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
298 => self.tick_n298_intro_doctor(state),
|
||||
299 => self.tick_n299_intro_balrog_misery(state),
|
||||
300 => self.tick_n300_intro_demon_crown(state),
|
||||
361 => self.tick_n361_gaudi_dashing(state, player),
|
||||
361 => self.tick_n361_gaudi_dashing(state, players[0]),
|
||||
_ => Ok(()),
|
||||
}?;
|
||||
|
||||
|
|
|
|||
28
src/npc/npc_utils.rs
Normal file
28
src/npc/npc_utils.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use num_traits::abs;
|
||||
|
||||
use crate::npc::NPC;
|
||||
use crate::player::Player;
|
||||
|
||||
impl NPC {
|
||||
pub fn get_closest_player_mut<'a>(&self, players: [&'a mut Player; 2]) -> &'a mut Player {
|
||||
let mut max_dist = f64::MAX;
|
||||
let mut player_idx = 0;
|
||||
|
||||
for (idx, player) in players.iter().enumerate() {
|
||||
if !player.cond.alive() || player.cond.hidden() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let dist_x = abs(self.x - player.x) as f64;
|
||||
let dist_y = abs(self.y - player.y) as f64;
|
||||
let dist = (dist_x * dist_x + dist_y * dist_y).sqrt();
|
||||
|
||||
if dist < max_dist {
|
||||
max_dist = dist;
|
||||
player_idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
players[player_idx]
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ use crate::player::Player;
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl NPC {
|
||||
pub fn tick_n111_quote_teleport_out(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub fn tick_n111_quote_teleport_out(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
|
|
@ -58,10 +58,9 @@ impl NPC {
|
|||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
self.anim_rect = state.constants.npc.n111_quote_teleport_out[self.anim_num as usize + dir_offset];
|
||||
|
||||
if player.equip.has_mimiga_mask() {
|
||||
self.anim_rect.top += 32;
|
||||
self.anim_rect.bottom += 32;
|
||||
}
|
||||
let offset = players[state.textscript_vm.executor_player.index()].get_texture_offset();
|
||||
self.anim_rect.top += offset;
|
||||
self.anim_rect.bottom += offset;
|
||||
|
||||
if self.action_num == 4 {
|
||||
self.anim_rect.bottom = self.anim_rect.top + self.action_counter / 4;
|
||||
|
|
@ -74,7 +73,7 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tick_n112_quote_teleport_in(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub fn tick_n112_quote_teleport_in(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.action_num = 1;
|
||||
|
|
@ -116,10 +115,9 @@ impl NPC {
|
|||
let dir_offset = if self.direction == Direction::Left { 0 } else { 2 };
|
||||
self.anim_rect = state.constants.npc.n111_quote_teleport_out[self.anim_num as usize + dir_offset];
|
||||
|
||||
if player.equip.has_mimiga_mask() {
|
||||
self.anim_rect.top += 32;
|
||||
self.anim_rect.bottom += 32;
|
||||
}
|
||||
let offset = players[state.textscript_vm.executor_player.index()].get_texture_offset();
|
||||
self.anim_rect.top += offset;
|
||||
self.anim_rect.bottom += offset;
|
||||
|
||||
if self.action_num == 1 {
|
||||
self.anim_rect.bottom = self.anim_rect.top + self.action_counter / 4;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use num_traits::abs;
|
|||
use crate::common::Direction;
|
||||
|
||||
impl NPC {
|
||||
pub(crate) fn tick_n040_santa(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult {
|
||||
pub(crate) fn tick_n040_santa(&mut self, state: &mut SharedGameState, players: [&mut Player; 2]) -> GameResult {
|
||||
match self.action_num {
|
||||
0 | 1 =>{
|
||||
if self.action_num == 0 {
|
||||
|
|
@ -22,6 +22,7 @@ impl NPC {
|
|||
self.anim_num = 1;
|
||||
}
|
||||
|
||||
let player = self.get_closest_player_mut(players);
|
||||
if abs(self.x - player.x) < 32 * 0x200
|
||||
&& self.y - 32 * 0x200 < player.y && self.y + 16 * 0x200 > player.y {
|
||||
self.direction = if self.x > player.x {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::common::{Condition, Direction, Flag, Rect};
|
|||
use crate::inventory::{AddExperienceResult, Inventory};
|
||||
use crate::npc::{NPC, NPCMap};
|
||||
use crate::physics::PhysicalEntity;
|
||||
use crate::player::{ControlMode, Player};
|
||||
use crate::player::{ControlMode, Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
impl PhysicalEntity for Player {
|
||||
|
|
@ -236,7 +236,7 @@ impl Player {
|
|||
flags
|
||||
}
|
||||
|
||||
fn tick_npc_collision(&mut self, state: &mut SharedGameState, npc: &mut NPC, inventory: &mut Inventory) {
|
||||
fn tick_npc_collision(&mut self, id: TargetPlayer, state: &mut SharedGameState, npc: &mut NPC, inventory: &mut Inventory) {
|
||||
let flags: Flag;
|
||||
|
||||
if npc.npc_flags.solid_soft() {
|
||||
|
|
@ -289,6 +289,7 @@ impl Player {
|
|||
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
||||
state.control_flags.set_tick_world(true);
|
||||
state.control_flags.set_interactions_disabled(true);
|
||||
state.textscript_vm.executor_player = id;
|
||||
state.textscript_vm.start_script(npc.event_num);
|
||||
self.cond.set_interacted(false);
|
||||
self.vel_x = 0;
|
||||
|
|
@ -298,6 +299,7 @@ impl Player {
|
|||
if npc.npc_flags.event_when_touched() && !state.control_flags.interactions_disabled() && flags.0 != 0 {
|
||||
state.control_flags.set_tick_world(true);
|
||||
state.control_flags.set_interactions_disabled(true);
|
||||
state.textscript_vm.executor_player = id;
|
||||
state.textscript_vm.start_script(npc.event_num);
|
||||
}
|
||||
|
||||
|
|
@ -315,17 +317,17 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick_npc_collisions(&mut self, 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) {
|
||||
for npc_cell in npc_map.npcs.values() {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
if !npc.cond.alive() { continue; }
|
||||
|
||||
self.tick_npc_collision(state, npc.borrow_mut(), inventory);
|
||||
self.tick_npc_collision(id, state, npc.borrow_mut(), inventory);
|
||||
}
|
||||
|
||||
for boss_npc in npc_map.boss_map.parts.iter_mut() {
|
||||
if boss_npc.cond.alive() {
|
||||
self.tick_npc_collision(state, boss_npc, inventory);
|
||||
self.tick_npc_collision(id, state, boss_npc, inventory);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::frame::{Frame, UpdateTarget};
|
|||
use crate::inventory::{Inventory, TakeExperienceResult};
|
||||
use crate::npc::{NPC, NPCMap};
|
||||
use crate::physics::PhysicalEntity;
|
||||
use crate::player::{Player, PlayerAppearance};
|
||||
use crate::player::{Player, PlayerAppearance, TargetPlayer};
|
||||
use crate::rng::RNG;
|
||||
use crate::scene::Scene;
|
||||
use crate::scene::title_scene::TitleScene;
|
||||
|
|
@ -962,6 +962,9 @@ impl GameScene {
|
|||
}
|
||||
|
||||
fn tick_world(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.hud_player1.has_player2 = !self.player2.cond.hidden();
|
||||
self.hud_player2.has_player2 = self.hud_player1.has_player2;
|
||||
|
||||
self.player1.current_weapon = {
|
||||
if let Some(weapon) = self.inventory_player1.get_current_weapon_mut() {
|
||||
weapon.wtype as u8
|
||||
|
|
@ -969,6 +972,13 @@ impl GameScene {
|
|||
0
|
||||
}
|
||||
};
|
||||
self.player2.current_weapon = {
|
||||
if let Some(weapon) = self.inventory_player2.get_current_weapon_mut() {
|
||||
weapon.wtype as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
self.player1.tick(state, ())?;
|
||||
self.player2.tick(state, ())?;
|
||||
|
||||
|
|
@ -996,11 +1006,13 @@ impl GameScene {
|
|||
self.player2.damage = 0;
|
||||
}
|
||||
|
||||
for npc_cell in self.npc_map.npcs.values() {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
{
|
||||
for npc_cell in self.npc_map.npcs.values() {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
|
||||
if npc.cond.alive() {
|
||||
npc.tick(state, (&mut self.player1, &self.npc_map.npcs, &mut self.stage))?;
|
||||
if npc.cond.alive() {
|
||||
npc.tick(state, ([&mut self.player1, &mut self.player2], &self.npc_map.npcs, &mut self.stage))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.npc_map.boss_map.tick(state, (&mut self.player1, &self.npc_map.npcs, &mut self.stage))?;
|
||||
|
|
@ -1008,10 +1020,10 @@ impl GameScene {
|
|||
self.npc_map.garbage_collect();
|
||||
|
||||
self.player1.tick_map_collisions(state, &mut self.stage);
|
||||
self.player1.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory_player1);
|
||||
self.player1.tick_npc_collisions(TargetPlayer::Player1, state, &mut self.npc_map, &mut self.inventory_player1);
|
||||
|
||||
self.player2.tick_map_collisions(state, &mut self.stage);
|
||||
self.player2.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory_player2);
|
||||
self.player2.tick_npc_collisions(TargetPlayer::Player2, state, &mut self.npc_map, &mut self.inventory_player2);
|
||||
|
||||
for npc_cell in self.npc_map.npcs.values() {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
|
|
@ -1036,8 +1048,13 @@ impl GameScene {
|
|||
|
||||
match self.frame.update_target {
|
||||
UpdateTarget::Player => {
|
||||
self.frame.target_x = self.player1.target_x;
|
||||
self.frame.target_y = self.player1.target_y;
|
||||
if !self.player2.cond.hidden() {
|
||||
self.frame.target_x = (self.player1.target_x + self.player2.target_x) / 2;
|
||||
self.frame.target_y = (self.player1.target_y + self.player2.target_y) / 2;
|
||||
} else {
|
||||
self.frame.target_x = self.player1.target_x;
|
||||
self.frame.target_y = self.player1.target_y;
|
||||
}
|
||||
}
|
||||
UpdateTarget::NPC(npc_id) => {
|
||||
if let Some(npc_cell) = self.npc_map.npcs.get(&npc_id) {
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@ pub struct TextScriptVM {
|
|||
pub flags: TextScriptFlags,
|
||||
pub mode: ScriptMode,
|
||||
/// The player who triggered the event.
|
||||
pub trigger_player: TargetPlayer,
|
||||
pub executor_player: TargetPlayer,
|
||||
/// Toggle for non-strict TSC parsing because English versions of CS+ (both AG and Nicalis release)
|
||||
/// modified the events carelessly and since original Pixel's engine hasn't enforced constraints
|
||||
/// while parsing no one noticed them.
|
||||
|
|
@ -451,7 +451,7 @@ impl TextScriptVM {
|
|||
stack: Vec::with_capacity(6),
|
||||
flags: TextScriptFlags(0),
|
||||
mode: ScriptMode::Map,
|
||||
trigger_player: TargetPlayer::Player1,
|
||||
executor_player: TargetPlayer::Player1,
|
||||
strict_mode: false,
|
||||
suspend: true,
|
||||
face: 0,
|
||||
|
|
@ -805,11 +805,13 @@ impl TextScriptVM {
|
|||
}
|
||||
OpCode::SMC => {
|
||||
game_scene.player1.cond.set_hidden(false);
|
||||
game_scene.player2.cond.set_hidden(false);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::HMC => {
|
||||
game_scene.player1.cond.set_hidden(true);
|
||||
game_scene.player2.cond.set_hidden(true);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
@ -1063,23 +1065,29 @@ impl TextScriptVM {
|
|||
let pos_x = read_cur_varint(&mut cursor)? as isize * 16 * 0x200;
|
||||
let pos_y = read_cur_varint(&mut cursor)? as isize * 16 * 0x200;
|
||||
|
||||
game_scene.player1.vel_x = 0;
|
||||
game_scene.player1.vel_y = 0;
|
||||
game_scene.player1.x = pos_x;
|
||||
game_scene.player1.y = pos_y;
|
||||
for player in [&mut game_scene.player1, &mut game_scene.player2].iter_mut() {
|
||||
player.vel_x = 0;
|
||||
player.vel_y = 0;
|
||||
player.x = pos_x;
|
||||
player.y = pos_y;
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::S2MV => {
|
||||
let param = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
let (executor, partner) = match state.textscript_vm.executor_player {
|
||||
TargetPlayer::Player1 => (&game_scene.player1, &mut game_scene.player2),
|
||||
TargetPlayer::Player2 => (&game_scene.player2, &mut game_scene.player1),
|
||||
};
|
||||
|
||||
match param {
|
||||
0 | 1 => {
|
||||
game_scene.player2.vel_x = 0;
|
||||
game_scene.player2.vel_y = 0;
|
||||
game_scene.player2.x = game_scene.player1.x
|
||||
+ if param == 0 { -16 * 0x200 } else { 16 * 0x200 };
|
||||
game_scene.player2.y = game_scene.player1.y;
|
||||
partner.vel_x = 0;
|
||||
partner.vel_y = 0;
|
||||
partner.x = executor.x + if param == 0 { -16 * 0x200 } else { 16 * 0x200 };
|
||||
partner.y = executor.y;
|
||||
}
|
||||
_ => {
|
||||
log::warn!("stub: <2MV unknown param");
|
||||
|
|
@ -1368,6 +1376,7 @@ impl TextScriptVM {
|
|||
let life = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.player1.life = clamp(game_scene.player1.life + life, 0, game_scene.player1.max_life);
|
||||
game_scene.player2.life = clamp(game_scene.player2.life + life, 0, game_scene.player2.max_life);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
@ -1378,6 +1387,10 @@ impl TextScriptVM {
|
|||
game_scene.inventory_player1.add_item(item_id);
|
||||
}
|
||||
|
||||
if !game_scene.inventory_player2.has_item(item_id) {
|
||||
game_scene.inventory_player2.add_item(item_id);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::IpN => {
|
||||
|
|
@ -1388,12 +1401,17 @@ impl TextScriptVM {
|
|||
game_scene.inventory_player1.add_item(item_id);
|
||||
}
|
||||
|
||||
if game_scene.inventory_player2.has_item_amount(item_id, Ordering::Less, amount) {
|
||||
game_scene.inventory_player2.add_item(item_id);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::ITm => {
|
||||
let item_id = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.inventory_player1.consume_item(item_id);
|
||||
game_scene.inventory_player2.consume_item(item_id);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
@ -1404,6 +1422,7 @@ impl TextScriptVM {
|
|||
|
||||
if let Some(wtype) = weapon_type {
|
||||
game_scene.inventory_player1.add_weapon(wtype, max_ammo);
|
||||
game_scene.inventory_player2.add_weapon(wtype, max_ammo);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
|
|
@ -1414,17 +1433,20 @@ impl TextScriptVM {
|
|||
|
||||
if let Some(wtype) = weapon_type {
|
||||
game_scene.inventory_player1.remove_weapon(wtype);
|
||||
game_scene.inventory_player2.remove_weapon(wtype);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::AEp => {
|
||||
game_scene.inventory_player1.refill_all_ammo();
|
||||
game_scene.inventory_player2.refill_all_ammo();
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::ZAM => {
|
||||
game_scene.inventory_player1.reset_all_weapon_xp();
|
||||
game_scene.inventory_player2.reset_all_weapon_xp();
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
@ -1512,7 +1534,7 @@ impl TextScriptVM {
|
|||
|
||||
if tick_npc != 0 {
|
||||
if let Some(npc) = game_scene.npc_map.npcs.get(&tick_npc) {
|
||||
npc.borrow_mut().tick(state, (&mut game_scene.player1, &game_scene.npc_map.npcs, &mut game_scene.stage))?;
|
||||
npc.borrow_mut().tick(state, ([&mut game_scene.player1, &mut game_scene.player2], &game_scene.npc_map.npcs, &mut game_scene.stage))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue