Merge branch 'socksonme/rework_sct' into 'master'

Rework SCT

See merge request veloren/veloren!3126
This commit is contained in:
Samuel Keiffer 2022-07-02 02:42:42 +00:00
commit 0bd08b1f9e
49 changed files with 890 additions and 803 deletions

View File

@ -31,6 +31,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Chest sprites can longer be exploded
- Smoke varies by temperature, humidity, time of day and house
- Added loot ownership for drops from mining
- Added an option for experience number accumulation.
- Added an option for damage number rounding (when greater than or equal to 1.0).
- Added sliders for incoming/non-incoming damage accumulation duration.
### Changed
@ -43,8 +46,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Zoom-in effect when aiming bow is now optional
- Non-Humanoid NPCs now pick up consumables when less than full health and use them to heal up.
- Changed module component modifier costs to the following scheme, based on base material: 1 -> 2 -> 5 -> 10 -> 15 -> 25
- Damage from the same source dealt in the same tick will now be grouped up.
- Critical hits are now shown differently in the damage numbers.
- Fall damage and some (extra) buffs/debuffs now show up in the damage numbers.
### Removed
- Removed the options for single and cumulated damage.
### Fixed
- Fixed bug that would sometimes cause taking a screenshot to panic because a buffer was mapped at the wrong time.
@ -57,7 +64,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix villagers seeing cultists and familiar enemies through objects.
- Menacing agents are now less spammy with their menacing messages
- Fixed the title screen FPS cap not applying when the background FPS limit was set higher than 60 FPS
- Fixed an issue where the hurt animation would "jump" whenever you lost/gained health.
- Fixed a bug where multiple damage sources in the same tick would show up as a singular attack.
- Fixed an issue where, if the same amount of healing and damage was received in the same tick, nothing would be shown.
## [0.12.0] - 2022-02-19
### Added

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Статусныя эфекты каля мінімапы",
"hud.settings.toggle_bar_experience": "Адлюстроўваць панэль досведу",
"hud.settings.scrolling_combat_text": "Адлюстроўваць шкоду/злечванне",
"hud.settings.single_damage_number": "Шкода ад кожнага ўдару",
"hud.settings.cumulated_damage": "Сумарная шкода",
"hud.settings.incoming_damage": "Шкода ад кожнага ўдара па гульцу",
"hud.settings.cumulated_incoming_damage": "Сумарная шкода па гульцу",
"hud.settings.speech_bubble": "Індыкатар гаворкі",
"hud.settings.speech_bubble_self": "Паказваць свае індыкатары гаворкі",
"hud.settings.speech_bubble_dark_mode": "Цёмны рэжым індыкатара гаворкі",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Buffs al Minimapa",
"hud.settings.toggle_bar_experience": "Mostra Barra d'Experiència",
"hud.settings.scrolling_combat_text": "Text de Combat Desplaçat",
"hud.settings.single_damage_number": "Danys en Nombres Rodons",
"hud.settings.cumulated_damage": "Dany Acumulat",
"hud.settings.incoming_damage": "Dany Imminent",
"hud.settings.cumulated_incoming_damage": "Dany Imminent Acumulat",
"hud.settings.speech_bubble": "Bafarades",
"hud.settings.speech_bubble_self": "Mostrar les Bafarades pròpies",
"hud.settings.speech_bubble_dark_mode": "Bafarades Mode Fosc",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Buffy u Minimapy",
"hud.settings.toggle_bar_experience": "Povolit Zkušenostní Bar",
"hud.settings.scrolling_combat_text": "Létajíci Text v boji",
"hud.settings.single_damage_number": "Jednotná čísla Poškození",
"hud.settings.cumulated_damage": "Seskupené Poškození",
"hud.settings.incoming_damage": "Příchozí Poškození",
"hud.settings.cumulated_incoming_damage": "Seskupené Příchozí Poškození",
"hud.settings.speech_bubble": "Povídací Bublina",
"hud.settings.speech_bubble_dark_mode": "Tmavá Povídací Bublina",
"hud.settings.speech_bubble_icon": "Ikona Povídací Bubliny",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Effekte an der Minimap",
"hud.settings.toggle_bar_experience": "Erfahrungsleiste umschalten",
"hud.settings.scrolling_combat_text": "Fließtext für Kampfhandlungen",
"hud.settings.single_damage_number": "Schaden einzeln anzeigen",
"hud.settings.cumulated_damage": "Gesamtschaden anzeigen",
"hud.settings.incoming_damage": "Erlittener Schaden",
"hud.settings.cumulated_incoming_damage": "Gesamter erlittener Schaden",
"hud.settings.speech_bubble": "Sprechblase",
"hud.settings.speech_bubble_dark_mode": "Sprechblase: Nachtmodus",
"hud.settings.speech_bubble_icon": "Sprechblasen-Icon",

View File

@ -25,16 +25,18 @@
"hud.settings.buffs_mmap": "Buffs at Minimap",
"hud.settings.toggle_bar_experience": "Toggle Experience Bar",
"hud.settings.scrolling_combat_text": "Scrolling Combat Text",
"hud.settings.single_damage_number": "Single Damage Numbers",
"hud.settings.cumulated_damage": "Cumulated Damage",
"hud.settings.damage_accumulation_duration": "Damage Accumulation Duration",
"hud.settings.incoming_damage": "Incoming Damage",
"hud.settings.cumulated_incoming_damage": "Cumulated Incoming Damage",
"hud.settings.incoming_damage_accumulation_duration": "Incoming Damage Accumulation Duration",
"hud.settings.round_damage": "Round Damage",
"hud.settings.speech_bubble": "Speech Bubble",
"hud.settings.speech_bubble_self": "Show Own Speech Bubbles",
"hud.settings.speech_bubble_dark_mode": "Speech Bubble Dark Mode",
"hud.settings.speech_bubble_icon": "Speech Bubble Icon",
"hud.settings.energybar_numbers": "Energybar Numbers",
"hud.settings.always_show_bars": "Always show Energybars",
"hud.settings.experience_numbers": "Experience Numbers",
"hud.settings.accumulate_experience": "Accumulate Experience Numbers",
"hud.settings.values": "Values",
"hud.settings.percentages": "Percentages",
"hud.settings.chat": "Chat",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Estados en el Minimapa",
"hud.settings.toggle_bar_experience": "Alternar Barra de Experiencia",
"hud.settings.scrolling_combat_text": "Texto de Combate Deslizante",
"hud.settings.single_damage_number": "Números de Daño Único",
"hud.settings.cumulated_damage": "Daño Acumulado",
"hud.settings.incoming_damage": "Daño Entrante",
"hud.settings.cumulated_incoming_damage": "Daño Entrante Acumulado",
"hud.settings.speech_bubble": "Burbuja de Diálogo",
"hud.settings.speech_bubble_self": "Mostrar Diálogos propios en Burbuja",
"hud.settings.speech_bubble_dark_mode": "Modo Oscuro de Burbuja de Diálogo",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Buffs en el Minimapa",
"hud.settings.toggle_bar_experience": "Alternar Barra de Experiencia",
"hud.settings.scrolling_combat_text": "Texto de Combate con Desplazamiento",
"hud.settings.single_damage_number": "Números de Daño Singular",
"hud.settings.cumulated_damage": "Daño Acumulado",
"hud.settings.incoming_damage": "Daño Recibido",
"hud.settings.cumulated_incoming_damage": "Daño Recibido Acumulado",
"hud.settings.speech_bubble": "Burbuja de Diálogo",
"hud.settings.speech_bubble_self": "Mostrar Diálogos propios en Burbuja",
"hud.settings.speech_bubble_dark_mode": "Burbuja de Diálogo en Modo Oscuro",

