add perma death option, make cessation nicer, fix spectator shields and cursors not appearing sometimes, make default settings transfer nicer

This commit is contained in:
bgkillas 2024-11-09 17:54:58 -05:00
parent 79e8f73d63
commit 2fc0e76f2c
10 changed files with 331 additions and 131 deletions

View file

@ -99,6 +99,7 @@ local_health_desc_2 = There is a respawn mechanic.
Health-percent-lost-on-reviving = HP percent lost on reviving Health-percent-lost-on-reviving = HP percent lost on reviving
global_hp_loss = Lose HP globally global_hp_loss = Lose HP globally
no_material_damage = No material damage no_material_damage = No material damage
perma_death = Perma death
shared_health_desc_1 = Health is shared, but scales with player count. shared_health_desc_1 = Health is shared, but scales with player count.
shared_health_desc_2 = Percentage-based damage and full heals are adjusted. shared_health_desc_2 = Percentage-based damage and full heals are adjusted.
shared_health_desc_3 = The original mode. shared_health_desc_3 = The original mode.

View file

@ -63,15 +63,39 @@ pub(crate) enum GameMode {
// MestariMina, // TODO later // MestariMina, // TODO later
} }
#[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(default)] #[serde(default)]
pub struct GameSettings { pub struct GameSettings {
seed: u64, seed: u64,
debug_mode: Option<bool>,
world_sync_version: Option<u32>,
player_tether: Option<bool>,
tether_length: Option<u32>,
use_constant_seed: bool,
item_dedup: Option<bool>,
enemy_hp_mult: Option<f32>,
world_sync_interval: Option<u32>,
game_mode: Option<GameMode>,
friendly_fire: Option<bool>,
friendly_fire_team: Option<i32>,
chunk_target: Option<u32>,
enemy_sync_interval: Option<u32>,
randomize_perks: Option<bool>,
progress: Vec<String>,
max_players: Option<u32>,
health_per_player: Option<u32>,
health_lost_on_revive: Option<u32>,
no_material_damage: Option<bool>,
global_hp_loss: Option<bool>,
perk_ban_list: Option<String>,
perma_death: Option<bool>,
}
pub struct DefaultSettings {
debug_mode: bool, debug_mode: bool,
world_sync_version: u32, world_sync_version: u32,
player_tether: bool, player_tether: bool,
tether_length: u32, tether_length: u32,
use_constant_seed: bool,
item_dedup: bool, item_dedup: bool,
enemy_hp_mult: f32, enemy_hp_mult: f32,
world_sync_interval: u32, world_sync_interval: u32,
@ -81,24 +105,22 @@ pub struct GameSettings {
chunk_target: u32, chunk_target: u32,
enemy_sync_interval: u32, enemy_sync_interval: u32,
randomize_perks: bool, randomize_perks: bool,
progress: Vec<String>,
max_players: u32, max_players: u32,
health_per_player: u32, health_per_player: u32,
health_lost_on_revive: u32, health_lost_on_revive: u32,
no_material_damage: bool, no_material_damage: bool,
global_hp_loss: bool, global_hp_loss: bool,
perk_ban_list: String, perk_ban_list: String,
perma_death: bool,
} }
impl Default for GameSettings { impl Default for DefaultSettings {
fn default() -> Self { fn default() -> Self {
GameSettings { DefaultSettings {
seed: 0,
debug_mode: false, debug_mode: false,
world_sync_version: 2, world_sync_version: 2,
player_tether: true, player_tether: true,
tether_length: 2048, tether_length: 2048,
use_constant_seed: false,
item_dedup: true, item_dedup: true,
randomize_perks: true, randomize_perks: true,
enemy_hp_mult: 1.0, enemy_hp_mult: 1.0,
@ -108,13 +130,13 @@ impl Default for GameSettings {
friendly_fire_team: 0, friendly_fire_team: 0,
chunk_target: 24, chunk_target: 24,
enemy_sync_interval: 3, enemy_sync_interval: 3,
progress: Vec::new(),
max_players: 250, max_players: 250,
health_per_player: 100, health_per_player: 100,
health_lost_on_revive: 0, health_lost_on_revive: 0,
no_material_damage: false, no_material_damage: false,
global_hp_loss: false, global_hp_loss: false,
perk_ban_list: String::new(), perk_ban_list: "GLOBAL_GORE,GLASS_CANNON,REVENGE_RATS,PLAGUE_RATS,VOMIT_RATS,CORDYCEPS,MOLD,FUNGAL_DISEASE,HOMUNCULUS,LUKKI_MINION".to_string(),
perma_death: false
} }
} }
} }
@ -498,7 +520,7 @@ impl App {
let peer = net::steam_networking::SteamPeer::new_host( let peer = net::steam_networking::SteamPeer::new_host(
steamworks::LobbyType::Private, steamworks::LobbyType::Private,
self.steam_state.as_ref().unwrap().client.clone(), self.steam_state.as_ref().unwrap().client.clone(),
self.app_saved_state.game_settings.max_players, self.app_saved_state.game_settings.max_players.unwrap_or(DefaultSettings::default().max_players),
); );
let netman = net::NetManager::new(PeerVariant::Steam(peer), self.get_netman_init()); let netman = net::NetManager::new(PeerVariant::Steam(peer), self.get_netman_init());
self.set_netman_settings(&netman); self.set_netman_settings(&netman);
@ -720,56 +742,93 @@ impl App {
} }
fn show_game_settings(&mut self, ui: &mut Ui, show_local: bool) { fn show_game_settings(&mut self, ui: &mut Ui, show_local: bool) {
let def = DefaultSettings::default();
heading_with_underline(ui, tr("connect_settings")); heading_with_underline(ui, tr("connect_settings"));
let game_settings = &mut self.app_saved_state.game_settings; let game_settings = &mut self.app_saved_state.game_settings;
ui.label(tr("Game-mode")); {
ui.radio_value( let mut temp = game_settings.game_mode.unwrap_or(def.game_mode);
&mut game_settings.game_mode, ui.label(tr("Game-mode"));
GameMode::SharedHealth, if ui.radio_value(
tr("Shared-health"), &mut temp,
); GameMode::SharedHealth,
ui.radio_value( tr("Shared-health"),
&mut game_settings.game_mode, ).changed() || ui.radio_value(
GameMode::LocalHealth, &mut temp,
tr("Local-health"), GameMode::LocalHealth,
); tr("Local-health"),
).changed() {
game_settings.game_mode = Some(temp)
}
}
ui.scope(|ui| { ui.scope(|ui| {
ui.set_height(100.0); ui.set_height(100.0);
match game_settings.game_mode { match game_settings.game_mode.unwrap_or(def.game_mode) {
GameMode::SharedHealth => { GameMode::SharedHealth => {
ui.label(tr("shared_health_desc_1")); ui.label(tr("shared_health_desc_1"));
ui.label(tr("shared_health_desc_2")); ui.label(tr("shared_health_desc_2"));
ui.label(tr("shared_health_desc_3")); ui.label(tr("shared_health_desc_3"));
ui.add_space(5.0); ui.add_space(5.0);
ui.label(tr("Health-per-player")); ui.label(tr("Health-per-player"));
ui.add(Slider::new(&mut game_settings.health_per_player, 0..=100)); let mut temp = game_settings.health_per_player.unwrap_or(def.health_per_player);
if ui.add(Slider::new(&mut temp, 0..=100)).changed() {
game_settings.health_per_player = Some(temp)
}
} }
GameMode::LocalHealth => { GameMode::LocalHealth => {
ui.label(tr("local_health_desc_1")); ui.label(tr("local_health_desc_1"));
ui.label(tr("local_health_desc_2")); ui.label(tr("local_health_desc_2"));
ui.add_space(5.0); ui.add_space(5.0);
ui.label(tr("Health-percent-lost-on-reviving")); ui.label(tr("Health-percent-lost-on-reviving"));
ui.add(Slider::new( {
&mut game_settings.health_lost_on_revive, let mut temp = game_settings.health_lost_on_revive.unwrap_or(def.health_lost_on_revive);
0..=100, if ui.add(Slider::new(
)); &mut temp,
ui.checkbox(&mut game_settings.global_hp_loss, tr("global_hp_loss")); 0..=100,
ui.checkbox( )).changed() {
&mut game_settings.no_material_damage, game_settings.health_lost_on_revive = Some(temp)
tr("no_material_damage"), }
); }
{
let mut temp = game_settings.global_hp_loss.unwrap_or(def.global_hp_loss);
if ui.checkbox(&mut temp, tr("global_hp_loss")).changed() {
game_settings.global_hp_loss = Some(temp)
}
}
{
let mut temp = game_settings.no_material_damage.unwrap_or(def.no_material_damage);
if ui.checkbox(
&mut temp,
tr("no_material_damage"),
).changed() {
game_settings.no_material_damage = Some(temp)
}
}
ui.add_space(1.0);
{
let mut temp = game_settings.perma_death.unwrap_or(def.perma_death);
if ui.checkbox(
&mut temp,
tr("perma_death"),
).changed() {
game_settings.perma_death = Some(temp)
}
}
} }
} }
}); });
ui.add_space(10.0); ui.add_space(10.0);
ui.label(tr("connect_settings_debug")); ui.label(tr("connect_settings_debug"));
ui.checkbox( {
&mut game_settings.debug_mode, let mut temp = game_settings.debug_mode.unwrap_or(def.debug_mode);
tr("connect_settings_debug_en"), if ui.checkbox(
); &mut temp,
tr("connect_settings_debug_en"),
).changed() {
game_settings.debug_mode = Some(temp)
}
}
ui.checkbox( ui.checkbox(
&mut game_settings.use_constant_seed, &mut game_settings.use_constant_seed,
tr("connect_settings_debug_fixed_seed"), tr("connect_settings_debug_fixed_seed"),
@ -780,40 +839,87 @@ impl App {
}); });
ui.add_space(10.0); ui.add_space(10.0);
ui.label(tr("connect_settings_max_players")); ui.label(tr("connect_settings_max_players"));
ui.add(Slider::new(&mut game_settings.max_players, 2..=250)); {
let mut temp = game_settings.max_players.unwrap_or(def.max_players);
if ui.add(Slider::new(&mut temp, 2..=250)).changed()
{
game_settings.max_players = Some(temp)
}
}
ui.add_space(10.0); ui.add_space(10.0);
ui.label(tr("Amount-of-chunks-host-has-loaded-at-once-synced-enemies-and-physics-objects-need-to-be-loaded-in-by-host-to-be-rendered-by-clients")); ui.label(tr("Amount-of-chunks-host-has-loaded-at-once-synced-enemies-and-physics-objects-need-to-be-loaded-in-by-host-to-be-rendered-by-clients"));
ui.add(Slider::new(&mut game_settings.chunk_target, 12..=64)); {
let mut temp = game_settings.chunk_target.unwrap_or(def.chunk_target);
if ui.add(Slider::new(&mut temp, 12..=64)).changed() {
game_settings.chunk_target = Some(temp)
}
}
ui.add_space(20.0); ui.add_space(20.0);
ui.label(tr("connect_settings_player_tether_desc")); ui.label(tr("connect_settings_player_tether_desc"));
ui.checkbox( {
&mut game_settings.player_tether, let mut temp = game_settings.player_tether.unwrap_or(def.player_tether);
tr("connect_settings_player_tether"), if ui.checkbox(
); &mut temp,
ui.add( tr("connect_settings_player_tether"),
Slider::new(&mut game_settings.tether_length, 10..=5000) ).changed()
.text(tr("connect_settings_player_tether_length")), {
); game_settings.player_tether = Some(temp)
}
}
{
let mut temp = game_settings.tether_length.unwrap_or(def.tether_length);
if ui.add(
Slider::new(&mut temp, 10..=5000)
.text(tr("connect_settings_player_tether_length")),
).changed() {
game_settings.tether_length = Some(temp)
}
}
ui.add_space(20.0); ui.add_space(20.0);
ui.checkbox( {
&mut game_settings.item_dedup, let mut temp = game_settings.item_dedup.unwrap_or(def.item_dedup);
tr("connect_settings_item_dedup"), if ui.checkbox(
); &mut temp,
ui.checkbox( tr("connect_settings_item_dedup"),
&mut game_settings.randomize_perks, ).changed() {
tr("Have-perk-pools-be-independent-of-each-other"), game_settings.item_dedup = Some(temp)
); }
ui.horizontal(|ui| { }
ui.text_edit_singleline(&mut game_settings.perk_ban_list); {
ui.label("perk ban list, comma seperated"); let mut temp = game_settings.randomize_perks.unwrap_or(def.randomize_perks);
}); if ui.checkbox(
ui.add( &mut temp,
Slider::new(&mut game_settings.enemy_hp_mult, 1.0..=1000.0) tr("Have-perk-pools-be-independent-of-each-other"),
.logarithmic(true) ).changed() {
.text(tr("connect_settings_enemy_hp_scale")), game_settings.randomize_perks = Some(temp)
); }
ui.checkbox(&mut game_settings.friendly_fire, tr("Enable-friendly-fire")); }
{
let mut temp = game_settings.perk_ban_list.clone().unwrap_or(def.perk_ban_list);
ui.horizontal(|ui| {
if ui.text_edit_singleline(&mut temp)
.changed() {
game_settings.perk_ban_list = Some(temp)
}
ui.label("perk ban list, comma seperated");
});
}
{
let mut temp = game_settings.enemy_hp_mult.unwrap_or(def.enemy_hp_mult);
if ui.add(
Slider::new(&mut temp, 1.0..=1000.0)
.logarithmic(true)
.text(tr("connect_settings_enemy_hp_scale")),
).changed() {
game_settings.enemy_hp_mult = Some(temp)
}
}
{
let mut temp = game_settings.friendly_fire.unwrap_or(def.friendly_fire);
if ui.checkbox(&mut temp, tr("Enable-friendly-fire")).changed() {
game_settings.friendly_fire = Some(temp)
}
}
if show_local { if show_local {
heading_with_underline(ui, tr("connect_settings_local")); heading_with_underline(ui, tr("connect_settings_local"));
ui.checkbox( ui.checkbox(
@ -1097,10 +1203,14 @@ impl eframe::App for App {
ui.add_space(15.0); ui.add_space(15.0);
if netman.friendly_fire.load(Ordering::Relaxed) { if netman.friendly_fire.load(Ordering::Relaxed) {
let last = self.app_saved_state.game_settings.friendly_fire_team; let last = self.app_saved_state.game_settings.friendly_fire_team;
ui.add(Slider::new(&mut self.app_saved_state.game_settings.friendly_fire_team, -1..=16)); let def = DefaultSettings::default();
let mut temp = self.app_saved_state.game_settings.friendly_fire_team.unwrap_or(def.friendly_fire_team);
if ui.add(Slider::new(&mut temp, -1..=16)).changed() {
self.app_saved_state.game_settings.friendly_fire_team = Some(temp);
}
if last != self.app_saved_state.game_settings.friendly_fire_team if last != self.app_saved_state.game_settings.friendly_fire_team
|| netman.friendly_fire_team.load(Ordering::Relaxed) == -2 { || netman.friendly_fire_team.load(Ordering::Relaxed) == -2 {
netman.friendly_fire_team.store(self.app_saved_state.game_settings.friendly_fire_team, Ordering::Relaxed); netman.friendly_fire_team.store(temp, Ordering::Relaxed);
} }
ui.label("what team number you are on, 0 means no team, -1 means friendly"); ui.label("what team number you are on, 0 means no team, -1 means friendly");
ui.add_space(15.0); ui.add_space(15.0);

View file

@ -26,11 +26,7 @@ use tungstenite::{accept, WebSocket};
use crate::mod_manager::ModmanagerSettings; use crate::mod_manager::ModmanagerSettings;
use crate::player_cosmetics::{create_player_png, PlayerPngDesc}; use crate::player_cosmetics::{create_player_png, PlayerPngDesc};
use crate::{ use crate::{bookkeeping::save_state::{SaveState, SaveStateEntry}, recorder::Recorder, DefaultSettings, GameSettings, PlayerColor};
bookkeeping::save_state::{SaveState, SaveStateEntry},
recorder::Recorder,
GameSettings, PlayerColor,
};
pub mod messages; pub mod messages;
mod proxy_opt; mod proxy_opt;
pub mod steam_networking; pub mod steam_networking;
@ -133,6 +129,7 @@ pub struct NetManager {
pub friendly_fire: AtomicBool, pub friendly_fire: AtomicBool,
pub ban_list: Mutex<Vec<OmniPeerId>>, pub ban_list: Mutex<Vec<OmniPeerId>>,
pub kick_list: Mutex<Vec<OmniPeerId>>, pub kick_list: Mutex<Vec<OmniPeerId>>,
pub no_more_players: AtomicBool,
} }
impl NetManager { impl NetManager {
@ -155,6 +152,7 @@ impl NetManager {
friendly_fire: AtomicBool::new(false), friendly_fire: AtomicBool::new(false),
ban_list: Default::default(), ban_list: Default::default(),
kick_list: Default::default(), kick_list: Default::default(),
no_more_players: AtomicBool::new(false),
} }
.into() .into()
} }
@ -472,6 +470,7 @@ impl NetManager {
.expect("can set write timeout"); .expect("can set write timeout");
let settings = self.settings.lock().unwrap(); let settings = self.settings.lock().unwrap();
let def = DefaultSettings::default();
state.try_ws_write(ws_encode_proxy("seed", settings.seed)); state.try_ws_write(ws_encode_proxy("seed", settings.seed));
let my_id = self.peer.my_id(); let my_id = self.peer.my_id();
state.try_ws_write(ws_encode_proxy("peer_id", format!("{:016x}", my_id.0))); state.try_ws_write(ws_encode_proxy("peer_id", format!("{:016x}", my_id.0)));
@ -485,25 +484,27 @@ impl NetManager {
} else { } else {
info!("No nickname chosen"); info!("No nickname chosen");
} }
self.friendly_fire let ff = settings.friendly_fire.unwrap_or(def.friendly_fire);
.store(settings.friendly_fire, atomic::Ordering::Relaxed); self.friendly_fire.store(ff, atomic::Ordering::Relaxed);
state.try_ws_write_option("friendly_fire", settings.friendly_fire); state.try_ws_write_option("friendly_fire", ff);
state.try_ws_write_option("debug", settings.debug_mode); state.try_ws_write_option("debug", settings.debug_mode.unwrap_or(def.debug_mode));
state.try_ws_write_option("world_sync_version", settings.world_sync_version); state.try_ws_write_option("world_sync_version", settings.world_sync_version.unwrap_or(def.world_sync_version));
state.try_ws_write_option("player_tether", settings.player_tether); state.try_ws_write_option("player_tether", settings.player_tether.unwrap_or(def.player_tether));
state.try_ws_write_option("tether_length", settings.tether_length); state.try_ws_write_option("tether_length", settings.tether_length.unwrap_or(def.tether_length));
state.try_ws_write_option("item_dedup", settings.item_dedup); state.try_ws_write_option("item_dedup", settings.item_dedup.unwrap_or(def.item_dedup));
state.try_ws_write_option("randomize_perks", settings.randomize_perks); state.try_ws_write_option("randomize_perks", settings.randomize_perks.unwrap_or(def.randomize_perks));
state.try_ws_write_option("enemy_hp_scale", settings.enemy_hp_mult); state.try_ws_write_option("enemy_hp_scale", settings.enemy_hp_mult.unwrap_or(def.enemy_hp_mult));
state.try_ws_write_option("world_sync_interval", settings.world_sync_interval); state.try_ws_write_option("world_sync_interval", settings.world_sync_interval.unwrap_or(def.world_sync_interval));
state.try_ws_write_option("game_mode", settings.game_mode); state.try_ws_write_option("game_mode", settings.game_mode.unwrap_or(def.game_mode));
state.try_ws_write_option("chunk_target", settings.chunk_target); state.try_ws_write_option("chunk_target", settings.chunk_target.unwrap_or(def.chunk_target));
state.try_ws_write_option("health_per_player", settings.health_per_player); state.try_ws_write_option("health_per_player", settings.health_per_player.unwrap_or(def.health_per_player));
state.try_ws_write_option("enemy_sync_interval", settings.enemy_sync_interval); state.try_ws_write_option("enemy_sync_interval", settings.enemy_sync_interval.unwrap_or(def.enemy_sync_interval));
state.try_ws_write_option("global_hp_loss", settings.global_hp_loss); state.try_ws_write_option("global_hp_loss", settings.global_hp_loss.unwrap_or(def.global_hp_loss));
state.try_ws_write_option("perk_ban_list", settings.perk_ban_list.as_str()); state.try_ws_write_option("perma_death", settings.perma_death.unwrap_or(def.perma_death));
state.try_ws_write_option("no_material_damage", settings.no_material_damage); let lst = settings.clone();
state.try_ws_write_option("health_lost_on_revive", settings.health_lost_on_revive); state.try_ws_write_option("perk_ban_list", lst.perk_ban_list.unwrap_or(def.perk_ban_list).as_str());
state.try_ws_write_option("no_material_damage", settings.no_material_damage.unwrap_or(def.no_material_damage));
state.try_ws_write_option("health_lost_on_revive", settings.health_lost_on_revive.unwrap_or(def.health_lost_on_revive));
let rgb = self.init_settings.player_color.player_main; let rgb = self.init_settings.player_color.player_main;
state.try_ws_write_option( state.try_ws_write_option(
"mina_color", "mina_color",

View file

@ -0,0 +1,37 @@
<Entity tags="polymorphed_cessation" name="$animal_player" >
<PlatformShooterPlayerComponent
center_camera_on_this_entity="1"
aiming_reticle_distance_from_character="60"
camera_max_distance_from_character="50"
move_camera_with_aim="1"
eating_area_min.x="-6"
eating_area_max.x="6"
eating_area_min.y="-4"
eating_area_max.y="6"
eating_cells_per_frame="2"
></PlatformShooterPlayerComponent>
<ControlsComponent
enabled="1"
gamepad_fire_on_thumbstick_extend="0"
gamepad_fire_on_thumbstick_extend_threshold="0.9"
gamepad_indirect_aiming_enabled="0"
></ControlsComponent>
<Entity name="cursor">
<SpriteComponent
alpha="1"
image_file="mods/quant.ew/files/resource/sprites/cursor.png"
next_rect_animation=""
offset_x="6.5"
offset_y="6.5"
emissive="1"
additive="1"
rect_animation=""
z_index="1"
update_transform="1"
update_transform_rotation="0"
has_special_scale="1"
special_scale_x="0.5"
special_scale_y="0.5"
></SpriteComponent>
</Entity>
</Entity>

View file

@ -176,9 +176,22 @@ local function player_died()
-- This may look like a hack, but it allows to use existing poly machinery to change player entity AND to store the original player for later, -- This may look like a hack, but it allows to use existing poly machinery to change player entity AND to store the original player for later,
-- Which is, like, perfect. -- Which is, like, perfect.
GameAddFlagRun("ew_flag_notplayer_active")
if ctx.proxy_opt.perma_death then
local ent = LoadGameEffectEntityTo(ctx.my_player.entity, "mods/quant.ew/files/system/local_health/notplayer/cessation.xml")
polymorph.switch_entity(ent + 1)
GameAddFlagRun("msg_gods_looking")
GameAddFlagRun("msg_gods_looking2")
EntityAddTag(ctx.my_player.entity, "ew_notplayer")
for _, child in ipairs(EntityGetAllChildren(ctx.my_player.entity) or {}) do
if EntityGetName(child) == "cursor" then
EntitySetComponentIsEnabled(child, EntityGetFirstComponentIncludingDisabled(child, "SpriteComponent"), false)
end
end
return
end
local ent = LoadGameEffectEntityTo(ctx.my_player.entity, "mods/quant.ew/files/system/local_health/notplayer/poly_effect.xml") local ent = LoadGameEffectEntityTo(ctx.my_player.entity, "mods/quant.ew/files/system/local_health/notplayer/poly_effect.xml")
ctx.my_player.entity = ent + 1 ctx.my_player.entity = ent + 1
GameAddFlagRun("ew_flag_notplayer_active")
do_switch_effect(false) do_switch_effect(false)
EntitySetName(ctx.my_player.entity, ctx.my_id.."?") EntitySetName(ctx.my_player.entity, ctx.my_id.."?")
util.set_ent_health(ctx.my_player.entity, {max_hp, max_hp}) util.set_ent_health(ctx.my_player.entity, {max_hp, max_hp})
@ -191,7 +204,7 @@ local function player_died()
remove_healthbar_locally() remove_healthbar_locally()
for _, child in ipairs(EntityGetAllChildren(ctx.my_player.entity) or {}) do for _, child in ipairs(EntityGetAllChildren(ctx.my_player.entity) or {}) do
if EntityGetName(child) == "cursor" or EntityGetName(child) == "notcursor" then if EntityGetName(child) == "cursor" or EntityGetName(child) == "notcursor" then
EntityKill(child) EntitySetComponentIsEnabled(child, EntityGetFirstComponentIncludingDisabled(child, "SpriteComponent"), false)
end end
end end
inventory_helper.set_item_data(item_data, ctx.my_player) inventory_helper.set_item_data(item_data, ctx.my_player)

View file

@ -0,0 +1,13 @@
<Entity>
<InheritTransformComponent>
</InheritTransformComponent>
<GameEffectComponent
effect="POLYMORPH_CESSATION"
frames="-1"
disable_movement="0"
polymorph_target="data/entities/animals/nibbana.xml"
>
</GameEffectComponent >
</Entity>

View file

@ -637,6 +637,8 @@ local function choose_movement()
ComponentSetValue2(state.control_component, "mButtonFrameRight", GameGetFrameNum()+100) ComponentSetValue2(state.control_component, "mButtonFrameRight", GameGetFrameNum()+100)
return return
end end
local air = ComponentGetValue2(state.damage_model, "air_in_lungs")
local fly = ComponentGetValue2(state.data_component, "mFlyingTimeLeft")
if state.target == nil or (has_ambrosia(ctx.my_player.entity) and state.init_timer > no_shoot_time + 4) then if state.target == nil or (has_ambrosia(ctx.my_player.entity) and state.init_timer > no_shoot_time + 4) then
state.control_a = false state.control_a = false
state.control_d = false state.control_d = false
@ -663,13 +665,14 @@ local function choose_movement()
move = -1 move = -1
end end
local air = ComponentGetValue2(state.damage_model, "air_in_lungs") if air < 2 then
if air < 1 then if fly < 0.5 then
state.control_w = true state.control_s = true
state.control_s = false state.control_w = false
elseif air < 2 then else
state.control_s = true state.control_w = true
state.control_w = false state.control_s = false
end
end end
return return
end end
@ -752,7 +755,7 @@ local function choose_movement()
on_right = my_x > t_x on_right = my_x > t_x
end end
if ComponentGetValue2(state.data_component, "mFlyingTimeLeft") < 0.2 and GameGetFrameNum() % 300 > 250 then if fly < 0.2 and GameGetFrameNum() % 300 > 250 then
rest = true rest = true
give_space = give_space + 10 give_space = give_space + 10
swap_side = false swap_side = false
@ -863,13 +866,14 @@ local function choose_movement()
if did_hit_up and state.water_potion ~= nil then if did_hit_up and state.water_potion ~= nil then
state.control_w = false state.control_w = false
end end
local air = ComponentGetValue2(state.damage_model, "air_in_lungs") if air < 2 then
if air < 1 then if fly < 0.5 then
state.control_w = true state.control_s = true
state.control_s = false state.control_w = false
elseif air < 2 then else
state.control_s = true state.control_w = true
state.control_w = false state.control_s = false
end
end end
end end
@ -1441,6 +1445,7 @@ end
function module.on_world_update() function module.on_world_update()
local active = GameHasFlagRun("ew_flag_notplayer_active") local active = GameHasFlagRun("ew_flag_notplayer_active")
and not ctx.proxy_opt.perma_death
if active and EntityGetIsAlive(ctx.my_player.entity) and EntityHasTag(ctx.my_player.entity, "ew_notplayer") then if active and EntityGetIsAlive(ctx.my_player.entity) and EntityHasTag(ctx.my_player.entity, "ew_notplayer") then
if state == nil then if state == nil then
init_state() init_state()

View file

@ -74,8 +74,15 @@ function module.on_world_update()
local mx, my = GameGetCameraPos() local mx, my = GameGetCameraPos()
for peer_id, player in pairs(ctx.players) do for peer_id, player in pairs(ctx.players) do
local ent = player.entity local ent = player.entity
local children = EntityGetAllChildren(ent) or {}
for _, child in ipairs(children) do
if EntityGetName(child) == "cursor" or EntityGetName(child) == "notcursor" then
EntitySetComponentIsEnabled(child, EntityGetFirstComponentIncludingDisabled(child, "SpriteComponent"), true)
end
end
local x, y = EntityGetTransform(ent) local x, y = EntityGetTransform(ent)
local notplayer = EntityHasTag(ent, "ew_notplayer") local notplayer = EntityHasTag(ent, "ew_notplayer")
and not ctx.proxy_opt.perma_death
if notplayer and GameHasFlagRun("ending_game_completed") then if notplayer and GameHasFlagRun("ending_game_completed") then
goto continue goto continue
end end
@ -84,7 +91,7 @@ function module.on_world_update()
end end
local dx, dy = x - mx, y - my local dx, dy = x - mx, y - my
local cape local cape
for _, child in ipairs(EntityGetAllChildren(ent) or {}) do for _, child in ipairs(children) do
if EntityGetName(child) == "cape" then if EntityGetName(child) == "cape" then
local cpe = EntityGetFirstComponentIncludingDisabled(child, "VerletPhysicsComponent") local cpe = EntityGetFirstComponentIncludingDisabled(child, "VerletPhysicsComponent")
local cx, cy = ComponentGetValue2(cpe, "m_position_previous") local cx, cy = ComponentGetValue2(cpe, "m_position_previous")

View file

@ -72,7 +72,7 @@ local function get_me()
local i = 0 local i = 0
local alive = -1, -1 local alive = -1, -1
for peer_id, potential_target in pairs(ctx.players) do for peer_id, potential_target in pairs(ctx.players) do
if GameHasFlagRun("ending_game_completed") and EntityHasTag(potential_target.entity, "ew_notplayer") then if (GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death) and EntityHasTag(potential_target.entity, "ew_notplayer") then
goto continue goto continue
end end
i = i + 1 i = i + 1
@ -218,7 +218,7 @@ local function set_camera_pos()
if cam_target == nil or re_cam then if cam_target == nil or re_cam then
local i = 0 local i = 0
for peer_id, potential_target in pairs(ctx.players) do for peer_id, potential_target in pairs(ctx.players) do
if GameHasFlagRun("ending_game_completed") and EntityHasTag(potential_target.entity, "ew_notplayer") then if (GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death) and EntityHasTag(potential_target.entity, "ew_notplayer") then
goto continue goto continue
end end
i = i + 1 i = i + 1
@ -246,7 +246,8 @@ end
local function update_i() local function update_i()
local i = 0 local i = 0
for peer_id, potential_target in pairs(ctx.players) do for peer_id, potential_target in pairs(ctx.players) do
if GameHasFlagRun("ending_game_completed") and EntityHasTag(potential_target.entity, "ew_notplayer") then if (GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death)
and EntityHasTag(potential_target.entity, "ew_notplayer") then
goto continue goto continue
end end
i = i + 1 i = i + 1
@ -263,7 +264,7 @@ end
local function number_of_players() local function number_of_players()
local i = 0 local i = 0
for _, potential_target in pairs(ctx.players) do for _, potential_target in pairs(ctx.players) do
if GameHasFlagRun("ending_game_completed") and EntityHasTag(potential_target.entity, "ew_notplayer") then if (GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death) and EntityHasTag(potential_target.entity, "ew_notplayer") then
goto continue goto continue
end end
i = i + 1 i = i + 1
@ -296,7 +297,9 @@ function spectate.on_world_update()
update_i() update_i()
last_len = number_of_players() last_len = number_of_players()
end end
if cam_target ~= nil and GameHasFlagRun("ending_game_completed") and EntityHasTag(cam_target.entity, "ew_notplayer") then if cam_target ~= nil
and ((GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death)
and EntityHasTag(cam_target.entity, "ew_notplayer")) then
update_i() update_i()
last_len = number_of_players() last_len = number_of_players()
end end

View file

@ -2,6 +2,15 @@ local rpc = net.new_rpc_namespace()
local shield_entities = {} local shield_entities = {}
local function remove_shield(peer_id)
if shield_entities[peer_id] ~= nil then
if EntityGetIsAlive(shield_entities[peer_id][2]) then
EntityKill(shield_entities[peer_id][2])
end
shield_entities[peer_id] = nil
end
end
rpc.opts_everywhere() rpc.opts_everywhere()
rpc.opts_reliable() rpc.opts_reliable()
function rpc.add_shield(target) function rpc.add_shield(target)
@ -12,23 +21,21 @@ function rpc.add_shield(target)
if not EntityGetIsAlive(entity) or EntityHasTag(entity, "polymorphed") then if not EntityGetIsAlive(entity) or EntityHasTag(entity, "polymorphed") then
return return
end end
if shield_entities[ctx.rpc_peer_id] ~= nil then if shield_entities[ctx.rpc_peer_id] == nil or shield_entities[ctx.rpc_peer_id][1] ~= target then
EntityKill(shield_entities[ctx.rpc_peer_id][2]) if shield_entities[ctx.rpc_peer_id] ~= nil
and EntityGetIsAlive(shield_entities[ctx.rpc_peer_id][2]) then
EntityKill(shield_entities[ctx.rpc_peer_id][2])
end
local ent = EntityLoad("mods/quant.ew/files/system/spectator_helps/shield_base.xml")
EntityAddChild(entity, ent)
shield_entities[ctx.rpc_peer_id] = {target, ent}
end end
local ent = EntityLoad("mods/quant.ew/files/system/spectator_helps/shield_base.xml")
EntityAddChild(entity, ent)
shield_entities[ctx.rpc_peer_id] = {target, ent}
end end
rpc.opts_everywhere() rpc.opts_everywhere()
rpc.opts_reliable() rpc.opts_reliable()
function rpc.del_shield() function rpc.del_shield()
if shield_entities[ctx.rpc_peer_id] ~= nil then remove_shield(ctx.rpc_peer_id)
if EntityGetIsAlive(shield_entities[ctx.rpc_peer_id][2]) then
EntityKill(shield_entities[ctx.rpc_peer_id][2])
end
shield_entities[ctx.rpc_peer_id] = nil
end
end end
local module = {} local module = {}
@ -48,11 +55,11 @@ local function is_acceptable_help_target(spectating_over)
return false return false
end end
if shield_entities[ctx.my_id] ~= nil then if shield_entities[ctx.my_id] ~= nil then
if shield_entities[ctx.my_id][1] ~= spectating_over then if shield_entities[ctx.my_id][1] ~= spectating_over then
rpc.del_shield() rpc.del_shield()
return false return false
end end
return false return GameGetFrameNum() % 300 < 10
end end
return true return true
end end
@ -77,7 +84,10 @@ end
local last_spectate local last_spectate
function module.on_world_update() function module.on_world_update()
if GameHasFlagRun("ending_game_completed") then if GameHasFlagRun("ending_game_completed") or ctx.proxy_opt.perma_death then
if not ctx.proxy_opt.perma_death then
rpc.del_shield()
end
return return
end end
if GameGetFrameNum() % 10 == 8 then if GameGetFrameNum() % 10 == 8 then