Refactored into modules.

This commit is contained in:
GreenComfyTea
2022-02-02 23:30:39 +02:00
parent 55c72dcc88
commit 2c4a3f4664
17 changed files with 5295 additions and 5001 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
local damage_hook = {};
local quest_status;
local player;
local enemy_character_base_type_def = sdk.find_type_definition("snow.enemy.EnemyCharacterBase");
local enemy_character_base_after_calc_damage_damage_side = enemy_character_base_type_def:get_method("afterCalcDamage_DamageSide");
sdk.hook(enemy_character_base_after_calc_damage_damage_side, function(args)
damage_hook.update_damage(args);
end, function(retval)
return retval;
end);
function damage_hook.update_damage(args)
local enemy = sdk.to_managed_object(args[2]);
if enemy == nil then
return;
end
local is_large_monster = enemy:call("get_isBossEnemy");
if is_large_monster == nil then
return;
end
local dead_or_captured = enemy:call("checkDie");
if dead_or_captured == nil then
return;
end
if dead_or_captured then
return;
end
local enemy_calc_damage_info = sdk.to_managed_object(args[3]); -- snow.hit.EnemyCalcDamageInfo.AfterCalcInfo_DamageSide
local attacker_id = enemy_calc_damage_info:call("get_AttackerID");
local attacker_type = enemy_calc_damage_info:call("get_DamageAttackerType");
if attacker_id >= 100 then
return;
end
-- 4 is virtual player in singleplayer that 'owns' 2nd otomo
if not quest_status.is_online and attacker_id == 4 then
attacker_id = player.myself.player_id;
end
local damage_object = {}
damage_object.total_damage = enemy_calc_damage_info:call("get_TotalDamage");
damage_object.physical_damage = enemy_calc_damage_info:call("get_PhysicalDamage");
damage_object.elemental_damage = enemy_calc_damage_info:call("get_ElementDamage");
damage_object.ailment_damage = enemy_calc_damage_info:call("get_ConditionDamage");
-- -1 - bombs
-- 0 - player
-- 9 - kunai
-- 11 - wyverblast
-- 12 - ballista
-- 13 - cannon
-- 14 - machine cannon
-- 16 - defender ballista/cannon
-- 17 - wyvernfire artillery
-- 18 - dragonator
-- 19 - otomo
-- 23 - monster
local damage_source_type = tostring(attacker_type);
if attacker_type == 0 then
damage_source_type = "player";
elseif attacker_type == 1 then
damage_source_type = "bomb";
elseif attacker_type == 9 then
damage_source_type = "kunai";
elseif attacker_type == 11 then
damage_source_type = "wyvernblast";
elseif attacker_type == 12 or attacker_type == 13 or attacker_type == 14 or attacker_type == 18 then
damage_source_type = "installation";
elseif attacker_type == 19 then
damage_source_type = "otomo";
elseif attacker_type == 23 then
damage_source_type = "monster";
end
local attacking_player = player.get_player(attacker_id);
if attacking_player == nil then
return;
end
player.update_damage(player.total, damage_source_type, is_large_monster, damage_object);
player.update_damage(attacking_player, damage_source_type, is_large_monster, damage_object);
end
function damage_hook.init_module()
quest_status = require("MHR_Overlay.Game_Handler.quest_status");
player = require("MHR_Overlay.Damage_Meter.player");
end
return damage_hook;

View File

@@ -0,0 +1,261 @@
local player = {};
local config = require("MHR_Overlay.Misc.config");
local table_helpers = require("MHR_Overlay.Misc.table_helpers");
local singletons = require("MHR_Overlay.Game_Handler.singletons");
local customization_menu = require("MHR_Overlay.UI.customization_menu");
player.list = {};
player.myself = nil;
player.myself_id = nil;
player.myself_position = Vector3f.new(0, 0, 0);
player.total = nil;
function player.new(player_id, player_name, player_hunter_rank)
local new_player = {};
new_player.id = player_id;
new_player.name = player_name;
new_player.hunter_rank = player_hunter_rank;
new_player.small_monsters = {};
new_player.small_monsters.total_damage = 0;
new_player.small_monsters.physical_damage = 0;
new_player.small_monsters.elemental_damage = 0;
new_player.small_monsters.ailment_damage = 0;
new_player.small_monsters.bombs = {};
new_player.small_monsters.bombs.total_damage = 0;
new_player.small_monsters.bombs.physical_damage = 0;
new_player.small_monsters.bombs.elemental_damage = 0;
new_player.small_monsters.bombs.ailment_damage = 0;
new_player.small_monsters.kunai = {};
new_player.small_monsters.kunai.total_damage = 0;
new_player.small_monsters.kunai.physical_damage = 0;
new_player.small_monsters.kunai.elemental_damage = 0;
new_player.small_monsters.kunai.ailment_damage = 0;
new_player.small_monsters.installations = {};
new_player.small_monsters.installations.total_damage = 0;
new_player.small_monsters.installations.physical_damage = 0;
new_player.small_monsters.installations.elemental_damage = 0;
new_player.small_monsters.installations.ailment_damage = 0;
new_player.small_monsters.otomo = {};
new_player.small_monsters.otomo.total_damage = 0;
new_player.small_monsters.otomo.physical_damage = 0;
new_player.small_monsters.otomo.elemental_damage = 0;
new_player.small_monsters.otomo.ailment_damage = 0;
new_player.small_monsters.monster = {};
new_player.small_monsters.monster.total_damage = 0;
new_player.small_monsters.monster.physical_damage = 0;
new_player.small_monsters.monster.elemental_damage = 0;
new_player.small_monsters.monster.ailment_damage = 0;
new_player.large_monsters = {};
new_player.large_monsters.total_damage = 0;
new_player.large_monsters.physical_damage = 0;
new_player.large_monsters.elemental_damage = 0;
new_player.large_monsters.ailment_damage = 0;
new_player.large_monsters.bombs = {};
new_player.large_monsters.bombs.total_damage = 0;
new_player.large_monsters.bombs.physical_damage = 0;
new_player.large_monsters.bombs.elemental_damage = 0;
new_player.large_monsters.bombs.ailment_damage = 0;
new_player.large_monsters.kunai = {};
new_player.large_monsters.kunai.total_damage = 0;
new_player.large_monsters.kunai.physical_damage = 0;
new_player.large_monsters.kunai.elemental_damage = 0;
new_player.large_monsters.kunai.ailment_damage = 0;
new_player.large_monsters.installations = {};
new_player.large_monsters.installations.total_damage = 0;
new_player.large_monsters.installations.physical_damage = 0;
new_player.large_monsters.installations.elemental_damage = 0;
new_player.large_monsters.installations.ailment_damage = 0;
new_player.large_monsters.otomo = {};
new_player.large_monsters.otomo.total_damage = 0;
new_player.large_monsters.otomo.physical_damage = 0;
new_player.large_monsters.otomo.elemental_damage = 0;
new_player.large_monsters.otomo.ailment_damage = 0;
new_player.large_monsters.monster = {};
new_player.large_monsters.monster.total_damage = 0;
new_player.large_monsters.monster.physical_damage = 0;
new_player.large_monsters.monster.elemental_damage = 0;
new_player.large_monsters.monster.ailment_damage = 0;
new_player.display = {};
new_player.display.total_damage = 0;
new_player.display.physical_damage = 0;
new_player.display.elemental_damage = 0;
new_player.display.ailment_damage = 0;
return new_player;
end
function player.get_player(player_id)
if player.list[player_id] == nil then
return nil;
end
return player.list[player_id];
end
function player.update_damage(_player, damage_source_type, is_large_monster, damage_object)
if _player == nil then
return;
end
local player_monster_type = _player.small_monsters;
if is_large_monster then
player_monster_type = _player.large_monsters;
end
if damage_source_type == "player" then
player.merge_damage(player_monster_type, damage_object);
elseif damage_source_type == "bomb" then
player.merge_damage(player_monster_type.bombs, damage_object);
elseif damage_source_type == "kunai" then
player.merge_damage(player_monster_type.kunai, damage_object);
elseif damage_source_type == "wyvernblast" then
player.merge_damage(player_monster_type, damage_object);
elseif damage_source_type == "installation" then
player.merge_damage(player_monster_type.installations, damage_object);
elseif damage_source_type == "otomo" then
player.merge_damage(player_monster_type.otomo, damage_object);
elseif damage_source_type == "monster" then
player.merge_damage(player_monster_type.monster, damage_object);
else
player.merge_damage(_player, damage_object);
end
player.update_display(_player);
end
function player.update_display(_player)
if _player == nil then
return;
end
_player.display.total_damage = 0;
_player.display.physical_damage = 0;
_player.display.elemental_damage = 0;
_player.display.ailment_damage = 0;
if config.current_config.damage_meter_UI.tracked_monster_types.small_monsters then
if config.current_config.damage_meter_UI.tracked_damage_types.player_damage then
player.merge_damage(_player.display, _player.small_monsters);
end
if config.current_config.damage_meter_UI.tracked_damage_types.bomb_damage then
player.merge_damage(_player.display, _player.small_monsters.bombs);
end
if config.current_config.damage_meter_UI.tracked_damage_types.kunai_damage then
player.merge_damage(_player.display, _player.small_monsters.kunai);
end
if config.current_config.damage_meter_UI.tracked_damage_types.installation_damage then
player.merge_damage(_player.display, _player.small_monsters.installations);
end
if config.current_config.damage_meter_UI.tracked_damage_types.otomo_damage then
player.merge_damage(_player.display, _player.small_monsters.otomo);
end
if config.current_config.damage_meter_UI.tracked_damage_types.monster_damage then
player.merge_damage(_player.display, _player.small_monsters.monster);
end
end
if config.current_config.damage_meter_UI.tracked_monster_types.large_monsters then
if config.current_config.damage_meter_UI.tracked_damage_types.player_damage then
player.merge_damage(_player.display, _player.large_monsters);
end
if config.current_config.damage_meter_UI.tracked_damage_types.bomb_damage then
player.merge_damage(_player.display, _player.large_monsters.bombs);
end
if config.current_config.damage_meter_UI.tracked_damage_types.kunai_damage then
player.merge_damage(_player.display, _player.large_monsters.kunai);
end
if config.current_config.damage_meter_UI.tracked_damage_types.installation_damage then
player.merge_damage(_player.display, _player.large_monsters.installations);
end
if config.current_config.damage_meter_UI.tracked_damage_types.otomo_damage then
player.merge_damage(_player.display, _player.large_monsters.otomo);
end
if config.current_config.damage_meter_UI.tracked_damage_types.monster_damage then
player.merge_damage(_player.display, _player.large_monsters.monster);
end
end
end
function player.merge_damage(first, second)
first.total_damage = first.total_damage + second.total_damage;
first.physical_damage = first.physical_damage + second.physical_damage;
first.elemental_damage = first.elemental_damage + second.elemental_damage;
first.ailment_damage = first.ailment_damage + second.ailment_damage;
return first;
end
function player.update_myself_position()
if singletons.player_manager == nil then
customization_menu.status = "No player manager";
return;
end
local master_player = singletons.player_manager:call("findMasterPlayer")
if master_player == nil then
customization_menu.status = "No master player";
return;
end
local master_player_game_object = master_player:call("get_GameObject")
if master_player_game_object == nil then
customization_menu.status = "No master player game object";
return;
end
local master_player_transform = master_player_game_object:call("get_Transform")
if not master_player_transform then
customization_menu.status = "No master player transform";
return;
end
local master_player_position = master_player_transform:call("get_Position")
if master_player_position == nil then
customization_menu.status = "No masterplayer position";
return;
end
player.myself_position = master_player_position;
end
function player.init_total()
player.total = player.new(0, "Total", 0);
end
function player.init_module()
config = require("MHR_Overlay.Misc.config");
table_helpers = require("MHR_Overlay.Misc.table_helpers");
singletons = require("MHR_Overlay.Game_Handler.singletons");
customization_menu = require("MHR_Overlay.UI.customization_menu");
player.init_total();
end
return player;