View File

@ -18,10 +18,7 @@
"hud.settings.opacity": "Opakotasuna",
"hud.settings.toggle_shortcuts": "Aldatu laster teklak",
"hud.settings.toggle_bar_experience": "Erakutsi/ezkutatu esperientzia barra",
"hud.settings.single_damage_number": "Egindako kaltea banaka erakutsi",
"hud.settings.cumulated_damage": "Egindako kaltea metatuta erakutsi",
"hud.settings.incoming_damage": "Jasotako kaltea banaka erakutsi",
"hud.settings.cumulated_incoming_damage": "Jasotako kalte metatua erakutsi",
"hud.settings.energybar_numbers": "Zenbakiak energia barran",
"hud.settings.always_show_bars": "Erakutsi beti energia barra",
"hud.settings.values": "Balioak",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Effets sur la minimap",
"hud.settings.toggle_bar_experience": "Activer la barre d'expérience",
"hud.settings.scrolling_combat_text": "Dégats de combat",
"hud.settings.single_damage_number": "Dégats infligés",
"hud.settings.cumulated_damage": "Dégat infligés cumulés",
"hud.settings.incoming_damage": "Dégats reçus",
"hud.settings.cumulated_incoming_damage": "Dégats reçus cumulés",
"hud.settings.speech_bubble": "Bulle de dialogue",
"hud.settings.speech_bubble_self": "Montrer ses propres bulles de dialogue",
"hud.settings.speech_bubble_dark_mode": "Bulle de dialogue Mode Sombre",

View File

@ -24,10 +24,7 @@
"hud.settings.buffs_mmap": "Hatások a minitérképnél",
"hud.settings.toggle_bar_experience": "Tapasztalatsáv megjelenítése/elrejtése",
"hud.settings.scrolling_combat_text": "Harci szöveg görgetése",
"hud.settings.single_damage_number": "Minden egyes sebzés",
"hud.settings.cumulated_damage": "Összes sebzés",
"hud.settings.incoming_damage": "Bejövő sebzés",
"hud.settings.cumulated_incoming_damage": "Összes bejövő sebzés",
"hud.settings.speech_bubble": "Szövegbuborék",
"hud.settings.speech_bubble_dark_mode": "Szövegbuborék sötét mód",
"hud.settings.speech_bubble_icon": "Szövegbuborék ikon",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Buff alla Minimappa",
"hud.settings.toggle_bar_experience": "Attiva/Disattiva Barra dell'Esperienza",
"hud.settings.scrolling_combat_text": "Testo del Combattimento a Scorrimento",
"hud.settings.single_damage_number": "Numero Danni Singoli",
"hud.settings.cumulated_damage": "Danno Accumulato",
"hud.settings.incoming_damage": "Danno in Entrata",
"hud.settings.cumulated_incoming_damage": "Danno in Entrata Accumulato",
"hud.settings.speech_bubble": "Fumetto",
"hud.settings.speech_bubble_self": "Mostra i Propri Fumetti",
"hud.settings.speech_bubble_dark_mode": "Fumetto Modalità Scura",

View File

@ -22,10 +22,7 @@
"hud.settings.buffs_mmap": "Buffs at Minimap",
"hud.settings.toggle_bar_experience": "経験値バーの切り替え",
"hud.settings.scrolling_combat_text": "戦闘メッセージのスクロール",
"hud.settings.single_damage_number": "Single Damage Numbers",
"hud.settings.cumulated_damage": "Cumulated Damage",
"hud.settings.incoming_damage": "Incoming Damage",
"hud.settings.cumulated_incoming_damage": "Cumulated Incoming Damage",
"hud.settings.speech_bubble": "吹き出し",
"hud.settings.speech_bubble_dark_mode": "ダークモード吹き出し",
"hud.settings.speech_bubble_icon": "アイコン吹き出し",

View File

@ -20,10 +20,7 @@
"hud.settings.toggle_shortcuts": "Toon Sneltoetsen",
"hud.settings.toggle_bar_experience": "Toon Experience Balk",
"hud.settings.scrolling_combat_text": "Pop-up Gevechtstext",
"hud.settings.single_damage_number": "Aparte Schade Getallen",
"hud.settings.cumulated_damage": "Cumulatieve Schade Getallen",
"hud.settings.incoming_damage": "Inkomende Schade Getallen",
"hud.settings.cumulated_incoming_damage": "Cumulatieve Inkomende Schade Getallen",
"hud.settings.speech_bubble": "Spraakbubbel",
"hud.settings.speech_bubble_dark_mode": "Donkere Modus",
"hud.settings.speech_bubble_icon": "Spraakbubbel Icoon",

View File

@ -21,10 +21,7 @@
"hud.settings.buffs_mmap": "Ikoner på Minimap",
"hud.settings.toggle_bar_experience": "Veksle erfaringsbar",
"hud.settings.scrolling_combat_text": "Rullende kamptekst",
"hud.settings.single_damage_number": "Enkelt skadetall",
"hud.settings.cumulated_damage": "Kumulert skade",
"hud.settings.incoming_damage": "Innkommende skade",
"hud.settings.cumulated_incoming_damage": "Kumulert innkommende skade",
"hud.settings.speech_bubble": "Snakkeboble",
"hud.settings.speech_bubble_dark_mode": "Mørk modus for snakkeboble",
"hud.settings.speech_bubble_icon": "Snakkeboble ikon",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Wzmocnienia na minimapie",
"hud.settings.toggle_bar_experience": "Przełącz pasek doświadczenia",
"hud.settings.scrolling_combat_text": "Przewijanie tekstu podczas walki",
"hud.settings.single_damage_number": "Ujednolicone numery obrażeń",
"hud.settings.cumulated_damage": "Skumulowane obrażenia",
"hud.settings.incoming_damage": "Otrzymywane obrażenia",
"hud.settings.cumulated_incoming_damage": "Kalkulowane otrzymywane obrażenia",
"hud.settings.speech_bubble": "Dymek rozmowy",
"hud.settings.speech_bubble_self": "Pokazuj swój dymek rozmowy",
"hud.settings.speech_bubble_dark_mode": "Dymek rozmowy w trybie ciemnym",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Buffs no Minimapa",
"hud.settings.toggle_bar_experience": "Mostar/Ocultar Barra de Experiência",
"hud.settings.scrolling_combat_text": "Texto de Combate Deslizante",
"hud.settings.single_damage_number": "Números Únicos de Dano",
"hud.settings.cumulated_damage": "Dano Acumulado",
"hud.settings.incoming_damage": "Dano Recebido",
"hud.settings.cumulated_incoming_damage": "Dano Recebido Acumulado",
"hud.settings.speech_bubble": "Balão de Fala",
"hud.settings.speech_bubble_dark_mode": "Balão de Fala Modo Escuro",
"hud.settings.speech_bubble_icon": "Ícone do Balão de Fala",

