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
global_hp_loss = Lose HP globally
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_2 = Percentage-based damage and full heals are adjusted.
shared_health_desc_3 = The original mode.

View file

@ -63,15 +63,39 @@ pub(crate) enum GameMode {
// MestariMina, // TODO later
}
#[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(default)]
pub struct GameSettings {
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,
world_sync_version: u32,
player_tether: bool,
tether_length: u32,
use_constant_seed: bool,
item_dedup: bool,
enemy_hp_mult: f32,
world_sync_interval: u32,
@ -81,24 +105,22 @@ pub struct GameSettings {
chunk_target: u32,
enemy_sync_interval: u32,
randomize_perks: bool,
progress: Vec<String>,
max_players: u32,
health_per_player: u32,
health_lost_on_revive: u32,
no_material_damage: bool,
global_hp_loss: bool,
perk_ban_list: String,
perma_death: bool,
}
impl Default for GameSettings {
impl Default for DefaultSettings {
fn default() -> Self {
GameSettings {
seed: 0,
DefaultSettings {
debug_mode: false,
world_sync_version: 2,
player_tether: true,
tether_length: 2048,
use_constant_seed: false,
item_dedup: true,
randomize_perks: true,
enemy_hp_mult: 1.0,
@ -108,13 +130,13 @@ impl Default for GameSettings {
friendly_fire_team: 0,
chunk_target: 24,
enemy_sync_interval: 3,
progress: Vec::new(),
max_players: 250,
health_per_player: 100,
health_lost_on_revive: 0,
no_material_damage: 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(
steamworks::LobbyType::Private,
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());
self.set_netman_settings(&netman);
@ -720,56 +742,93 @@ impl App {
}
fn show_game_settings(&mut self, ui: &mut Ui, show_local: bool) {
let def = DefaultSettings::default();
heading_with_underline(ui, tr("connect_settings"));
let game_settings = &mut self.app_saved_state.game_settings;
ui.label(tr("Game-mode"));
ui.radio_value(
&mut game_settings.game_mode,
GameMode::SharedHealth,
tr("Shared-health"),
);
ui.radio_value(
&mut game_settings.game_mode,
GameMode::LocalHealth,
tr("Local-health"),
);
{
let mut temp = game_settings.game_mode.unwrap_or(def.game_mode);
ui.label(tr("Game-mode"));
if ui.radio_value(
&mut temp,
GameMode::SharedHealth,
tr("Shared-health"),
).changed() || ui.radio_value(
&mut temp,
GameMode::LocalHealth,
tr("Local-health"),
).changed() {
game_settings.game_mode = Some(temp)
}
}
ui.scope(|ui| {
ui.set_height(100.0);
match game_settings.game_mode {
match game_settings.game_mode.unwrap_or(def.game_mode) {
GameMode::SharedHealth => {
ui.label(tr("shared_health_desc_1"));
ui.label(tr("shared_health_desc_2"));
ui.label(tr("shared_health_desc_3"));
ui.add_space(5.0);
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 => {
ui.label(tr("local_health_desc_1"));
ui.label(tr("local_health_desc_2"));
ui.add_space(5.0);
ui.label(tr("Health-percent-lost-on-reviving"));
ui.add(Slider::new(
&mut game_settings.health_lost_on_revive,
0..=100,
));
ui.checkbox(&mut game_settings.global_hp_loss, tr("global_hp_loss"));
ui.checkbox(
&mut game_settings.no_material_damage,
tr("no_material_damage"),
);
{
let mut temp = game_settings.health_lost_on_revive.unwrap_or(def.health_lost_on_revive);
if ui.add(Slider::new(
&mut temp,
0..=100,
)).changed() {
game_settings.health_lost_on_revive = Some(temp)
}
}
{
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.label(tr("connect_settings_debug"));
ui.checkbox(
&mut game_settings.debug_mode,
tr("connect_settings_debug_en"),
);
{
let mut temp = game_settings.debug_mode.unwrap_or(def.debug_mode);
if ui.checkbox(
&mut temp,
tr("connect_settings_debug_en"),
).changed() {
game_settings.debug_mode = Some(temp)
}
}
ui.checkbox(
&mut game_settings.use_constant_seed,
tr("connect_settings_debug_fixed_seed"),
@ -780,40 +839,87 @@ impl App {
});
ui.add_space(10.0);
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.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.label(tr("connect_settings_player_tether_desc"));
ui.checkbox(
&mut game_settings.player_tether,
tr("connect_settings_player_tether"),
);
ui.add(
Slider::new(&mut game_settings.tether_length, 10..=5000)
.text(tr("connect_settings_player_tether_length")),
);
{
let mut temp = game_settings.player_tether.unwrap_or(def.player_tether);
if ui.checkbox(
&mut temp,
tr("connect_settings_player_tether"),
).changed()
{
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.checkbox(
&mut game_settings.item_dedup,
tr("connect_settings_item_dedup"),
);
ui.checkbox(
&mut game_settings.randomize_perks,
tr("Have-perk-pools-be-independent-of-each-other"),
);
ui.horizontal(|ui| {
ui.text_edit_singleline(&mut game_settings.perk_ban_list);
ui.label("perk ban list, comma seperated");
});
ui.add(
Slider::new(&mut game_settings.enemy_hp_mult, 1.0..=1000.0)
.logarithmic(true)
.text(tr("connect_settings_enemy_hp_scale")),
);
ui.checkbox(&mut game_settings.friendly_fire, tr("Enable-friendly-fire"));
{
let mut temp = game_settings.item_dedup.unwrap_or(def.item_dedup);
if ui.checkbox(
&mut temp,
tr("connect_settings_item_dedup"),
).changed() {
game_settings.item_dedup = Some(temp)
}
}
{
let mut temp = game_settings.randomize_perks.unwrap_or(def.randomize_perks);
if ui.checkbox(
&mut temp,
tr("Have-perk-pools-be-independent-of-each-other"),
).changed() {
game_settings.randomize_perks = Some(temp)
}
}
{
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 {
heading_with_underline(ui, tr("connect_settings_local"));
ui.checkbox(
@ -1097,10 +1203,14 @@ impl eframe::App for App {
ui.add_space(15.0);
if netman.friendly_fire.load(Ordering::Relaxed) {
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
|| 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.add_space(15.0);
@ -1462,4 +1572,4 @@ pub fn host_cli(port: u16) {
let player_path = netmaninit.player_path.clone();
let netman = net::NetManager::new(varient, netmaninit);
netman.start_inner(player_path, true).unwrap();
}
}

View file

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