View File

@@ -0,0 +1,87 @@
local quest_status = {};
local singletons;
local customization_menu;
local player;
local small_monster;
local large_monster;
quest_status.index = 0;
quest_status.is_online = false;
quest_status.is_training_area = false;
local quest_manager_type_definition = sdk.find_type_definition("snow.QuestManager");
local on_changed_game_status = quest_manager_type_definition:get_method("onChangedGameStatus");
sdk.hook(on_changed_game_status, function(args)
local new_quest_status = sdk.to_int64(args[3]);
if new_quest_status ~= nil then
if (quest_status.index < 2 and new_quest_status == 2) or
new_quest_status < 2 then
player.list = {};
player.total = player.new(0, "Total", 0);
small_monster.list = {};
large_monster.list = {};
end
quest_status.index = new_quest_status;
end
end, function(retval)
return retval;
end);
function quest_status.init()
if singletons.quest_manager == nil then
return;
end
local new_quest_status = singletons.quest_manager:call("getStatus");
if new_quest_status == nil then
customization_menu.status = "No quest status";
return;
end
quest_status.index = new_quest_status;
quest_status.update_is_online();
quest_status.update_is_training_area();
end
function quest_status.update_is_online()
if singletons.lobby_manager == nil then
return;
end
local is_quest_online = singletons.lobby_manager:call("IsQuestOnline");
if is_quest_online == nil then
return;
end
quest_status.is_online = is_quest_online;
end
function quest_status.update_is_training_area()
if singletons.village_area_manager == nil then
customization_menu.status = "No village area manager";
return;
end
local _is_training_area = singletons.village_area_manager:call("checkCurrentArea_TrainingArea");
if _is_training_area == nil then
return;
end
quest_status.is_training_area = _is_training_area;
end
function quest_status.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
customization_menu = require("MHR_Overlay.UI.customization_menu");
player = require("MHR_Overlay.Damage_Meter.player");
small_monster = require("MHR_Overlay.Monsters.small_monster");
large_monster = require("MHR_Overlay.Monsters.large_monster");
quest_status.init();
end
return quest_status;

View File

@@ -0,0 +1,46 @@
local screen = {};
screen.width = 1920;
screen.height = 1080;
function screen.update_window_size()
local width, height = d2d.surface_size();
if width ~= nil then
screen.width = width;
end
if height ~= nil then
screen.height = height;
end
end
function screen.calculate_absolute_coordinates(position)
if position.anchor == "Top-Left" then
return {x = position.x, y = position.y};
end
if position.anchor == "Top-Right" then
local screen_x = screen.width - position.x;
return {x = screen_x, y = position.y};
end
if position.anchor == "Bottom-Left" then
local screen_y = screen.height - position.y;
return {x = position.x, y = screen_y};
end
if position.anchor == "Bottom-Right" then
local screen_x = screen.width - position.x;
local screen_y = screen.height - position.y;
return {x = screen_x, y = screen_y};
end
return {x = position.x, y = position.y};
end
function screen.init_module()
end
return screen;

View File

@@ -0,0 +1,118 @@
local singletons = {};
singletons.message_manager = nil;
singletons.enemy_manager = nil;
singletons.lobby_manager = nil;
singletons.progress_manager = nil;
singletons.quest_manager = nil;
singletons.player_manager = nil;
singletons.village_area_manager = nil;
function singletons.init()
singletons.init_message_manager();
singletons.init_enemy_manager();
singletons.init_lobby_manager()
singletons.init_progress_manager();
singletons.init_quest_manager();
singletons.init_player_manager();
singletons.init_village_area_manager();
end
function singletons.init_message_manager()
if singletons.message_manager ~= nil then
return;
end
singletons.message_manager = sdk.get_managed_singleton("snow.gui.MessageManager");
if singletons.message_manager == nil then
log.error("[MHR Overlay] No message manager");
end
return singletons.message_manager;
end
function singletons.init_enemy_manager()
if singletons.enemy_manager ~= nil then
return;
end
singletons.enemy_manager = sdk.get_managed_singleton("snow.enemy.EnemyManager");
if singletons.enemy_manager == nil then
log.error("[MHR Overlay] No enemy manager");
end
return singletons.enemy_manager;
end
function singletons.init_lobby_manager()
if singletons.lobby_manager ~= nil then
return;
end
singletons.lobby_manager = sdk.get_managed_singleton("snow.LobbyManager");
if singletons.lobby_manager == nil then
log.error("[MHR Overlay] No lobby manager");
return false;
end
return singletons.lobby_manager;
end
function singletons.init_progress_manager()
if singletons.progress_manager ~= nil then
return;
end
singletons.progress_manager = sdk.get_managed_singleton("snow.progress.ProgressManager");
if singletons.progress_manager == nil then
log.error("[MHR Overlay] No progress manager");
return false;
end
return singletons.progress_manager;
end
function singletons.init_quest_manager()
if singletons.quest_manager ~= nil then
return;
end
singletons.quest_manager = sdk.get_managed_singleton("snow.QuestManager");
if singletons.quest_manager == nil then
log.error("[MHR Overlay] No quest manager");
end
return singletons.quest_manager;
end
function singletons.init_player_manager()
if singletons.player_manager ~= nil then
return;
end
singletons.player_manager = sdk.get_managed_singleton("snow.player.PlayerManager");
if singletons.player_manager == nil then
log.error("[MHR Overlay] No player manager");
end
return singletons.player_manager;
end
function singletons.init_village_area_manager()
if singletons.village_area_manager ~= nil then
return;
end
singletons.village_area_manager = sdk.get_managed_singleton("snow.VillageAreaManager");
if singletons.village_area_manager == nil then
log.error("[MHR Overlay] No village manager");
end
return singletons.village_area_manager;
end
function singletons.init_module()
singletons.init();
end
return singletons;