View File

@ -19,10 +19,7 @@
"hud.settings.toggle_shortcuts": "Mostar/Ocultar atalhos",
"hud.settings.toggle_bar_experience": "Mostar/Ocultar barra de experiência",
"hud.settings.scrolling_combat_text": "Texto de combate deslizante",
"hud.settings.single_damage_number": "Números de dano únicos",
"hud.settings.cumulated_damage": "Dano acumulado",
"hud.settings.incoming_damage": "Dano recebido",
"hud.settings.cumulated_incoming_damage": "Dano recebido acumulado",
"hud.settings.energybar_numbers": "Números da barra de energia",
"hud.settings.values": "Valores",
"hud.settings.percentages": "Percentagens",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Баффы возле миникарте",
"hud.settings.toggle_bar_experience": "Переключить панель опыта",
"hud.settings.scrolling_combat_text": "Отображение урона/исцеления",
"hud.settings.single_damage_number": "Отдельно нанесённый",
"hud.settings.cumulated_damage": "Суммарно нанесённый",
"hud.settings.incoming_damage": "Отдельно полученный",
"hud.settings.cumulated_incoming_damage": "Суммарно полученный",
"hud.settings.speech_bubble": "Диалоговое окно",
"hud.settings.speech_bubble_self": "Показывать каждое отдельное окно",
"hud.settings.speech_bubble_dark_mode": "Диалоговое окно (тёмная тема)",

View File

@ -24,10 +24,7 @@
"hud.settings.buffs_mmap": "Бафови на Мапици",
"hud.settings.toggle_bar_experience": "Ис/Укључи Траку са Искуством",
"hud.settings.scrolling_combat_text": "Померајући Борбени Текст ",
"hud.settings.single_damage_number": "Појединачне Ране",
"hud.settings.cumulated_damage": "Акумулиране Ране",
"hud.settings.incoming_damage": "Долазне Ране",
"hud.settings.cumulated_incoming_damage": "Акумулирана Долазна Ране",
"hud.settings.speech_bubble": "Говорни Облачић",
"hud.settings.speech_bubble_dark_mode": "Тамни Говорни Облачић",
"hud.settings.speech_bubble_icon": "Иконица Говорног Облачића",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "Effekter vid Minikartan",
"hud.settings.toggle_bar_experience": "Visa/dölj erfarenhetsmätare",
"hud.settings.scrolling_combat_text": "Rullande stridstext",
"hud.settings.single_damage_number": "Ett enda skadenummer",
"hud.settings.cumulated_damage": "Sammanlagd skada",
"hud.settings.incoming_damage": "Inkommande skada",
"hud.settings.cumulated_incoming_damage": "Sammanlagd inkommande skada",
"hud.settings.speech_bubble": "Pratbubbla",
"hud.settings.speech_bubble_self": "Visa egna pratbubblor",
"hud.settings.speech_bubble_dark_mode": "Pratbubbla mörkt läge",

View File

@ -25,10 +25,7 @@
"hud.settings.buffs_mmap": "แสดงสถานะที่แผนที่",
"hud.settings.toggle_bar_experience": "เปิด/ปิดแถบค่าประสบการณ์",
"hud.settings.scrolling_combat_text": "ความเสียหายที่ทำได้",
"hud.settings.single_damage_number": "แสดงแต่ละเลขแยกกัน",
"hud.settings.cumulated_damage": "แสดงเลขรวมกันเป็นเลขเดียว",
"hud.settings.incoming_damage": "ความเสียหายที่ได้รับ",
"hud.settings.cumulated_incoming_damage": "ความเสียหายที่ได้รับแบบรวม",
"hud.settings.speech_bubble": "ลูกโป่งคำพูด",
"hud.settings.speech_bubble_self": "แสดงลูกโป่งคำพูด",
"hud.settings.speech_bubble_dark_mode": "แสดงลูกดป่งคำพูดแบบมืด",

View File

@ -22,10 +22,7 @@
"hud.settings.buffs_mmap": "Etkiler haritanın yanında",
"hud.settings.toggle_bar_experience": "Tecrübe çubuğunu aç/kapa",
"hud.settings.scrolling_combat_text": "Verilen/Alınan Hasar Yazısı",
"hud.settings.single_damage_number": "Verilen Hasarı Tek Tek Göster",
"hud.settings.cumulated_damage": "Toplam Verilen Hasarı Göster",
"hud.settings.incoming_damage": "Alınan Hasarı Tek Tek Göster",
"hud.settings.cumulated_incoming_damage": "Toplam Alınan Hasarı Göster",
"hud.settings.speech_bubble": "Konuşma balonu",
"hud.settings.speech_bubble_dark_mode": "Konuşma balonunda karanlık tema kullan",
"hud.settings.speech_bubble_icon": "Konuşma balonunda ikon göster",

View File

@ -24,10 +24,7 @@
"hud.settings.buffs_mmap": "Бафи біля Мінімапи",
"hud.settings.toggle_bar_experience": "Панель досвіду",
"hud.settings.scrolling_combat_text": "Відображення Пошкоджень/Зцілень",
"hud.settings.single_damage_number": "Роздільно нанесені Гравцем",
"hud.settings.cumulated_damage": "Сумарно нанесені Гравцем",
"hud.settings.incoming_damage": "Роздільно отримані Гравцем",
"hud.settings.cumulated_incoming_damage": "Сумарно отримані Гравцем",
"hud.settings.speech_bubble": "Діалоги",
"hud.settings.speech_bubble_dark_mode": "Темний режим",
"hud.settings.speech_bubble_icon": "Піктограма",

View File

@ -24,10 +24,7 @@
"hud.settings.buffs_mmap": "Buffs tại Minimap",
"hud.settings.toggle_bar_experience": "Bật tắt thanh kinh nghiệm",
"hud.settings.scrolling_combat_text": "Thông Tin Chiến Đấu",
"hud.settings.single_damage_number": "Sát thương từng đòn đánh",
"hud.settings.cumulated_damage": "Sát thương tích lũy",
"hud.settings.incoming_damage": "Sát thương nhận phải",
"hud.settings.cumulated_incoming_damage": "Sát thương tích lũy nhận phải",
"hud.settings.speech_bubble": "Bong Bóng Thoại",
"hud.settings.speech_bubble_dark_mode": "Chế độ tối màu",
"hud.settings.speech_bubble_icon": "Biểu tượng bong bóng thoại",

View File

@ -22,10 +22,7 @@
"hud.settings.buffs_mmap": "增益效果显示在小地图旁",
"hud.settings.toggle_bar_experience": "显示经验条",
"hud.settings.scrolling_combat_text": "战斗信息",
"hud.settings.single_damage_number": "单次伤害",
"hud.settings.cumulated_damage": "累计伤害",
"hud.settings.incoming_damage": "所受伤害",
"hud.settings.cumulated_incoming_damage": "累计所受伤害",
"hud.settings.speech_bubble": "对话框",
"hud.settings.speech_bubble_dark_mode": "对话框启用暗色模式",
"hud.settings.speech_bubble_icon": "对话框显示图标",

View File

@ -20,10 +20,7 @@
"hud.settings.toggle_shortcuts": "顯示快捷鍵",
"hud.settings.toggle_bar_experience": "顯示經驗條",
"hud.settings.scrolling_combat_text": "戰鬥訊息",
"hud.settings.single_damage_number": "單一傷害",
"hud.settings.cumulated_damage": "累積傷害",
"hud.settings.incoming_damage": "所受傷害",
"hud.settings.cumulated_incoming_damage": "累積所受傷害",
"hud.settings.energybar_numbers": "能量條",
"hud.settings.values": "數字",
"hud.settings.percentages": "百分比",

View File

@ -235,10 +235,11 @@ impl Attack {
self.crit_multiplier,
strength_modifier,
time,
damage.instance,
);
let applied_damage = -change.amount;
accumulated_damage += applied_damage;
emit_outcome(Outcome::Damage { pos: target.pos });
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
entity: target.entity,
@ -257,6 +258,8 @@ impl Attack {
by: attacker.map(|x| x.into()),
cause: Some(damage.damage.source),
time,
crit: is_crit,
instance: damage.instance,
};
emit(ServerEvent::HealthChange {
entity: target.entity,
@ -295,6 +298,8 @@ impl Attack {
amount: health_change,
by: attacker.map(|x| x.into()),
cause: Some(damage.damage.source),
instance: damage.instance,
crit: false,
time,
};
emit(ServerEvent::HealthChange {
@ -354,6 +359,8 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: false,
instance: rand::random(),
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -386,6 +393,8 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: false,
instance: rand::random(),
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -497,6 +506,8 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: false,
instance: rand::random(),
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -529,6 +540,8 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: false,
instance: rand::random(),
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -618,15 +631,18 @@ pub struct AttackDamage {
damage: Damage,
target: Option<GroupTarget>,
effects: Vec<CombatEffect>,
/// A random ID, used to group up attacks
instance: u64,
}
#[cfg(not(target_arch = "wasm32"))]
impl AttackDamage {
pub fn new(damage: Damage, target: Option<GroupTarget>) -> Self {
pub fn new(damage: Damage, target: Option<GroupTarget>, instance: u64) -> Self {
Self {
damage,
target,
effects: Vec::new(),
instance,
}
}
@ -818,6 +834,7 @@ impl Damage {
crit_mult: f32,
damage_modifier: f32,
time: Time,
instance: u64,
) -> HealthChange {
let mut damage = self.value * damage_modifier;
let critdamage = if is_crit {
@ -841,6 +858,8 @@ impl Damage {
by: damage_contributor,
cause: Some(self.source),
time,
crit: is_crit,
instance,
}
},
DamageSource::Falling => {
@ -853,6 +872,8 @@ impl Damage {
by: None,
cause: Some(self.source),
time,
crit: false,
instance,
}
},
DamageSource::Buff(_) | DamageSource::Other => HealthChange {
@ -860,6 +881,8 @@ impl Damage {
by: None,
cause: Some(self.source),
time,
crit: false,
instance,
},
}
}

View File

@ -152,6 +152,7 @@ pub enum BuffEffect {
rate: f32,
accumulated: f32,
kind: ModifierKind,
instance: u64,
},
/// Periodically consume entity energy
EnergyChangeOverTime {
@ -234,12 +235,14 @@ impl Buff {
) -> Self {
// Normalized nonlinear scaling
let nn_scaling = |a| a / (a + 0.5);
let instance = rand::random();
let (effects, time) = match kind {
BuffKind::Bleeding => (
vec![BuffEffect::HealthChangeOverTime {
rate: -data.strength,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
}],
data.duration,
),
@ -248,6 +251,7 @@ impl Buff {
rate: data.strength,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
}],
data.duration,
),
@ -256,6 +260,7 @@ impl Buff {
rate: data.strength,
accumulated: 0.0,
kind: ModifierKind::Fractional,
instance,
}],
data.duration,
),
@ -271,6 +276,7 @@ impl Buff {
rate: -1.0,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
},
],
data.duration,
@ -304,6 +310,7 @@ impl Buff {
rate: -data.strength,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
}],
data.duration,
),
@ -322,6 +329,7 @@ impl Buff {
rate: -data.strength * 4.0,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
},
],
data.duration,
@ -333,6 +341,7 @@ impl Buff {
rate: data.strength * 10.0,
accumulated: 0.0,
kind: ModifierKind::Additive,
instance,
},
],
data.duration,

View File

@ -24,6 +24,10 @@ pub struct HealthChange {
pub cause: Option<DamageSource>,
/// The time that the health change occurred at
pub time: Time,
/// A boolean that tells you if the change was a crit
pub crit: bool,
/// A random ID, used to group up health changes from the same attack
pub instance: u64,
}
impl HealthChange {
@ -132,7 +136,9 @@ impl Health {
amount: 0.0,
by: None,
cause: None,
crit: false,
time: Time(0.0),
instance: rand::random(),
},
is_dead: false,
damage_contributors: HashMap::new(),
@ -151,7 +157,8 @@ impl Health {
}
#[cfg(not(target_arch = "wasm32"))]
pub fn change_by(&mut self, change: HealthChange) {
/// Returns a boolean if the delta was not zero.
pub fn change_by(&mut self, change: HealthChange) -> bool {
let prev_health = i64::from(self.current);
self.current = (((self.current() + change.amount).clamp(0.0, f32::from(Self::MAX_HEALTH))
* Self::SCALING_FACTOR_FLOAT) as u32)
@ -179,6 +186,7 @@ impl Health {
(change.time.0 - last_damage_time.0) < DAMAGE_CONTRIB_PRUNE_SECS
});
}
delta != 0
}
pub fn damage_contributions(&self) -> impl Iterator<Item = (&DamageContributor, &u64)> {
@ -210,7 +218,9 @@ impl Health {
amount: 0.0,
by: None,
cause: None,
crit: false,
time: Time(0.0),
instance: rand::random(),
},
is_dead: false,
damage_contributors: HashMap::new(),
@ -244,6 +254,8 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);
@ -269,6 +281,8 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);
@ -288,6 +302,8 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);
health.change_by(health_change);
@ -313,6 +329,8 @@ mod tests {
time: Time(10.0),
by: Some(damage_contrib1),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);
@ -322,6 +340,8 @@ mod tests {
time: Time(100.0),
by: Some(damage_contrib2),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);
@ -335,6 +355,8 @@ mod tests {
time: Time(620.0),
by: Some(damage_contrib2),
cause: None,
crit: false,
instance: rand::random(),
};
health.change_by(health_change);