812
MHR_Overlay/Misc/config.lua Normal file
View File

@@ -0,0 +1,812 @@
local config = {};
local table_helpers;
config.current_config = nil;
config.config_file_name = "MHR Overlay/config.json";
config.default_config = {
global_settings = {
module_visibility = {
during_quest = {
small_monster_UI = true,
large_monster_UI = true,
time_UI = true,
damage_meter_UI = true
},
quest_summary_Screen = {
time_UI = true,
damage_meter_UI = true
},
training_area = {
large_monster_UI = true,
damage_meter_UI = true
}
},
font = {
family = "Consolas",
size = 13,
bold = true,
italic = false
},
},
small_monster_UI = {
enabled = true,
spacing = {
x = 110,
y = 40
},
settings = {
orientation = "Horizontal"
},
dynamic_positioning = {
enabled = true,
max_distance = 300,
opacity_falloff = true,
world_offset = {
x = 0,
y = 3,
z = 0
},
viewport_offset = {
x = -50,
y = 0
}
},
sorting = {
type = "Normal",
reversed_order = false
},
position = {
x = 0,
y = 0,
anchor = "Top-Left"
},
monster_name_label = {
visibility = true,
text = "%s",
offset = {
x = 5,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
health = {
text_label = {
visibility = false,
text = "HP:",
offset = {
x = -25,
y = 12
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
value_label = {
visibility = true,
text = "%.0f/%.0f", -- current_health/max_health
offset = {
x = 50,
y = 25
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
percentage_label = {
visibility = false,
text = "%5.1f%%",
offset = {
x = 55,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
bar = {
visibility = true,
offset = {
x = 0,
y = 17
},
size = {
width = 100,
height = 7
},
colors = {
foreground = 0xB974A652,
background = 0xB9000000,
capture_health = 0xB9CCCC33
}
}
},
stamina = {
text_label = {
visibility = false,
text = "Stamina:",
offset = {
x = 15,
y = 37
},
color = 0xFFA3F5F0,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
value_label = {
visibility = false,
text = "%.0f/%.0f", -- current_health/max_health
offset = {
x = 15,
y = 54
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
percentage_label = {
visibility = false,
text = "%5.1f%%",
offset = {
x = 55,
y = 64
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
bar = {
visibility = false,
offset = {
x = 10,
y = 54
},
size = {
width = 90,
height = 4
},
colors = {
foreground = 0xB966CCC5,
background = 0x88000000
}
}
}
},
large_monster_UI = {
enabled = true,
spacing = {
x = 220,
y = 40,
},
settings = {
orientation = "Horizontal"
},
dynamic_positioning = {
enabled = true,
max_distance = 300,
opacity_falloff = true,
world_offset = {
x = 0,
y = 6,
z = 0
},
viewport_offset = {
x = -100,
y = 0
}
},
sorting = {
type = "Normal",
reversed_order = false
},
position = {
x = 525,
y = 125,--y = 44,
anchor = "Top-Left"
},
monster_name_label = {
visibility = true,
text = "%s",
include = {
monster_name = true,
crown = true,
size = true,
crown_thresholds = false
},
offset = {
x = 5,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
health = {
text_label = {
visibility = false,
text = "HP:",
offset = {
x = -25,
y = 19
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
value_label = {
visibility = true,
text = "%.0f/%.0f", -- current_health/max_health
offset = {
x = 5,
y = 19
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
percentage_label = {
visibility = true,
text = "%5.1f%%",
offset = {
x = 150,
y = 19
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
bar = {
visibility = true,
offset = {
x = 0,
y = 17
},
size = {
width = 200,
height = 20
},
colors = {
foreground = 0xB974A653,
background = 0xB9000000,
capture ={
foreground = 0xB9CCCC33,
background = 0x88000000
}
}
}
},
stamina = {
text_label = {
visibility = true,
text = "Stamina:",
offset = {
x = 15,
y = 37
},
color = 0xFFA3F5F0,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
value_label = {
visibility = true,
text = "%.0f/%.0f", -- current_health/max_health
offset = {
x = 55,
y = 54
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
percentage_label = {
visibility = true,
text = "%5.1f%%",
offset = {
x = 145,
y = 54
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
bar = {
visibility = true,
offset = {
x = 10,
y = 54
},
size = {
width = 185,
height = 7
},
colors = {
foreground = 0xB966CCC5,
background = 0x88000000
}
}
},
rage = {
text_label = {
visibility = true,
text = "Rage:",
offset = {
x = 15,
y = 61
},
color = 0xFFFF9393,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
value_label = {
visibility = true,
text = "%.0f/%.0f", -- current_health/max_health
offset = {
x = 55,
y = 78
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
percentage_label = {
visibility = true,
text = "%5.1f%%",
offset = {
x = 145,
y = 78
},
color = 0xFFFFFFFF,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
bar = {
visibility = true,
offset = {
x = 10,
y = 78
},
size = {
width = 185,
height = 7
},
colors = {
foreground = 0xB9CC6666,
background = 0x88000000
}
}
}
},
time_UI = {
enabled = true,
position = {
x = 65,
y = 189,
anchor = "Top-Left"
},
time_label = {
visibility = true,
text = "%02d:%06.3f",
offset = {
x = 0,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
}
},
damage_meter_UI = {
enabled = true,
tracked_monster_types = {
small_monsters = true,
large_monsters = true
},
tracked_damage_types = {
player_damage = true,
bomb_damage = true,
kunai_damage = true,
installation_damage = true, -- hunting_installations like ballista, cannon, etc.
otomo_damage = true,
monster_damage = true
}, -- note that installations during narwa fight are counted as monster damage
spacing = {
x = 270,
y = 24
},
settings = {
orientation = "Vertical", -- "Vertical" or "Horizontal"
hide_module_if_total_damage_is_zero = false,
hide_player_if_player_damage_is_zero = false,
total_damage_offset_is_relative = true,
highlighted_bar = "Me",
damage_bar_relative_to = "Top Damage", -- "total damage" or "top damage"
my_damage_bar_location = "First" -- "normal" or "first" or "last"
},
sorting = {
type = "Damage", -- "normal" or "damage"
reversed_order = false
},
position = {
x = 525,
y = 225,
-- Possible values: "Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right"
anchor = "Bottom-Left"
},
player_name_label = {
visibility = true,
include = {
myself = {
hunter_rank = true,
word_player = false,
player_id = false,
player_name = true
},
others = {
hunter_rank = true,
word_player = false,
player_id = false,
player_name = true
}
},
text = "%s",
offset = {
x = 5,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
damage_value_label = {
visibility = true,
text = "%.0f",
offset = {
x = 145,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
damage_percentage_label = {
visibility = true,
text = "%5.1f%%",
offset = {
x = 205,
y = 0
},
color = 0xFFCCF4E1,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
total_damage_label = {
visibility = true,
text = "Total Damage",
offset = {
x = 5,
y = 0
},
color = 0xFFFF7373,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
total_damage_value_label = {
visibility = true,
text = "%.0f",
offset = {
x = 145,
y = 0
},
color = 0xFFFF7373,
shadow = {
visibility = true,
offset = {
x = 1,
y = 1
},
color = 0xFF000000
}
},
damage_bar = {
visibility = true,
offset = {
x = 0,
y = 17
},
size = {
width = 250,
height = 5
},
colors = {
foreground = 0xA7CCA3F4,
background = 0xA7000000
}
},
highlighted_damage_bar = {
visibility = true,
offset = {
x = 0,
y = 17
},
size = {
width = 250,
height = 5
},
colors = {
foreground = 0xA7F4D5A3,
background = 0xA7000000
}
}
}
};
function config.load()
local loaded_config = json.load_file(config.config_file_name);
if loaded_config ~= nil then
log.info('[MHR Overlay] config.json loaded successfully');
config.current_config = table_helpers.merge(config.default_config, loaded_config);
else
log.error('[MHR Overlay] Failed to load config.json');
config.current_config = table_helpers.deep_copy(config.default_config);
end
end
function config.save()
-- save current config to disk, replacing any existing file
local success = json.dump_file(config.config_file_name, config.current_config);
if success then
log.info('[MHR Overlay] config.json saved successfully');
else
log.error('[MHR Overlay] Failed to save config.json');
end
end
function config.init_module()
table_helpers = require("MHR_Overlay.Misc.table_helpers");
config.load();
config.current_config.version = "v1.7";
end
return config;

View File

@@ -0,0 +1,146 @@
local table_helpers = {};
function table_helpers.deep_copy(original, copies)
copies = copies or {};
local original_type = type(original);
local copy;
if original_type == 'table' then
if copies[original] then
copy = copies[original];
else
copy = {};
copies[original] = copy;
for original_key, original_value in next, original, nil do
copy[table_helpers.deep_copy(original_key, copies)] = table_helpers.deep_copy(original_value, copies);
end
setmetatable(copy, table_helpers.deep_copy(getmetatable(original), copies));
end
else -- number, string, boolean, etc
copy = original;
end
return copy;
end
function table_helpers.find_index(table, value, nullable)
for i = 1, #table do
if table[i] == value then
return i;
end
end
if not nullable then
return 1;
end
return nil;
end
function table_helpers.merge(...)
local tables_to_merge = {...};
assert(#tables_to_merge > 1, "There should be at least two tables to merge them");
for key, table in ipairs(tables_to_merge) do
assert(type(table) == "table", string.format("Expected a table as function parameter %d", key));
end
local result = table_helpers.deep_copy(tables_to_merge[1]);
for i = 2, #tables_to_merge do
local from = tables_to_merge[i];
for key, value in pairs(from) do
if type(value) == "table" then
result[key] = result[key] or {};
assert(type(result[key]) == "table", string.format("Expected a table: '%s'", key));
result[key] = table_helpers.merge(result[key], value);
else
result[key] = value;
end
end
end
return result;
end
function table_helpers.tostring(table)
local cache, stack, output = {}, {}, {};
local depth = 1;
local output_string = "{\n";
while true do
local size = 0;
for key, value in pairs(table) do
size = size + 1;
end
local current_index = 1;
for key, value in pairs(table) do
if (cache[table] == nil) or (current_index >= cache[table]) then
if (string.find(output_string, "}", output_string:len())) then
output_string = output_string .. ",\n";
elseif not (string.find(output_string, "\n",output_string:len())) then
output_string = output_string .. "\n";
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output, output_string);
output_string = "";
local key;
if (type(key) == "number" or type(key) == "boolean") then
key = "[" .. tostring(key) .. "]";
else
key = "['" .. tostring(key) .. "']";
end
if (type(value) == "number" or type(value) == "boolean") then
output_string = output_string .. string.rep('\t', depth) .. key .. " = " .. tostring(value);
elseif (type(value) == "table") then
output_string = output_string .. string.rep('\t', depth) .. key .. " = {\n";
table.insert(stack, table);
table.insert(stack, value);
cache[table] = current_index + 1;
break
else
output_string = output_string .. string.rep('\t', depth) .. key .. " = '" .. tostring(value) .. "'";
end
if (current_index == size) then
output_string = output_string .. "\n" .. string.rep('\t', depth - 1) .. "}";
else
output_string = output_string .. ",";
end
else
-- close the table
if (current_index == size) then
output_string = output_string .. "\n" .. string.rep('\t', depth - 1) .. "}";
end
end
current_index = current_index + 1;
end
if (size == 0) then
output_string = output_string .. "\n" .. string.rep('\t', depth - 1) .. "}";
end
if (#stack > 0) then
table = stack[#stack];
stack[#stack] = nil;
depth = cache[table] == nil and depth + 1 or depth - 1;
else
break;
end
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output, output_string);
output_string = table.concat(output);
return output_string;
end
function table_helpers.init_module()
end
return table_helpers;

View File

@@ -0,0 +1,268 @@
local large_monster = {};
local singletons;
local customization_menu;
large_monster.list = {};
function large_monster.new(enemy)
local new_monster = {};
new_monster.is_large = true;
new_monster.health = 0;
new_monster.max_health = 999999;
new_monster.health_percentage = 0;
new_monster.missing_health = 0;
new_monster.capture_health = 0;
new_monster.stamina = 0;
new_monster.max_stamina = 1000;
new_monster.stamina_percentage = 0;
new_monster.missing_stamina = 0;
new_monster.is_in_rage = false;
new_monster.rage_point = 0;
new_monster.rage_limit = 2001;
new_monster.rage_timer = 0;
new_monster.rage_duration = 600;
new_monster.rage_count = 0;
new_monster.rage_percentage = 0;
new_monster.rage_total_seconds_left = 0;
new_monster.rage_minutes_left = 0;
new_monster.rage_seconds_left = 0;
new_monster.rage_timer_percentage = 0;
new_monster.position = Vector3f.new(0, 0, 0);
new_monster.name = "Large Monster";
new_monster.size = 1;
new_monster.small_border = 0;
new_monster.big_border = 5;
new_monster.king_border = 10;
new_monster.crown = "";
large_monster.init(new_monster, enemy);
if large_monster.list[enemy] == nil then
large_monster.list[enemy] = new_monster;
end
return new_monster;
end
function large_monster.get_monster(enemy)
if large_monster.list[enemy] == nil then
large_monster.list[enemy] = large_monster.new(enemy);
end
return large_monster.list[enemy];
end
function large_monster.init(monster, enemy)
local enemy_type = enemy:get_field("<EnemyType>k__BackingField");
if enemy_type == nil then
customization_menu.status = "No enemy type";
return;
end
local enemy_name = singletons.message_manager:call("getEnemyNameMessage", enemy_type);
if enemy_name ~= nil then
monster.name = enemy_name;
end
local size_info = singletons.enemy_manager:call("findEnemySizeInfo", enemy_type);
if size_info ~= nil then
local small_border = size_info:call("get_SmallBorder");
local big_border = size_info:call("get_BigBorder");
local king_border = size_info:call("get_KingBorder");
local size = enemy:call("get_MonsterListRegisterScale");
if small_border ~= nil then
monster.small_border = small_border;
end
if big_border ~= nil then
monster.big_border = big_border;
end
if king_border ~= nil then
monster.king_border = king_border;
end
if size ~= nil then
monster.size = size;
end
if monster.size <= monster.small_border then
monster.crown = "Mini";
elseif monster.size >= monster.king_border then
monster.crown = "Gold";
elseif monster.size >= monster.big_border then
monster.crown = "Silver";
end
end
end
function large_monster.update(enemy)
if enemy == nil then
return;
end
local physical_param = enemy:get_field("<PhysicalParam>k__BackingField");
if physical_param == nil then
customization_menu.status = "No physical param";
return;
end
local status_param = enemy:get_field("<StatusParam>k__BackingField");
if status_param == nil then
customization_menu.status = "No status param";
return;
end
local anger_param = enemy:get_field("<AngerParam>k__BackingField");
if anger_param == nil then
customization_menu.status = "No anger param";
return;
end
local stamina_param = enemy:get_field("<StaminaParam>k__BackingField");
if stamina_param == nil then
customization_menu.status = "No stamina param";
return;
end
local vital_param = physical_param:call("getVital", 0, 0);
if vital_param == nil then
customization_menu.status = "No vital param";
return;
end
local health = vital_param:call("get_Current");
local max_health = vital_param:call("get_Max");
local capture_health = physical_param:call("get_CaptureHpVital");
local stamina = stamina_param:call("getStamina");
local max_stamina = stamina_param:call("getMaxStamina");
local is_in_rage = anger_param:call("isAnger");
local rage_point = anger_param:call("get_AngerPoint");
local rage_limit = anger_param:call("get_LimitAnger");
local rage_timer = anger_param:call("get_Timer");
local rage_duration = anger_param:call("get_TimerAnger");
local rage_count = anger_param:call("get_CountAnger");
local enemy_game_object = enemy:call("get_GameObject");
if enemy_game_object == nil then
customization_menu.status = "No enemy game object";
return;
end
local enemy_transform = enemy_game_object:call("get_Transform");
if enemy_transform == nil then
customization_menu.status = "No enemy transform";
return;
end
local position = enemy_transform:call("get_Position");
if not position then
customization_menu.status = "No enemy position";
return;
end
local monster = large_monster.get_monster(enemy);
if health ~= nil then
monster.health = health;
end
if max_health ~= nil then
monster.max_health = max_health;
end
if capture_health ~= nil then
monster.capture_health = capture_health;
end
if max_health ~= nil and health ~= nil then
monster.missing_health = max_health - health;
if max_health ~= 0 then
monster.health_percentage = health / max_health;
end
end
if position ~= nil then
monster.position = position;
end
if stamina ~= nil then
monster.stamina = stamina;
end
if max_stamina ~= nil then
monster.max_stamina = max_stamina;
end
if max_stamina ~= nil and stamina ~= nil then
monster.missing_stamina = max_stamina - stamina;
if max_stamina ~= 0 then
monster.stamina_percentage = stamina / max_stamina;
end
end
if is_in_rage ~= nil then
monster.is_in_rage = is_in_rage;
end
if rage_point ~= nil then
monster.rage_point = rage_point;
end
if rage_limit ~= nil then
monster.rage_limit = rage_limit;
end
if rage_point ~= nil and rage_limit ~= nil then
if rage_limit ~= 0 then
monster.rage_percentage = rage_point / rage_limit;
end
end
if rage_timer ~= nil then
monster.rage_timer = rage_timer;
end
if rage_duration ~= nil then
monster.rage_duration = rage_duration;
end
if rage_timer ~= nil and rage_duration ~= nil and monster.is_in_rage then
monster.rage_total_seconds_left = rage_duration - rage_timer;
if monster.rage_total_seconds_left < 0 then
monster.rage_total_seconds_left = 0;
end
monster.rage_minutes_left = math.floor(monster.rage_total_seconds_left / 60);
monster.rage_seconds_left = monster.rage_total_seconds_left - 60 * monster.rage_minutes_left;
if rage_duration ~= 0 then
monster.rage_timer_percentage = monster.rage_total_seconds_left / rage_duration;
end
end
if rage_count ~= nil then
monster.rage_count = rage_count;
end
end
function large_monster.init_list()
large_monster.list = {};
end
function large_monster.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
customization_menu = require("MHR_Overlay.UI.customization_menu");
end
return large_monster;

View File

@@ -0,0 +1,37 @@
local monster = {};
local small_monster;
local large_monster;
local enemy_character_base_type_def = sdk.find_type_definition("snow.enemy.EnemyCharacterBase");
local enemy_character_base_type_def_update_method = enemy_character_base_type_def:get_method("update");
sdk.hook(enemy_character_base_type_def_update_method, function(args)
monster.update_monster(sdk.to_managed_object(args[2]));
end, function(retval)
return retval;
end);
function monster.update_monster(enemy)
if enemy == nil then
return;
end
local is_large = enemy:call("get_isBossEnemy");
if is_large == nil then
return;
end
if is_large then
large_monster.update(enemy);
else
small_monster.update(enemy);
end
end
function monster.init_module()
small_monster = require("MHR_Overlay.Monsters.small_monster");
large_monster = require("MHR_Overlay.Monsters.large_monster");
end
return monster;

View File

@@ -0,0 +1,159 @@
local small_monster = {};
local singletons;
local customization_menu;
small_monster.list = {};
function small_monster.new(enemy)
local new_monster = {};
new_monster.is_large = false;
new_monster.health = 0;
new_monster.max_health = 999999;
new_monster.health_percentage = 0;
new_monster.missing_health = 0;
new_monster.capture_health = 0;
new_monster.stamina = 0;
new_monster.max_stamina = 1000;
new_monster.stamina_percentage = 0;
new_monster.missing_stamina = 0;
new_monster.position = Vector3f.new(0, 0, 0);
new_monster.name = "Small Monster";
small_monster.init(new_monster, enemy);
if small_monster.list[enemy] == nil then
small_monster.list[enemy] = new_monster;
end
return new_monster;
end
function small_monster.get_monster(enemy)
if small_monster.list[enemy] == nil then
small_monster.list[enemy] = small_monster.new(enemy);
end
return small_monster.list[enemy];
end
function small_monster.init(monster, enemy)
local enemy_type = enemy:get_field("<EnemyType>k__BackingField");
if enemy_type == nil then
customization_menu.status = "No enemy type";
return;
end
local enemy_name = singletons.message_manager:call("getEnemyNameMessage", enemy_type);
if enemy_name ~= nil then
monster.name = enemy_name;
end
end
function small_monster.update(enemy)
if enemy == nil then
return;
end
local physical_param = enemy:get_field("<PhysicalParam>k__BackingField");
if physical_param == nil then
customization_menu.status = "No physical param";
return;
end
local status_param = enemy:get_field("<StatusParam>k__BackingField");
if status_param == nil then
customization_menu.status = "No status param";
return;
end
local stamina_param = enemy:get_field("<StaminaParam>k__BackingField");
if stamina_param == nil then
customization_menu.status = "No stamina param";
return;
end
local vital_param = physical_param:call("getVital", 0, 0);
if vital_param == nil then
customization_menu.status = "No vital param";
return;
end
local health = vital_param:call("get_Current");
local max_health = vital_param:call("get_Max");
local capture_health = physical_param:call("get_CaptureHpVital");
local stamina = stamina_param:call("getStamina");
local max_stamina = stamina_param:call("getMaxStamina");
local enemy_game_object = enemy:call("get_GameObject");
if enemy_game_object == nil then
customization_menu.status = "No enemy game object";
return;
end
local enemy_transform = enemy_game_object:call("get_Transform");
if enemy_transform == nil then
customization_menu.status = "No enemy transform";
return;
end
local position = enemy_transform:call("get_Position");
if not position then
customization_menu.status = "No enemy position";
return;
end
local monster = small_monster.get_monster(enemy);
if health ~= nil then
monster.health = health;
end
if max_health ~= nil then
monster.max_health = max_health;
end
if capture_health ~= nil then
monster.capture_health = capture_health;
end
if max_health ~= nil and health ~= nil then
monster.missing_health = max_health - health;
if max_health ~= 0 then
monster.health_percentage = health / max_health;
end
end
if position ~= nil then
monster.position = position;
end
if stamina ~= nil then
monster.stamina = stamina;
end
if max_stamina ~= nil then
monster.max_stamina = max_stamina;
end
if max_stamina ~= nil and stamina ~= nil then
monster.missing_stamina = max_stamina - stamina;
if max_stamina ~= 0 then
monster.stamina_percentage = stamina / max_stamina;
end
end
end
function small_monster.init_list()
small_monster.list = {};
end
function small_monster.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
customization_menu = require("MHR_Overlay.UI.customization_menu");
end
return small_monster;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
local damage_meter_UI = {};
local singletons;
local config;
local customization_menu;
local player;
local quest_status;
local screen;
local drawing;
damage_meter_UI.last_displayed_players = {};
function damage_meter_UI.draw()
if player.total.display.total_damage == 0 and config.current_config.damage_meter_UI.settings.hide_module_if_total_damage_is_zero then
return;
end
if singletons.lobby_manager == nil then
return;
end
if singletons.progress_manager == nil then
return;
end
-- myself player
local myself_player_info = singletons.lobby_manager:get_field("_myHunterInfo");
if myself_player_info == nil then
customization_menu.status = "No myself player info list";
return;
end
local myself_player_name = myself_player_info:get_field("_name");
if myself_player_name == nil then
customization_menu.status = "No myself player name";
return;
end
if quest_status.is_online then
player.myself_id = singletons.lobby_manager:get_field("_myselfQuestIndex");
if player.myself_id == nil then
customization_menu.status = "No myself player id";
return;
end
else
player.myself_id = singletons.lobby_manager:get_field("_myselfIndex");
if player.myself_id == nil then
customization_menu.status = "No myself player id";
return;
end
end
local myself_hunter_rank = singletons.progress_manager:call("get_HunterRank");
if myself_hunter_rank == nil then
customization_menu.status = "No myself hunter rank";
myself_hunter_rank = 0;
end
if player.list[player.myself_id] == nil then
player.list[player.myself_id] = player.new(player.myself_id, myself_player_name, myself_hunter_rank);
player.myself = player.list[player.myself_id];
end
local quest_players = {};
if quest_status.index > 2 then
quest_players = damage_meter_UI.last_displayed_players;
else
-- other players
local player_info_list = singletons.lobby_manager:get_field("_questHunterInfo");
if player_info_list == nil then
customization_menu.status = "No player info list";
end
local count = player_info_list:call("get_Count");
if count == nil then
customization_menu.status = "No player info list count";
return;
end
for i = 0, count - 1 do
local player_info = player_info_list:call("get_Item", i);
if player_info == nil then
goto continue
end
local player_id = player_info:get_field("_memberIndex");
if player_id == nil then
goto continue
end
local player_hunter_rank = player_info:get_field("_hunterRank");
if player_hunter_rank == nil then
goto continue
end
if player_id == player.myself_id and config.current_config.damage_meter_UI.settings.my_damage_bar_location ~= "Normal" then
player.list[player.myself_id].hunter_rank = player_hunter_rank;
goto continue
end
local player_name = player_info:get_field("_name");
if player_name == nil then
goto continue
end
if player.list[player_id] == nil then
player.list[player_id] = player.new(player_id, player_name, player_hunter_rank);
elseif player.list[player_id].name ~= player_name then
player.list[player_id] = player.new(player_id, player_name, player_hunter_rank);
end
table.insert(quest_players, player.list[player_id]);
::continue::
end
-- sort here
if config.current_config.damage_meter_UI.sorting.type == "Normal" and config.current_config.damage_meter_UI.sorting.reversed_order then
local reversed_quest_players = {};
for i = #quest_players, 1, -1 do
table.insert(reversed_quest_players, quest_players[i]);
end
quest_players = reversed_quest_players;
elseif config.current_config.damage_meter_UI.sorting.type == "Damage" then
if config.current_config.damage_meter_UI.sorting.reversed_order then
table.sort(quest_players, function(left, right)
return left.display.total_damage < right.display.total_damage;
end);
else
table.sort(quest_players, function(left, right)
return left.display.total_damage > right.display.total_damage;
end);
end
end
if config.current_config.damage_meter_UI.settings.my_damage_bar_location == "First" then
table.insert(quest_players, 1, player.list[player.myself_id]);
elseif config.current_config.damage_meter_UI.settings.my_damage_bar_location == "Last" then
table.insert(quest_players, #quest_players + 1, player.list[player.myself_id]);
elseif #quest_players == 0 then
table.insert(quest_players, 1, player.list[player.myself_id]);
end
damage_meter_UI.last_displayed_players = quest_players;
end
local top_damage = 0;
for _, _player in ipairs(quest_players) do
if _player.display.total_damage > top_damage then
top_damage = _player.display.total_damage;
end
end
-- draw
local position_on_screen = screen.calculate_absolute_coordinates(config.current_config.damage_meter_UI.position);
for _, _player in ipairs(quest_players) do
if _player.display.total_damage == 0 and config.current_config.damage_meter_UI.settings.hide_player_if_player_damage_is_zero then
goto continue1
end
local player_damage_percentage = 0;
if player.total.display.total_damage ~= 0 then
player_damage_percentage = _player.display.total_damage / player.total.display.total_damage;
end
local player_damage_bar_percentage = 0;
if config.current_config.damage_meter_UI.settings.damage_bar_relative_to == "Total Damage" then
if player.total.display.total_damage ~= 0 then
player_damage_bar_percentage = _player.display.total_damage / player.total.display.total_damage;
end
else
if top_damage ~= 0 then
player_damage_bar_percentage = _player.display.total_damage / top_damage;
end
end
if _player.id == player.myself_id and config.current_config.damage_meter_UI.settings.highlighted_bar == "Me" then
drawing.draw_bar(config.current_config.damage_meter_UI.highlighted_damage_bar, position_on_screen, player_damage_bar_percentage);
elseif config.current_config.damage_meter_UI.settings.highlighted_bar == "Top Damage" and _player.display.total_damage == top_damage then
drawing.draw_bar(config.current_config.damage_meter_UI.highlighted_damage_bar, position_on_screen, player_damage_bar_percentage);
else
drawing.draw_bar(config.current_config.damage_meter_UI.damage_bar, position_on_screen, player_damage_bar_percentage);
end
local player_include = config.current_config.damage_meter_UI.player_name_label.include.others;
if _player.id == player.myself_id then
player_include = config.current_config.damage_meter_UI.player_name_label.include.myself;
end
local player_name_text = "";
if player_include.hunter_rank then
player_name_text = string.format("[%d] ", _player.hunter_rank);
end
if player_include.word_player then
player_name_text = player_name_text .. "Player ";
end
if player_include.player_id then
player_name_text = player_name_text .. string.format("%d ", _player.id);
end
if player_include.player_name then
player_name_text = player_name_text .. _player.name;
end
drawing.draw_label(config.current_config.damage_meter_UI.player_name_label, position_on_screen, player_name_text);
drawing.draw_label(config.current_config.damage_meter_UI.damage_value_label, position_on_screen, _player.display.total_damage);
drawing.draw_label(config.current_config.damage_meter_UI.damage_percentage_label, position_on_screen, 100 * player_damage_percentage);
if config.current_config.damage_meter_UI.settings.orientation == "Horizontal" then
position_on_screen.x = position_on_screen.x + config.current_config.damage_meter_UI.spacing.x;
else
position_on_screen.y = position_on_screen.y + config.current_config.damage_meter_UI.spacing.y;
end
::continue1::
end
-- draw total damage
if not config.current_config.damage_meter_UI.settings.total_damage_offset_is_relative then
position_on_screen = screen.calculate_absolute_coordinates(config.current_config.damage_meter_UI.position);
end
drawing.draw_label(config.current_config.damage_meter_UI.total_damage_label, position_on_screen);
drawing.draw_label(config.current_config.damage_meter_UI.total_damage_value_label, position_on_screen, player.total.display.total_damage);
end
function damage_meter_UI.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
config = require("MHR_Overlay.Misc.config");
customization_menu = require("MHR_Overlay.UI.customization_menu");
player = require("MHR_Overlay.Damage_Meter.player");
quest_status = require("MHR_Overlay.Game_Handler.quest_status");
screen = require("MHR_Overlay.Game_Handler.screen");
drawing = require("MHR_Overlay.UI.drawing");
end
return damage_meter_UI;

100
MHR_Overlay/UI/drawing.lua Normal file
View File

@@ -0,0 +1,100 @@
local drawing = {};
local config;
drawing.font = nil;
function drawing.init_font()
drawing.font = d2d.create_font(config.current_config.global_settings.font.family, config.current_config.global_settings.font.size, config.current_config.global_settings.font.bold, config.current_config.global_settings.font.italic);
end
function drawing.color_to_argb(color)
local alpha = (color >> 24) & 0xFF;
local red = (color >> 16) & 0xFF;
local green = (color >> 8) & 0xFF;
local blue = color & 0xFF;
return alpha, red, green, blue;
end
function drawing.argb_to_color(alpha, red, green, blue)
return 0x1000000 * alpha + 0x10000 * red + 0x100 * green + blue;
end
function drawing.scale_color_opacity(color, scale)
local alpha, red, green, blue = drawing.color_to_argb(color);
local new_alpha = math.floor(alpha * scale);
if new_alpha < 0 then new_alpha = 0; end
if new_alpha > 255 then new_alpha = 255; end
return drawing.argb_to_color(new_alpha, red, green, blue);
end
function drawing.scale_bar_opacity(bar, scale)
if bar == nil or scale == nil then
return;
end
if not bar.visibility then
return;
end
bar.colors.foreground = drawing.scale_color_opacity(bar.colors.foreground, scale);
bar.colors.background = drawing.scale_color_opacity(bar.colors.background, scale);
end
function drawing.scale_label_opacity(label, scale)
if label == nil or scale == nil then
return;
end
if not label.visibility then
return;
end
label.color = drawing.scale_color_opacity(label.color, scale);
label.shadow.color = drawing.scale_color_opacity(label.shadow.color, scale);
end
function drawing.draw_label(label, position, ...)
if label == nil or not label.visibility then
return;
end
local text = string.format(label.text, table.unpack({...}));
if label.shadow.visibility then
d2d.text(drawing.font, text, position.x + label.offset.x + label.shadow.offset.x,
position.y + label.offset.y + label.shadow.offset.y, label.shadow.color);
end
d2d.text(drawing.font, text, position.x + label.offset.x, position.y + label.offset.y, label.color);
end
function drawing.draw_bar(bar, position, percentage)
if bar == nil then
return;
end
if not bar.visibility then
return;
end
if percentage > 1 then
percentage = 1;
end
local foreground_width = bar.size.width * percentage;
local background_width = bar.size.width - foreground_width;
-- foreground
d2d.fill_rect(position.x + bar.offset.x, position.y + bar.offset.y, foreground_width, bar.size.height,
bar.colors.foreground);
-- background
d2d.fill_rect(position.x + foreground_width + bar.offset.x, position.y + bar.offset.y, background_width,
bar.size.height, bar.colors.background);
end
function drawing.init_module()
config = require("MHR_Overlay.Misc.config");
end
return drawing;

View File

@@ -0,0 +1,238 @@
local large_monster_UI = {};
local singletons;
local config;
local customization_menu;
local large_monster;
local screen;
local player;
local drawing;
local table_helpers;
function large_monster_UI.draw()
if singletons.enemy_manager == nil then
return;
end
local displayed_monsters = {};
local enemy_count = singletons.enemy_manager:call("getBossEnemyCount");
if enemy_count == nil then
return;
end
for i = 0, enemy_count - 1 do
local enemy = singletons.enemy_manager:call("getBossEnemy", i);
if enemy == nil then
customization_menu.status = "No enemy";
break
end
local monster = large_monster.list[enemy];
if monster == nil then
customization_menu.status = "No monster hp entry";
break
end
table.insert(displayed_monsters, monster);
end
if not config.current_config.large_monster_UI.dynamic_positioning.enabled then
-- sort here
if config.current_config.large_monster_UI.sorting.type == "Normal" and config.current_config.large_monster_UI.sorting.reversed_order then
local reversed_monsters = {};
for i = #displayed_monsters, 1, -1 do
table.insert(reversed_monsters, displayed_monsters[i]);
end
displayed_monsters = reversed_monsters;
elseif config.current_config.large_monster_UI.sorting.type == "Health" then
if config.current_config.large_monster_UI.sorting.reversed_order then
table.sort(displayed_monsters, function(left, right)
return left.health > right.health;
end);
else
table.sort(displayed_monsters, function(left, right)
return left.health < right.health;
end);
end
elseif config.current_config.large_monster_UI.sorting.type == "Health Percentage" then
if config.current_config.large_monster_UI.sorting.reversed_order then
table.sort(displayed_monsters, function(left, right)
return left.health_percentage > right.health_percentage;
end);
else
table.sort(displayed_monsters, function(left, right)
return left.health_percentage < right.health_percentage;
end);
end
end
end
local i = 0;
for _, monster in ipairs(displayed_monsters) do
local position_on_screen;
if config.current_config.large_monster_UI.dynamic_positioning.enabled then
local world_offset = Vector3f.new(config.current_config.large_monster_UI.dynamic_positioning.world_offset.x, config.current_config.large_monster_UI.dynamic_positioning.world_offset.y, config.current_config.large_monster_UI.dynamic_positioning.world_offset.z);
position_on_screen = draw.world_to_screen(monster.position + world_offset);
if position_on_screen == nil then
goto continue
end
position_on_screen.x = position_on_screen.x + config.current_config.large_monster_UI.dynamic_positioning.viewport_offset.x;
position_on_screen.y = position_on_screen.y + config.current_config.large_monster_UI.dynamic_positioning.viewport_offset.y;
else
position_on_screen = screen.calculate_absolute_coordinates(config.current_config.large_monster_UI.position);
if config.current_config.large_monster_UI.settings.orientation == "Horizontal" then
position_on_screen.x = position_on_screen.x + config.current_config.large_monster_UI.spacing.x * i;
else
position_on_screen.y = position_on_screen.y + config.current_config.large_monster_UI.spacing.y * i;
end
end
local monster_name_label = config.current_config.large_monster_UI.monster_name_label;
local health_bar = table_helpers.deep_copy(config.current_config.large_monster_UI.health.bar);
local health_label = config.current_config.large_monster_UI.health.text_label;
local health_value_label = config.current_config.large_monster_UI.health.value_label;
local health_percentage_label = config.current_config.large_monster_UI.health.percentage_label;
local stamina_bar = config.current_config.large_monster_UI.stamina.bar;
local stamina_label = config.current_config.large_monster_UI.stamina.text_label;
local stamina_value_label = config.current_config.large_monster_UI.stamina.value_label;
local stamina_percentage_label = config.current_config.large_monster_UI.stamina.percentage_label;
local rage_bar = config.current_config.large_monster_UI.rage.bar;
local rage_label = config.current_config.large_monster_UI.rage.text_label;
local rage_value_label = table_helpers.deep_copy(config.current_config.large_monster_UI.rage.value_label);
local rage_percentage_label = table_helpers.deep_copy(config.current_config.large_monster_UI.rage.percentage_label);
if monster.health <= monster.capture_health then
health_bar.colors = health_bar.colors.capture;
end
local monster_name_text = "";
if config.current_config.large_monster_UI.monster_name_label.include.monster_name then
monster_name_text = string.format("%s ", monster.name);
end
if config.current_config.large_monster_UI.monster_name_label.include.crown and monster.crown ~= "" then
monster_name_text = monster_name_text .. string.format("%s ", monster.crown);
end
if config.current_config.large_monster_UI.monster_name_label.include.size then
monster_name_text = monster_name_text .. string.format("#%.0f ", 100 * monster.size);
end
if config.current_config.large_monster_UI.monster_name_label.include.scrown_thresholds then
monster_name_text = monster_name_text .. string.format("<=%.0f >=%.0f >=%.0f", 100 * monster.small_border,
100 * monster.big_border, 100 * monster.king_border);
end
local rage_bar_percentage = monster.rage_percentage;
if monster.is_in_rage then
rage_bar_percentage = monster.rage_timer_percentage;
end
if config.current_config.large_monster_UI.dynamic_positioning.enabled then
if config.current_config.large_monster_UI.dynamic_positioning.max_distance == 0 then
return;
end
local distance = (player.myself_position - monster.position):length();
if distance > config.current_config.large_monster_UI.dynamic_positioning.max_distance then
goto continue;
end
if config.current_config.large_monster_UI.dynamic_positioning.opacity_falloff then
local opacity_falloff = 1 - (distance / config.current_config.large_monster_UI.dynamic_positioning.max_distance);
monster_name_label = table_helpers.deep_copy(config.current_config.large_monster_UI.monster_name_label);
health_label = table_helpers.deep_copy(config.current_config.large_monster_UI.health.text_label);
health_value_label = table_helpers.deep_copy(config.current_config.large_monster_UI.health.value_label);
health_percentage_label = table_helpers.deep_copy(config.current_config.large_monster_UI.health.percentage_label);
stamina_bar = table_helpers.deep_copy(config.current_config.large_monster_UI.stamina.bar);
stamina_label = table_helpers.deep_copy(config.current_config.large_monster_UI.stamina.text_label);
stamina_value_label = table_helpers.deep_copy(config.current_config.large_monster_UI.stamina.value_label);
stamina_percentage_label = table_helpers.deep_copy(config.current_config.large_monster_UI.stamina.percentage_label);
rage_bar = table_helpers.deep_copy(config.current_config.large_monster_UI.rage.bar);
rage_label = table_helpers.deep_copy(config.current_config.large_monster_UI.rage.text_label);
drawing.scale_label_opacity(monster_name_label, opacity_falloff);
drawing.scale_bar_opacity(health_bar, opacity_falloff);
drawing.scale_label_opacity(health_label, opacity_falloff);
drawing.scale_label_opacity(health_value_label, opacity_falloff);
drawing.scale_label_opacity(health_percentage_label, opacity_falloff);
drawing.scale_bar_opacity(stamina_bar, opacity_falloff);
drawing.scale_label_opacity(stamina_label, opacity_falloff);
drawing.scale_label_opacity(stamina_value_label, opacity_falloff);
drawing.scale_label_opacity(stamina_percentage_label, opacity_falloff);
drawing.scale_bar_opacity(rage_bar, opacity_falloff);
drawing.scale_label_opacity(rage_label, opacity_falloff);
drawing.scale_label_opacity(rage_value_label, opacity_falloff);
drawing.scale_label_opacity(rage_percentage_label, opacity_falloff);
end
end
if monster.is_in_rage then
rage_value_label.visibility = false;
rage_percentage_label.text = "%.0f:%04.1f";
end
drawing.draw_bar(health_bar, position_on_screen, monster.health_percentage);
drawing.draw_bar(stamina_bar, position_on_screen, monster.stamina_percentage);
drawing.draw_bar(rage_bar, position_on_screen, rage_bar_percentage);
drawing.draw_label(monster_name_label, position_on_screen, monster_name_text);
drawing.draw_label(health_label, position_on_screen);
drawing.draw_label(health_value_label, position_on_screen, monster.health, monster.max_health);
drawing.draw_label(health_percentage_label, position_on_screen, 100 * monster.health_percentage);
drawing.draw_label(stamina_label, position_on_screen);
drawing.draw_label(stamina_value_label, position_on_screen, monster.stamina, monster.max_stamina);
drawing.draw_label(stamina_percentage_label, position_on_screen, 100 * monster.stamina_percentage);
drawing.draw_label(rage_label, position_on_screen);
drawing.draw_label(rage_value_label, position_on_screen, monster.rage_point, monster.rage_limit);
if monster.is_in_rage then
drawing.draw_label(rage_percentage_label, position_on_screen, monster.rage_minutes_left, monster.rage_seconds_left);
else
drawing.draw_label(rage_percentage_label, position_on_screen, 100 * monster.rage_percentage);
end
i = i + 1;
::continue::
end
end
function large_monster_UI.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
config = require("MHR_Overlay.Misc.config");
customization_menu = require("MHR_Overlay.UI.customization_menu");
large_monster = require("MHR_Overlay.Monsters.large_monster");
screen = require("MHR_Overlay.Game_Handler.screen");
player = require("MHR_Overlay.Damage_Meter.player");
drawing = require("MHR_Overlay.UI.drawing");
table_helpers = require("MHR_Overlay.Misc.table_helpers");
end
return large_monster_UI;

View File

@@ -0,0 +1,181 @@
local small_monster_UI = {};
local singletons;
local config;
local small_monster;
local customization_menu;
local screen;
local player;
local drawing;
local table_helpers;
function small_monster_UI.draw()
if singletons.enemy_manager == nil then
return;
end
local displayed_monsters = {};
local enemy_count = singletons.enemy_manager:call("getZakoEnemyCount");
if enemy_count == nil then
customization_menu.status = "No enemy count";
return;
end
for i = 0, enemy_count - 1 do
local enemy = singletons.enemy_manager:call("getZakoEnemy", i);
if enemy == nil then
customization_menu.status = "No enemy";
break
end
local monster = small_monster.list[enemy];
if monster == nil then
customization_menu.status = "No monster hp entry";
break
end
table.insert(displayed_monsters, monster);
end
if not config.current_config.small_monster_UI.dynamic_positioning.enabled then
-- sort here
if config.current_config.small_monster_UI.sorting.type == "Normal" and config.current_config.small_monster_UI.sorting.reversed_order then
local reversed_monsters = {};
for i = #displayed_monsters, 1, -1 do
table.insert(reversed_monsters, displayed_monsters[i]);
end
displayed_monsters = reversed_monsters;
elseif config.current_config.small_monster_UI.sorting.type == "Health" then
if config.current_config.small_monster_UI.sorting.reversed_order then
table.sort(displayed_monsters, function(left, right)
return left.health > right.health;
end);
else
table.sort(displayed_monsters, function(left, right)
return left.health < right.health;
end);
end
elseif config.current_config.small_monster_UI.sorting.type == "Health Percentage" then
if config.current_config.small_monster_UI.sorting.reversed_order then
table.sort(displayed_monsters, function(left, right)
return left.health_percentage > right.health_percentage;
end);
else
table.sort(displayed_monsters, function(left, right)
return left.health_percentage < right.health_percentage;
end);
end
end
end
x = "";
local i = 0;
for _, monster in ipairs(displayed_monsters) do
local position_on_screen;
if config.current_config.small_monster_UI.dynamic_positioning.enabled then
local world_offset = Vector3f.new(config.current_config.small_monster_UI.dynamic_positioning.world_offset.x, config.current_config.small_monster_UI.dynamic_positioning.world_offset.y, config.current_config.small_monster_UI.dynamic_positioning.world_offset.z);
position_on_screen = draw.world_to_screen(monster.position + world_offset);
if position_on_screen == nil then
goto continue
end
position_on_screen.x = position_on_screen.x + config.current_config.small_monster_UI.dynamic_positioning.viewport_offset.x;
position_on_screen.y = position_on_screen.y + config.current_config.small_monster_UI.dynamic_positioning.viewport_offset.y;
else
position_on_screen = screen.calculate_absolute_coordinates(config.current_config.small_monster_UI.position);
if config.current_config.small_monster_UI.settings.orientation == "Horizontal" then
position_on_screen.x = position_on_screen.x + config.current_config.small_monster_UI.spacing.x * i;
else
position_on_screen.y = position_on_screen.y + config.current_config.small_monster_UI.spacing.y * i;
end
end
local monster_name_label = config.current_config.small_monster_UI.monster_name_label;
local health_bar = config.current_config.small_monster_UI.health.bar;
local health_label = config.current_config.small_monster_UI.health.text_label;
local health_value_label = config.current_config.small_monster_UI.health.value_label;
local health_percentage_label = config.current_config.small_monster_UI.health.percentage_label;
local stamina_bar = config.current_config.small_monster_UI.stamina.bar;
local stamina_label = config.current_config.small_monster_UI.stamina.text_label;
local stamina_value_label = config.current_config.small_monster_UI.stamina.value_label;
local stamina_percentage_label = config.current_config.small_monster_UI.stamina.percentage_label;
if config.current_config.small_monster_UI.dynamic_positioning.enabled then
if config.current_config.small_monster_UI.dynamic_positioning.max_distance == 0 then
return;
end
local distance = (player.myself_position - monster.position):length();
if distance > config.current_config.small_monster_UI.dynamic_positioning.max_distance then
goto continue;
end
if config.current_config.small_monster_UI.dynamic_positioning.opacity_falloff then
local opacity_falloff = 1 - (distance / config.current_config.small_monster_UI.dynamic_positioning.max_distance);
monster_name_label = table_helpers.deep_copy(config.current_config.small_monster_UI.monster_name_label);
health_bar = table_helpers.deep_copy(config.current_config.small_monster_UI.health.bar);
health_label = table_helpers.deep_copy(config.current_config.small_monster_UI.health.text_label);
health_value_label = table_helpers.deep_copy(config.current_config.small_monster_UI.health.value_label);
health_percentage_label = table_helpers.deep_copy(config.current_config.small_monster_UI.health.percentage_label);
stamina_bar = table_helpers.deep_copy(config.current_config.small_monster_UI.stamina.bar);
stamina_label = table_helpers.deep_copy(config.current_config.small_monster_UI.stamina.text_label);
stamina_value_label = table_helpers.deep_copy(config.current_config.small_monster_UI.stamina.value_label);
stamina_percentage_label = table_helpers.deep_copy(config.current_config.small_monster_UI.stamina.percentage_label);
drawing.scale_bar_opacity(health_bar, opacity_falloff);
drawing.scale_bar_opacity(stamina_bar, opacity_falloff)
drawing.scale_label_opacity(monster_name_label, opacity_falloff);
drawing.scale_label_opacity(health_label, opacity_falloff);
drawing.scale_label_opacity(health_value_label, opacity_falloff);
drawing.scale_label_opacity(health_percentage_label, opacity_falloff);
drawing.scale_label_opacity(stamina_label, opacity_falloff);
drawing.scale_label_opacity(stamina_value_label, opacity_falloff);
drawing.scale_label_opacity(stamina_percentage_label, opacity_falloff);
end
end
drawing.draw_bar(health_bar, position_on_screen, monster.health_percentage);
drawing.draw_bar(stamina_bar, position_on_screen, monster.stamina_percentage);
drawing.draw_label(monster_name_label, position_on_screen, monster.name);
drawing.draw_label(health_label, position_on_screen);
drawing.draw_label(health_value_label, position_on_screen, monster.health, monster.max_health);
drawing.draw_label(health_percentage_label, position_on_screen, 100 * monster.health_percentage);
drawing.draw_label(stamina_label, position_on_screen);
drawing.draw_label(stamina_value_label, position_on_screen, monster.stamina, monster.max_stamina);
drawing.draw_label(stamina_percentage_label, position_on_screen, 100 * monster.stamina_percentage);
i = i + 1;
::continue::
end
end
function small_monster_UI.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
config = require("MHR_Overlay.Misc.config");
customization_menu = require("MHR_Overlay.UI.customization_menu");
small_monster = require("MHR_Overlay.Monsters.small_monster");
screen = require("MHR_Overlay.Game_Handler.screen");
player = require("MHR_Overlay.Damage_Meter.player");
drawing = require("MHR_Overlay.UI.drawing");
table_helpers = require("MHR_Overlay.Misc.table_helpers");
end
return small_monster_UI;

View File

@@ -0,0 +1,46 @@
local time_UI = {};
local singletons;
local customization_menu;
local screen;
local config;
local drawing;
function time_UI.draw()
if singletons.quest_manager == nil then
return;
end
local quest_time_elapsed_minutes = singletons.quest_manager:call("getQuestElapsedTimeMin");
if quest_time_elapsed_minutes == nil then
customization_menu.status = "No quest time elapsed minutes";
return;
end
local quest_time_total_elapsed_seconds = singletons.quest_manager:call("getQuestElapsedTimeSec");
if quest_time_total_elapsed_seconds == nil then
customization_menu.status = "No quest time total elapsed seconds";
return;
end
if quest_time_total_elapsed_seconds == 0 then
return;
end
local quest_time_elapsed_seconds = quest_time_total_elapsed_seconds - quest_time_elapsed_minutes * 60;
local position_on_screen = screen.calculate_absolute_coordinates(config.current_config.time_UI.position);
drawing.draw_label(config.current_config.time_UI.time_label, position_on_screen, quest_time_elapsed_minutes, quest_time_elapsed_seconds);
end
function time_UI.init_module()
singletons = require("MHR_Overlay.Game_Handler.singletons");
customization_menu = require("MHR_Overlay.UI.customization_menu");
screen = require("MHR_Overlay.Game_Handler.screen");
config = require("MHR_Overlay.Misc.config");
drawing = require("MHR_Overlay.UI.drawing");
end
return time_UI;