View File

@ -57,7 +57,7 @@ impl MeleeConstructor {
scaling the melee attack."
)
}
let instance = rand::random();
let attack = match self.kind {
Slash {
damage,
@ -80,6 +80,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
)
.with_effect(buff);
@ -128,6 +129,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
)
.with_effect(buff);
@ -170,6 +172,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
if let Some(damage_effect) = self.damage_effect {
@ -210,6 +213,7 @@ impl MeleeConstructor {
value: damage,
},
None,
instance,
)
.with_effect(lifesteal);
@ -244,6 +248,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
if let Some(damage_effect) = self.damage_effect {

View File

@ -99,6 +99,7 @@ impl ProjectileConstructor {
crit_mult: f32,
buff_strength: f32,
) -> Projectile {
let instance = rand::random();
use ProjectileConstructor::*;
match self {
Arrow {
@ -129,6 +130,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
)
.with_effect(buff);
let attack = Attack::default()
@ -169,6 +171,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
)
.with_effect(buff);
let attack = Attack::default()
@ -207,6 +210,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
@ -250,6 +254,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
@ -286,6 +291,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
@ -337,6 +343,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
@ -373,6 +380,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)
@ -424,6 +432,7 @@ impl ProjectileConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
let attack = Attack::default()
.with_damage(damage)

View File

@ -1,9 +1,18 @@
use crate::{comp, uid::Uid};
use crate::{combat::DamageContributor, comp, uid::Uid};
use comp::{beam, item::Reagent, poise::PoiseState, skillset::SkillGroupKind, UtteranceKind};
use hashbrown::HashSet;
use serde::{Deserialize, Serialize};
use vek::*;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct HealthChangeInfo {
pub amount: f32,
pub crit: bool,
pub target: Uid,
pub by: Option<DamageContributor>,
pub instance: u64,
}
/// An outcome represents the final result of an instantaneous event. It implies
/// that said event has already occurred. It is not a request for that event to
/// occur, nor is it something that may be cancelled or otherwise altered. Its
@ -58,8 +67,9 @@ pub enum Outcome {
pos: Vec3<f32>,
body: comp::Body,
},
Damage {
HealthChange {
pos: Vec3<f32>,
info: HealthChangeInfo,
},
Death {
pos: Vec3<f32>,
@ -96,7 +106,7 @@ impl Outcome {
| Outcome::Beam { pos, .. }
| Outcome::SkillPointGain { pos, .. }
| Outcome::SummonedCreature { pos, .. }
| Outcome::Damage { pos, .. }
| Outcome::HealthChange { pos, .. }
| Outcome::Death { pos, .. }
| Outcome::Block { pos, .. }
| Outcome::PoiseChange { pos, .. }

View File

@ -116,6 +116,7 @@ impl CharacterBehavior for Data {
value: self.static_data.damage,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
);
if let Some(effect) = self.static_data.damage_effect {
damage = damage.with_effect(effect);

View File

@ -264,6 +264,7 @@ impl CharacterBehavior for Data {
value: damage as f32,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
);
if let Some(effect) = self.static_data.stage_data[stage_index].damage_effect {
damage = damage.with_effect(effect);

View File

@ -96,6 +96,7 @@ impl CharacterBehavior for Data {
value: self.static_data.damage as f32,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
);
if let Some(effect) = self.static_data.damage_effect {
damage = damage.with_effect(effect);

View File

@ -241,6 +241,7 @@ impl<'a> System<'a> for Sys {
rate,
accumulated,
kind,
instance,
} => {
*accumulated += *rate * dt;
// Apply health change only once per second, per health, or
@ -248,7 +249,7 @@ impl<'a> System<'a> for Sys {
if accumulated.abs() > rate.abs().min(1.0)
|| buff.time.map_or(false, |dur| dur == Duration::default())
{
let (cause, by) = if *accumulated < 0.0 {
let (cause, by) = if *accumulated != 0.0 {
(Some(DamageSource::Buff(buff.kind)), buff_owner)
} else {
(None, None)
@ -274,6 +275,8 @@ impl<'a> System<'a> for Sys {
by: damage_contributor,
cause,
time: *read_data.time,
crit: false,
instance: *instance,
},
});
*accumulated = 0.0;

View File

@ -1056,7 +1056,9 @@ fn handle_health(
amount: hp - health.current(),
by: None,
cause: None,
crit: false,
time: *time,
instance: rand::random(),
};
health.change_by(change);
Ok(())

View File

@ -23,7 +23,7 @@ use common::{
Player, Poise, Pos, SkillSet, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
outcome::{HealthChangeInfo, Outcome},
resources::Time,
rtsim::RtSimEntity,
terrain::{Block, BlockKind, TerrainGrid},
@ -67,7 +67,26 @@ pub fn handle_poise(server: &Server, entity: EcsEntity, change: comp::PoiseChang
pub fn handle_health_change(server: &Server, entity: EcsEntity, change: HealthChange) {
let ecs = &server.state.ecs();
if let Some(mut health) = ecs.write_storage::<Health>().get_mut(entity) {
health.change_by(change);
// If the change amount was not zero
let changed = health.change_by(change);
if let (Some(pos), Some(uid)) = (
ecs.read_storage::<Pos>().get(entity),
ecs.read_storage::<Uid>().get(entity),
) {
if changed {
let outcomes = ecs.write_resource::<EventBus<Outcome>>();
outcomes.emit_now(Outcome::HealthChange {
pos: pos.0,
info: HealthChangeInfo {
amount: change.amount,
by: change.by,
target: *uid,
crit: change.crit,
instance: change.instance,
},
});
}
}
}
// This if statement filters out anything under 5 damage, for DOT ticks
// TODO: Find a better way to separate direct damage from DOT here
@ -573,10 +592,20 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
stats.get(entity),
&msm,
);
let change =
damage.calculate_health_change(damage_reduction, None, false, 0.0, 1.0, *time);
let change = damage.calculate_health_change(
damage_reduction,
None,
false,
0.0,
1.0,
*time,
rand::random(),
);
health.change_by(change);
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
server_eventbus.emit_now(ServerEvent::HealthChange { entity, change });
}
// Handle poise change
if let Some(mut poise) = ecs.write_storage::<comp::Poise>().get_mut(entity) {
let poise_damage = -(mass.0 * vel.magnitude_squared() / 1500.0);

View File

@ -159,6 +159,7 @@ impl StateExt for State {
0.0,
1.0,
*time,
rand::random(),
);
self.ecs()
.write_storage::<comp::Health>()

View File

@ -95,7 +95,7 @@ use common::{
item::{ItemDefinitionId, ItemKind, ToolKind},
object,
poise::PoiseState,
quadruped_low, quadruped_medium, quadruped_small, Body, CharacterAbilityType,
quadruped_low, quadruped_medium, quadruped_small, Body, CharacterAbilityType, Health,
InventoryUpdateEvent, UtteranceKind,
},
outcome::Outcome,
@ -514,9 +514,12 @@ impl SfxMgr {
false,
);
},
Outcome::Damage { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);
audio.emit_sfx(sfx_trigger_item, *pos, Some(1.5), false);
Outcome::HealthChange { pos, info, .. } => {
// Don't emit sound effects from positive damage (healing)
if info.amount < Health::HEALTH_EPSILON {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);
audio.emit_sfx(sfx_trigger_item, *pos, Some(1.5), false);
}
},
Outcome::Death { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Death);

View File

@ -1,4 +1,4 @@
use common::comp::Ori;
use common::{comp::Ori, outcome::HealthChangeInfo};
use specs::Component;
use specs_idvs::IdvStorage;
use vek::*;
@ -8,8 +8,9 @@ use vek::*;
#[derive(Copy, Clone, Debug)]
pub struct HpFloater {
pub timer: f32,
// Numbers of times significant damage has been dealt
pub hp_change: f32,
// Used for the "jumping" animation of the HpFloater whenever it changes it's value
pub jump_timer: f32,
pub info: HealthChangeInfo,
// Used for randomly offsetting
pub rand: f32,
}
@ -17,9 +18,7 @@ pub struct HpFloater {
pub struct HpFloaterList {
// Order oldest to newest
pub floaters: Vec<HpFloater>,
// Keep from spawning more floaters from same hp change
// Note: this can't detect a change if equivalent healing and damage take place simultaneously
pub last_hp: f32,
// The time since you last damaged this entity
// Used to display nametags outside normal range if this time is below a certain value
pub time_since_last_dmg_by_me: Option<f32>,

View File

@ -1,16 +1,15 @@
use crate::ecs::comp::{HpFloater, HpFloaterList};
use crate::ecs::comp::HpFloaterList;
use common::{
comp::{Health, Pos},
resources::{DeltaTime, PlayerEntity},
uid::Uid,
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
// How long floaters last (in seconds)
pub const HP_SHOWTIME: f32 = 3.0;
pub const CRIT_SHOWTIME: f32 = 0.7;
pub const MY_HP_SHOWTIME: f32 = 2.5;
pub const HP_ACCUMULATETIME: f32 = 1.0;
#[derive(Default)]
pub struct Sys;
@ -19,7 +18,6 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
Read<'a, PlayerEntity>,
Read<'a, DeltaTime>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Health>,
WriteStorage<'a, HpFloaterList>,
@ -32,88 +30,20 @@ impl<'a> System<'a> for Sys {
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
fn run(
_job: &mut Job<Self>,
(entities, my_entity, dt, uids, pos, healths, mut hp_floater_lists): Self::SystemData,
(entities, my_entity, dt, pos, healths, mut hp_floater_lists): Self::SystemData,
) {
// Add hp floater lists to all entities with health and a position
// Note: necessary in order to know last_hp
for (entity, last_hp) in (&entities, &healths, &pos, !&hp_floater_lists)
for entity in (&entities, &healths, &pos, !&hp_floater_lists)
.join()
.map(|(e, h, _, _)| (e, h.current()))
.map(|(e, _, _, _)| e)
.collect::<Vec<_>>()
{
let _ = hp_floater_lists.insert(entity, HpFloaterList {
floaters: Vec::new(),
last_hp,
time_since_last_dmg_by_me: None,
});
}
// Add hp floaters to all entities that have been damaged
let my_uid = my_entity.0.and_then(|entity| uids.get(entity));
for (entity, health, hp_floater_list) in (&entities, &healths, &mut hp_floater_lists).join()
{
// Increment timer for time since last damaged by me
hp_floater_list
.time_since_last_dmg_by_me
.as_mut()
.map(|t| *t += dt.0);
// Check if health has changed (won't work if damaged and then healed with
// equivalently in the same frame)
if (hp_floater_list.last_hp - health.current()).abs() > Health::HEALTH_EPSILON {
hp_floater_list.last_hp = health.current();
// TODO: What if multiple health changes occurred since last check here
// Also, If we make health store a vec of the last_changes (from say the last
// frame), what if the client receives the health component from
// two different server ticks at once, then one will be lost
// (tbf this is probably a rare occurance and the results
// would just be a transient glitch in the display of these damage numbers)
// (maybe health changes could be sent to the client as a list
// of events)
if match health.last_change.by.map(|x| x.uid()) {
// HealthSource::Damage { by: Some(by), .. }
// | HealthSource::Heal { by: Some(by) } => {
// let by_me = my_uid.map_or(false, |&uid| by == uid);
// // If the attack was by me also reset this timer
// if by_me {
// hp_floater_list.time_since_last_dmg_by_me = Some(0.0);
// }
// my_entity.0 == Some(entity) || by_me
// },
// HealthSource::Suicide => my_entity.0 == Some(entity),
// HealthSource::World => my_entity.0 == Some(entity),
// HealthSource::LevelUp => my_entity.0 == Some(entity),
// HealthSource::Command => true,
// HealthSource::Item => true,
// _ => false,
Some(by) => {
let by_me = my_uid.map_or(false, |&uid| by == uid);
// If the attack was by me also reset this timer
if by_me {
hp_floater_list.time_since_last_dmg_by_me = Some(0.0);
}
my_entity.0 == Some(entity) || by_me
},
None => false,
} {
let last_floater = hp_floater_list.floaters.last_mut();
match last_floater {
Some(f) if f.timer < HP_ACCUMULATETIME => {
//TODO: Add "jumping" animation on floater when it changes its value
f.hp_change += health.last_change.amount;
},
_ => {
hp_floater_list.floaters.push(HpFloater {
timer: 0.0,
hp_change: health.last_change.amount,
rand: rand::random(),
});
},
}
}
}
}
// Remove floater lists on entities without health or without position
for entity in (&entities, !&healths, &hp_floater_lists)
.join()
@ -131,30 +61,29 @@ impl<'a> System<'a> for Sys {
}
// Maintain existing floaters
for (
entity,
HpFloaterList {
ref mut floaters,
ref last_hp,
..
},
) in (&entities, &mut hp_floater_lists).join()
{
for mut floater in floaters.iter_mut() {
for (entity, hp_floater_list) in (&entities, &mut hp_floater_lists).join() {
// Increment timer for time since last damaged by me
hp_floater_list
.time_since_last_dmg_by_me
.as_mut()
.map(|t| *t += dt.0);
for mut floater in hp_floater_list.floaters.iter_mut() {
// Increment timer
floater.timer += dt.0;
floater.jump_timer += dt.0;
}
// Clear floaters if newest floater is past show time or health runs out
if floaters.last().map_or(false, |f| {
// Clear floaters if newest floater is past show time
if hp_floater_list.floaters.last().map_or(false, |f| {
f.timer
> if Some(entity) != my_entity.0 {
HP_SHOWTIME
} else {
MY_HP_SHOWTIME
}
|| last_hp.abs() < Health::HEALTH_EPSILON
}) {
floaters.clear();
hp_floater_list.floaters.clear();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -77,15 +77,16 @@ widget_ids! {
sct_title,
sct_show_text,
sct_show_radio,
sct_single_dmg_text,
sct_single_dmg_radio,
sct_show_batch_text,
sct_show_batch_radio,
sct_batched_dmg_radio,
sct_inc_dmg_text,
sct_inc_dmg_radio,
sct_batch_inc_text,
sct_batch_inc_radio,
sct_round_dmg_text,
sct_round_dmg_radio,
sct_dmg_accum_duration_slider,
sct_dmg_accum_duration_text,
sct_dmg_accum_duration_value,
sct_show_inc_dmg_text,
sct_show_inc_dmg_radio,
sct_inc_dmg_accum_duration_slider,
sct_inc_dmg_accum_duration_text,
sct_inc_dmg_accum_duration_value,
//
speech_bubble_text,
speech_bubble_self_text,
@ -94,6 +95,10 @@ widget_ids! {
speech_bubble_dark_mode_button,
speech_bubble_icon_text,
speech_bubble_icon_button,
//
experience_numbers_title,
accum_experience_text,
accum_experience_button,
}
}
@ -711,12 +716,12 @@ impl<'a> Widget for Interface<'a> {
/*Scrolling Combat text
O Show Damage Numbers
O Show single Damage Numbers
O Show batched dealt Damage
Damage Accumulation Duration:
[0s ----I----2s]
O Show incoming Damage
O Batch incoming Numbers
Number Display Duration: 1s ----I----5s
Incoming Damage Accumulation Duration:
[0s ----I----2s]
O Round Damage Numbers
*/
// SCT/ Scrolling Combat Text
Text::new(
@ -754,105 +759,152 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR)
.set(state.ids.sct_show_text, ui);
if self.global_state.settings.interface.sct {
// Toggle single damage numbers
let show_sct_damage_batch = !ToggleButton::new(
!self.global_state.settings.interface.sct_damage_batch,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_show_text, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.sct_single_dmg_radio, ui);
let sct_dmg_accum_duration =
self.global_state.settings.interface.sct_dmg_accum_duration;
let sct_inc_dmg_accum_duration = self
.global_state
.settings
.interface
.sct_inc_dmg_accum_duration;
Text::new(
self.localized_strings
.get("hud.settings.single_damage_number"),
.get("hud.settings.damage_accumulation_duration"),
)
.right_from(state.ids.sct_single_dmg_radio, 10.0)
.down_from(state.ids.sct_show_radio, 8.0)
.right_from(state.ids.sct_show_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_single_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_single_dmg_text, ui);
// Toggle Batched Damage
let show_sct_damage_batch = ToggleButton::new(
show_sct_damage_batch,
.set(state.ids.sct_dmg_accum_duration_text, ui);
if let Some(new_val) = ImageSlider::continuous(
sct_dmg_accum_duration,
0.0,
2.0,
self.imgs.slider_indicator,
self.imgs.slider,
)
.w_h(104.0, 22.0)
.down_from(state.ids.sct_dmg_accum_duration_text, 8.0)
.track_breadth(12.0)
.slider_length(10.0)
.pad_track((5.0, 5.0))
.set(state.ids.sct_dmg_accum_duration_slider, ui)
{
events.push(SctDamageAccumDuration(new_val));
}
Text::new(&format!("{:.2}", sct_dmg_accum_duration,))
.right_from(state.ids.sct_dmg_accum_duration_slider, 8.0)
.font_size(self.fonts.cyri.scale(14))
.graphics_for(state.ids.sct_dmg_accum_duration_slider)
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.sct_dmg_accum_duration_value, ui);
// Conditionally toggle incoming damage
let show_inc_dmg = ToggleButton::new(
self.global_state.settings.interface.sct_inc_dmg,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_single_dmg_radio, 8.0)
.down_from(state.ids.sct_dmg_accum_duration_slider, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.sct_show_batch_radio, ui);
.set(state.ids.sct_show_inc_dmg_radio, ui);
if self.global_state.settings.interface.sct_damage_batch != show_sct_damage_batch {
events.push(SctDamageBatch(
!self.global_state.settings.interface.sct_damage_batch,
if self.global_state.settings.interface.sct_inc_dmg != show_inc_dmg {
events.push(SctIncomingDamage(
!self.global_state.settings.interface.sct_inc_dmg,
))
}
Text::new(self.localized_strings.get("hud.settings.cumulated_damage"))
.right_from(state.ids.sct_show_batch_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_batched_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_show_batch_text, ui);
// Toggle Incoming Damage
let show_sct_player_batch = !ToggleButton::new(
!self.global_state.settings.interface.sct_player_batch,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_show_batch_radio, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.sct_inc_dmg_radio, ui);
Text::new(self.localized_strings.get("hud.settings.incoming_damage"))
.right_from(state.ids.sct_inc_dmg_radio, 10.0)
.right_from(state.ids.sct_show_inc_dmg_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_inc_dmg_radio)
.graphics_for(state.ids.sct_show_inc_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_inc_dmg_text, ui);
// Toggle Batched Incoming Damage
let show_sct_player_batch = ToggleButton::new(
show_sct_player_batch,
.set(state.ids.sct_show_inc_dmg_text, ui);
if self.global_state.settings.interface.sct_inc_dmg {
Text::new(
self.localized_strings
.get("hud.settings.incoming_damage_accumulation_duration"),
)
.down_from(state.ids.sct_show_inc_dmg_radio, 8.0)
.right_from(state.ids.sct_show_inc_dmg_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.sct_inc_dmg_accum_duration_text, ui);
if let Some(new_val) = ImageSlider::continuous(
sct_inc_dmg_accum_duration,
0.0,
2.0,
self.imgs.slider_indicator,
self.imgs.slider,
)
.w_h(104.0, 22.0)
.down_from(state.ids.sct_inc_dmg_accum_duration_text, 8.0)
.track_breadth(12.0)
.slider_length(10.0)
.pad_track((5.0, 5.0))
.set(state.ids.sct_inc_dmg_accum_duration_slider, ui)
{
events.push(SctIncomingDamageAccumDuration(new_val));
}
Text::new(&format!("{:.2}", sct_inc_dmg_accum_duration,))
.right_from(state.ids.sct_inc_dmg_accum_duration_slider, 8.0)
.font_size(self.fonts.cyri.scale(14))
.graphics_for(state.ids.sct_inc_dmg_accum_duration_slider)
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.sct_inc_dmg_accum_duration_value, ui);
}
// Round Damage
let show_sct_damage_rounding = ToggleButton::new(
self.global_state.settings.interface.sct_damage_rounding,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_inc_dmg_radio, 8.0)
.down_from(
if self.global_state.settings.interface.sct_inc_dmg {
state.ids.sct_inc_dmg_accum_duration_slider
} else {
state.ids.sct_show_inc_dmg_radio
},
8.0,
)
.x_align_to(state.ids.sct_show_inc_dmg_radio, Align::Start)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.sct_batch_inc_radio, ui);
.set(state.ids.sct_round_dmg_radio, ui);
if self.global_state.settings.interface.sct_player_batch != show_sct_player_batch {
events.push(SctPlayerBatch(
!self.global_state.settings.interface.sct_player_batch,
if self.global_state.settings.interface.sct_damage_rounding != show_sct_damage_rounding
{
events.push(SctRoundDamage(
!self.global_state.settings.interface.sct_damage_rounding,
))
}
Text::new(
self.localized_strings
.get("hud.settings.cumulated_incoming_damage"),
)
.right_from(state.ids.sct_batch_inc_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_batch_inc_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_batch_inc_text, ui);
Text::new(self.localized_strings.get("hud.settings.round_damage"))
.right_from(state.ids.sct_round_dmg_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_round_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_round_dmg_text, ui);
}
// Speech bubbles
Text::new(self.localized_strings.get("hud.settings.speech_bubble"))
.down_from(
if self.global_state.settings.interface.sct {
state.ids.sct_batch_inc_radio
state.ids.sct_round_dmg_radio
} else {
state.ids.sct_show_radio
},
@ -1062,6 +1114,46 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR)
.set(state.ids.always_show_bars_label, ui);
// Experience Numbers
Text::new(
self.localized_strings
.get("hud.settings.experience_numbers"),
)
.down_from(state.ids.always_show_bars_button, 20.0)
.font_size(self.fonts.cyri.scale(18))
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.experience_numbers_title, ui);
// Acuumulate Experience Gained
let accum_experience = ToggleButton::new(
self.global_state.settings.interface.accum_experience,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.experience_numbers_title, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.accum_experience_button, ui);
if self.global_state.settings.interface.accum_experience != accum_experience {
events.push(AccumExperience(
!self.global_state.settings.interface.accum_experience,
));
}
Text::new(
self.localized_strings
.get("hud.settings.accumulate_experience"),
)
.right_from(state.ids.accum_experience_button, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.accum_experience_button)
.color(TEXT_COLOR)
.set(state.ids.accum_experience_text, ui);
// Reset the interface settings to the default settings
if Button::image(self.imgs.button)
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)

View File

@ -284,7 +284,7 @@ impl ParticleMgr {
| Outcome::ExpChange { .. }
| Outcome::SkillPointGain { .. }
| Outcome::ComboChange { .. }
| Outcome::Damage { .. }
| Outcome::HealthChange { .. }
| Outcome::PoiseChange { .. }
| Outcome::Utterance { .. }
| Outcome::Glider { .. } => {},

View File

@ -1579,7 +1579,8 @@ impl PlayState for SessionState {
for outcome in outcomes {
self.scene
.handle_outcome(&outcome, &scene_data, &mut global_state.audio);
self.hud.handle_outcome(&outcome);
self.hud
.handle_outcome(&outcome, scene_data.client, global_state);
}
}
}

View File

@ -96,8 +96,10 @@ pub enum Graphics {
#[derive(Clone)]
pub enum Interface {
Sct(bool),
SctPlayerBatch(bool),
SctDamageBatch(bool),
SctRoundDamage(bool),
SctDamageAccumDuration(f32),
SctIncomingDamage(bool),
SctIncomingDamageAccumDuration(f32),
SpeechBubbleSelf(bool),
SpeechBubbleDarkMode(bool),
SpeechBubbleIcon(bool),
@ -134,6 +136,7 @@ pub enum Interface {
MapShowPeaks(bool),
MapShowBiomes(bool),
MapShowVoxelMap(bool),
AccumExperience(bool),
ResetInterfaceSettings,
}
@ -457,11 +460,17 @@ impl SettingsChange {
Interface::Sct(sct) => {
settings.interface.sct = sct;
},
Interface::SctPlayerBatch(sct_player_batch) => {
settings.interface.sct_player_batch = sct_player_batch;
Interface::SctRoundDamage(sct_round_damage) => {
settings.interface.sct_damage_rounding = sct_round_damage;
},
Interface::SctDamageBatch(sct_damage_batch) => {
settings.interface.sct_damage_batch = sct_damage_batch;
Interface::SctDamageAccumDuration(sct_dmg_accum_duration) => {
settings.interface.sct_dmg_accum_duration = sct_dmg_accum_duration;
},
Interface::SctIncomingDamage(sct_inc_dmg) => {
settings.interface.sct_inc_dmg = sct_inc_dmg;
},
Interface::SctIncomingDamageAccumDuration(sct_inc_dmg_accum_duration) => {
settings.interface.sct_inc_dmg_accum_duration = sct_inc_dmg_accum_duration;
},
Interface::SpeechBubbleSelf(sbdm) => {
settings.interface.speech_bubble_self = sbdm;
@ -559,6 +568,9 @@ impl SettingsChange {
Interface::MapShowVoxelMap(map_show_voxel_map) => {
settings.interface.map_show_voxel_map = map_show_voxel_map;
},
Interface::AccumExperience(accum_experience) => {
settings.interface.accum_experience = accum_experience;
},
Interface::ResetInterfaceSettings => {
// Reset Interface Settings
let tmp = settings.interface.intro_show;

View File

@ -15,8 +15,10 @@ pub struct InterfaceSettings {
pub toggle_chat: bool,
pub toggle_hotkey_hints: bool,
pub sct: bool,
pub sct_player_batch: bool,
pub sct_damage_batch: bool,
pub sct_damage_rounding: bool,
pub sct_dmg_accum_duration: f32,
pub sct_inc_dmg: bool,
pub sct_inc_dmg_accum_duration: f32,
pub speech_bubble_self: bool,
pub speech_bubble_dark_mode: bool,
pub speech_bubble_icon: bool,
@ -44,6 +46,7 @@ pub struct InterfaceSettings {
pub minimap_show: bool,
pub minimap_face_north: bool,
pub minimap_zoom: f64,
pub accum_experience: bool,
}
impl Default for InterfaceSettings {
@ -55,8 +58,10 @@ impl Default for InterfaceSettings {
toggle_chat: true,
toggle_hotkey_hints: true,
sct: true,
sct_player_batch: false,
sct_damage_batch: false,
sct_damage_rounding: false,
sct_dmg_accum_duration: 0.45,
sct_inc_dmg: true,
sct_inc_dmg_accum_duration: 0.45,
speech_bubble_self: true,
speech_bubble_dark_mode: false,
speech_bubble_icon: true,
@ -84,6 +89,7 @@ impl Default for InterfaceSettings {
minimap_show: true,
minimap_face_north: true,
minimap_zoom: 160.0,
accum_experience: true,
}
}
}