local mod_gui = require("mod-gui") require "util" require "particles" --local modsprites = require("prototypes.sprites") local format_number = util.format_number local stg_critical_interval = 1.5 --[[ ** RPG SYSTEM ** by ProjectMakers (Fork from MFerrari) ]] function shortnumberstring(number) local steps = { {1,""}, {1e3,"k"}, {1e6,"m"}, {1e9,"g"}, {1e12,"t"}, } for _,b in ipairs(steps) do if b[1] <= number+1 then steps.use = _ end end local result = string.format("%.1f", number / steps[steps.use][1]) if tonumber(result) >= 1e3 and steps.use < #steps then steps.use = steps.use + 1 result = string.format("%.1f", tonumber(result) / 1e3) end return result .. steps[steps.use][2] end function RPG_format_number(number) local result if number < 1000000000 then result=format_number(number) else result=shortnumberstring(number) end return result end function Log(what) game.write_file("myrpg.log", serpent.block(what), true) end local colors = { white = {r = 1, g = 1, b = 1}, black = {r = 0, g = 0, b = 0}, darkgrey = {r = 0.25, g = 0.25, b = 0.25}, grey = {r = 0.5, g = 0.5, b = 0.5}, lightgrey = {r = 0.75, g = 0.75, b = 0.75}, red = {r = 1, g = 0, b = 0}, darkred = {r = 0.5, g = 0, b = 0}, lightred = {r = 1, g = 0.5, b = 0.5}, green = {r = 0, g = 1, b = 0}, darkgreen = {r = 0, g = 0.5, b = 0}, lightgreen = {r = 0.5, g = 1, b = 0.5}, blue = {r = 0, g = 0, b = 1}, darkblue = {r = 0, g = 0, b = 0.5}, lightblue = {r = 0.5, g = 0.5, b = 1}, orange = {r = 1, g = 0.55, b = 0.1}, yellow = {r = 1, g = 1, b = 0}, pink = {r = 1, g = 0, b = 1}, purple = {r = 0.6, g = 0.1, b = 0.6}, brown = {r = 0.6, g = 0.4, b = 0.1}, } --prototypes.sprites.charxpmod_space_suit.layers[2].tint = {1,0,0,0.5} -- CUSTOM EVENT HANDLING -- --(remote interface is lower in the file, there I describe how to subscribe to my events) -- if your mod alters the character bonus settings, then you should get_on_player_updated_status to make required adjusts to your mod, if necessary local on_player_updated_status = script.generate_event_name() --uint local on_player_level_up = script.generate_event_name() --uint function printXP(player,XP) if player and player.valid then if settings.get_player_settings(player)["charxpmod_print_xp_user"].value then player.surface.create_entity{name = "flying-text", position = player.position, text = "+" .. RPG_format_number(XP) ..' XP', color = colors.yellow} end end end function ResetXPTables() local xp = 1500 global.xp_table = {[1] = xp} local mp = 1.6 local red = 0.018 --local maxL = settings.startup["charxpmod_xp_maxlevel"].value local maxi = global.setting_max_player_level local m for k=2,maxi do m = mp - k*(red-red*k/ maxi) -- (Multiplier - Level * (reductor-reductor*Level/100)) xp = math.ceil(xp * m) if (xp / global.xp_table[k-1]) < 1.02 then xp = global.xp_table[k-1] * 1.02 end xp= math.ceil(xp) global.xp_table[k] = xp end global.max_xp = xp end function SetForceValues(name) global.kills_spawner[name] = 0 global.kills_units[name] = 0 global.kills_worms[name] = 0 global.XP[name] = 0 global.XP_GANHO[name] = 0 global.XP_TECH[name] = 0 global.XP_LEVEL[name] = 1 global.XP_LEVEL_MIN[name] = 0 global.XP_KILL_HP[name] = 0 global.XP_MAX_PLAYTIME[name] = 0 global.XP_AVG_PLAYTIME[name] = 0 end function CheckAddPlayerStatus(name) global.personalxp[name] = global.personalxp[name] or {} for _, player in pairs(game.players) do global.personalxp[name][player.name] = global.personalxp[name][player.name] or 0 --game.print(name .. player.name .. global.personalxp[name][player.name]) end end function VersionChange() if global.personalxp.opt_Pick_Extender == nil then global.personalxp.opt_Pick_Extender = {} for _, player in pairs(game.players) do global.personalxp.opt_Pick_Extender[player.name] = false end end if global.XP_MAX_PLAYTIME == nil then global.XP_MAX_PLAYTIME={} for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then global.XP_MAX_PLAYTIME[name] = 0 end end end if global.XP_AVG_PLAYTIME == nil then global.XP_AVG_PLAYTIME={} for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then global.XP_AVG_PLAYTIME[name] = 0 end end end CheckAddPlayerStatus('rocketsXP_count') end function SetupPlayer(player,ResetXP) local name= player.name if ResetXP then global.personalxp.XP[name] = 0 global.personalxp.Death[name] = 0 global.personal_kill_units[name] = 0 global.personal_kill_spawner[name] = 0 global.personal_kill_turrets[name] = 0 end global.personalxp.Level[name] = 1 Reset_Character_Bonuses(player.character) for k=1,#global.Player_Attributes do local attrib = global.Player_Attributes[k] global.personalxp[attrib][name]= 0 end global.personalxp.opt_Pick_Extender[name] = false UpdatePlayerLvStats(player) end function CheckPlayers() for _, player in pairs(game.players) do if not (global.personalxp.Level[player.name]) then SetupPlayer(player,true) end if not global.personal_kill_units[player.name] then global.personal_kill_units[player.name] = 0 global.personal_kill_spawner[player.name] = 0 global.personal_kill_turrets[player.name] = 0 end InitPlayerGui(player) end end function CheckPlayer(player) if not (global.personalxp.Level[player.name]) then SetupPlayer(player,true) end end function ReadRunTimeSettings(event) global.setting_print_critical = false global.setting_afk_time = 15 global.setting_time_ratio_xp = true global.setting_death_penal = 30 if event and event.setting_type=='runtime-per-user' and event.setting=='charxpmod_hide_xp_panel' then local player = game.players[event.player_index] player.gui.top.chartopframe.visible = not settings.get_player_settings(player)["charxpmod_hide_xp_panel"].value end end function XPModSetup() global.handle_respawn = global.handle_respawn or {} global.last_critical_effect_from = global.last_critical_effect_from or {} global.Player_Attributes = { "LV_Health_Bonus", "LV_Armor_Bonus", "LV_Damage_Bonus", "LV_Damage_Critical", "LV_Run_Speed", "LV_Craft_Speed", "LV_Mining_Speed", "LV_Inv_Bonus", "LV_InvTrash_Bonus", "LV_Robot_Bonus", "LV_Reach_Dist", } global.setting_allow_xp_by_tech = true global.setting_allow_xp_by_kill = true global.setting_allow_xp_by_rocket = true global.setting_allow_xp_by_mining = true global.XP_Mult = 1 global.setting_allow_damage_attribs = false global.setting_max_player_level = 200 global.setting_max_level_ability = 50 ReadRunTimeSettings() if global.CharXPMOD == nil then global.CharXPMOD = 1 global.kills_spawner={} global.kills_units={} global.kills_worms={} global.XP={} global.XP_GANHO={} global.XP_KILL_HP={} global.XP_TECH={} global.XP_LEVEL={} global.XP_LEVEL_MIN={} global.XP_MAX_PLAYTIME={} global.XP_AVG_PLAYTIME={} global.personalxp = {} global.personalxp.Level = {} global.personalxp.XP = {} global.personalxp.Death = {} for k=1,#global.Player_Attributes do global.personalxp[global.Player_Attributes[k]]= {} end global.personalxp.opt_Pick_Extender = {} for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then SetForceValues(name) end end end ResetXPTables() mySettingsrpg = { charxpmod_LV_Health_Bonus = { value = 10, }, charxpmod_LV_Armor_Bonus = { value = 1, }, charxpmod_LV_Run_Speed = { value = 3, }, charxpmod_LV_Damage_Bonus = { value = 2, }, charxpmod_LV_Damage_Critical = { value = 1, }, charxpmod_LV_Craft_Speed = { value = 5, }, charxpmod_LV_Mining_Speed = { value = 5, }, charxpmod_LV_Reach_Dist = { value = 1, }, charxpmod_LV_Inv_Bonus = { value = 1, }, charxpmod_LV_InvTrash_Bonus = { value = 1, }, charxpmod_LV_Robot_Bonus = { value = 1, }, } global.RPG_Bonus = {} for k=1,#global.Player_Attributes do local attrib = global.Player_Attributes[k] global.RPG_Bonus[attrib]= mySettingsrpg ["charxpmod_"..attrib].value CheckAddPlayerStatus(attrib) end global.personal_kill_units = global.personal_kill_units or {} global.personal_kill_spawner = global.personal_kill_spawner or {} global.personal_kill_turrets = global.personal_kill_turrets or {} VersionChange() CheckPlayers() end function ResetAll() ResetXPTables() for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then SetForceValues(name) end end for _, player in pairs(game.players) do SetupPlayer(player,true) UpdatePanel(player) end end function ResetPointSpent() ResetXPTables() for _, player in pairs(game.players) do SetupPlayer(player,false) end end function InitPlayerGui(player) local name = player.name -- close main panel local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if frame then frame.destroy() end -- remove previous versions if player.gui.top.chartopframe then player.gui.top.chartopframe.destroy() end if player.gui.top.btcharxp then player.gui.top.btcharxp.destroy() end -- create new ones local Topframe = player.gui.top.add{name="chartopframe", direction = "horizontal", type="frame", style=mod_gui.frame_style, visible = false} Topframe.style.minimal_height = 30 -- Topframe.style.maximal_height = 37 Topframe.style.minimal_width = 150 -- Topframe.style.maximal_width = 250 --snouz Topframe.style.margin = {0,10,5,10} Topframe.style.padding = {0,9,0,0} Topframe.add{name="btcharxp", type="sprite-button", sprite = "entity/character", tooltip = {"panel-title", player.name}, style = mod_gui.top_button_style, visible = false} -- "mod_gui_button"} local tabFrame = Topframe.add{type = "table", name = "tabtopframexp", column_count = 1, visible = false} Level = global.personalxp.Level[name] local pnivel = tabFrame.add{type="label", name='chartoplvtxt', caption={'actual_lv',Level}, visible = false} pnivel.style.font="charxpmod_font_17b" local TopXPbar = tabFrame.add{type = "progressbar", name = "TopXPbar", visible = false} TopXPbar.style.width=110 UpdatePanel(player) end ---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------- function RatioXP(player) local ratioXP = 1 if global.setting_time_ratio_xp and global.XP_AVG_PLAYTIME[player.force.name]>0 then ratioXP = player.online_time/global.XP_AVG_PLAYTIME[player.force.name] if ratioXP >= 1.10 then ratioXP = 1.10 elseif ratioXP < 0.05 then ratioXP = 0.05 end end return ratioXP end function XP_Player_upd() for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then local cp = #force.connected_players local afk = global.setting_afk_time if cp>0 then local XP = global.XP[name] --math.ceil(global.XP[name] / cp) if XP>0 then for p, PL in pairs (force.connected_players) do if afk==0 or PL.afk_timeglobal.max_xp then global.personalxp.Level[name]=global.setting_max_player_level else for L=Lv, #global.xp_table do if global.personalxp.XP[name]< global.xp_table[L] then global.personalxp.Level[name]=L break end end end if global.personalxp.Level[name] > Lv then --player.print({'player_lv_up',global.personalxp.Level[name]}) --mod_gui.get_button_flow(player).focus() --player.gui.top.chartopframe.focus() player.play_sound{path = 'player_level_up',volume_modifier=0.85} script.raise_event(on_player_level_up, {player_index = player.index, player_level = global.personalxp.Level[name]}) end UpdatePanel(player) end end end function XP_Time_upd() for name, force in pairs (game.forces) do if name~='neutral' and name~='enemy' then local PT local TT=0 local QP=0 for p, PL in pairs (force.players) do PT = PL.online_time if PT > global.XP_AVG_PLAYTIME[name]/20 then -- a player time count for avg if he has at least 5% of the avg time TT = TT + PT QP = QP + 1 end if global.XP_MAX_PLAYTIME[name] < PT then global.XP_MAX_PLAYTIME[name] = PT end end if QP>0 then global.XP_AVG_PLAYTIME[name] = TT/QP end end end end function XP_UPDATE_tick() XP_Time_upd() XP_Player_upd() XP_PlayerLv_upd() end function SumPointSpent(name) local sum = 0 for k=1,#global.Player_Attributes do local attrib = global.Player_Attributes[k] sum = sum + global.personalxp[attrib][name] end return sum end -- MAIN RPG CHARACTER GUI function update_char_panel(player) XP_Time_upd() local force = player.force.name local painel = player.gui.center["char-panel"] or player.gui.screen["char-panel"] local frame = painel.tabcharScroll local name = player.name local Level = global.personalxp.Level[name] local HP = 0 --local playercolor = player.color --modsprites.charxpmod_space_suit_mask.tint = playercolor local ptime = player.online_time local txtPTime = {"time-played", string.format("%d:%02d:%02d", math.floor(ptime / 216000), math.floor(ptime / 3600) % 60, math.floor(ptime / 60) % 60)} local PontosXP = Level - 1 - SumPointSpent(name) if PontosXP<0 then PontosXP=0 end frame.add{type = "line"} local tabChar = frame.add{type = "table", name = "tab_tbchar", column_count = 2} local frametabChar = tabChar.add{name="frametabChar", type="frame", style=mod_gui.frame_style} if player.character and player.character.valid then HP = math.ceil(player.character.health) local cam = frametabChar.add{type = "entity-preview", name='rpg_player_preview'} --local cam = frametabChar.add({ type="camera", name="rpg_player_preview", position = player.position, zoom = 0.75 }) cam.style.width = 110 cam.style.height = 110 cam.entity=player.character cam.style.padding = {0,-10,0,-10} cam.style.margin = {5,0,-5,0} else local rpgportrait = frametabChar.add{type = "sprite", sprite = "charxpmod_space_suit"} rpgportrait.style.padding = {0,-10,0,-10} rpgportrait.style.margin = {5,0,-5,0} --rpgportrait.style.width = 44.8 --rpgportrait.style.height = 84 --rpgportrait.style.margin = {2,25,4,20} end local tabScroll = tabChar.add{type = "scroll-pane", name = "tabScroll2", vertical_scroll_policy = "auto", horizontal_scroll_policy = "auto"} --tabScroll.style.height = 120 tabScroll.style.padding = {-5,0,5,10} local tabPName = tabScroll.add{type = "table", name = "tab_pname", column_count = 1} local pnivel = tabPName.add{type="label", name='ocharlevel', caption={'actual_lv',Level}} pnivel.style.font = "charxpmod_font_30" --pnivel.style.font_color = player.color pnivel.style.bottom_padding = -5 -- XP RATIO local ratioXP = RatioXP(player) ratioXP = math.floor(ratioXP*100) local tabStats = tabScroll.add{type = "table", name = "tabStats", column_count = 1} local wd = 160 tabStats.add{type="label", name='STT1', caption=txtPTime}.style.width = wd tabStats.add{type="label", name='STT3', caption={'xp_ratio',ratioXP}} --.style.width = wd tabStats.add{type="label", name='STT2', caption={'xp_deaths',global.personalxp.Death[name]}}.style.width = wd tabStats.add{type="label", name='STT5', caption='HP: '.. format_number(HP)}.style.width = wd local pbvalue = CalculateXP_PB(player.name) local XP = global.personalxp.XP[name] local NextLevel = global.xp_table[Level] local NextLtxt = RPG_format_number(NextLevel) if XP >= global.max_xp then NextLtxt = 'MAX' end frame.add{type = "line"} ---------------XP NUMBERS local flowXP = frame.add{type = "flow", direction="horizontal"} flowXP.style.width = 450 local currXP = flowXP.add{type="label", name='lbxpatual', caption='XP: ' .. RPG_format_number( XP ) } --.style.font="charxpmod_font_17" currXP.style.font='default-bold' local stretchableFlow = flowXP.add{type = "flow", direction="horizontal"} stretchableFlow.style.horizontally_stretchable = true local flownextXP = flowXP.add{type = "flow", direction="horizontal"} flownextXP.style.horizontal_align = "right" flownextXP.style.width = 200 local nextXP = flownextXP.add{type="label", caption={'next_lv', NextLtxt}} --.style.font="charxpmod_font_17" ----------------XP BAR local btAttribute2 = frame.add{type="sprite-button", sprite = "info11", name="info22", tooltip = { "xp_hint_global.personalxp.LV_Info" } } btAttribute2.style.width = 70 btAttribute2.style.height = 70 btAttribute2.style.margin = {0,0,0,0} btAttribute2.style.padding = {0,0,0,0} local tabBar = frame.add{type = "table", column_count = 1} local bar = tabBar.add{type = "progressbar", value = pbvalue, name = "tab_XPbar", style="achievement_progressbar"} bar.style.width = 450 frame.add{type = "line"} frame.add{type = "label", name = 'lbxPAGastar', caption={'xp_points',PontosXP}}.style.font="charxpmod_font_20" -- LEVELS / UPGRADES local tabUpgrades = frame.add{type = "table", name = "tabUpgrades", column_count = 6} tabUpgrades.style.horizontal_spacing = 10 tabUpgrades.style.vertical_spacing = 10 local Max = global.setting_max_level_ability local custo = 1 local vchar local at_level local attrib local bonus, Tbonus for A=1,#global.Player_Attributes do attrib = global.Player_Attributes[A] local enabled = true if (attrib=="LV_Armor_Bonus" or attrib=="LV_Damage_Bonus" or attrib=="LV_Damage_Critical") and (not global.setting_allow_damage_attribs) then enabled = false end if global.RPG_Bonus[attrib]==0 then enabled = false end if enabled then vchar = 'global.personalxp.'..attrib at_level = global.personalxp[attrib][name] bonus = global.RPG_Bonus[attrib] Tbonus = at_level * bonus local tabAttrib = tabUpgrades.add{type = "table", column_count = 1} tabAttrib.style.horizontal_align = "center" local framebtAttributetext = tabAttrib.add{direction = "horizontal", type="frame"} framebtAttributetext.style.width = 67 --67 framebtAttributetext.style.horizontal_align = "center" framebtAttributetext.style.margin = {0,0,-5,0} framebtAttributetext.style.padding = {0,0,-5,0} local btAttributetext = framebtAttributetext.add{type="label", caption={vchar}} btAttributetext.style.font = "charxpmod_font_12" btAttributetext.style.width = 60 --57 btAttributetext.style.horizontal_align = "center" btAttributetext.style.margin = {0,0,0,0} btAttributetext.style.padding = {0,0,0,0} local btAttribute = tabAttrib.add{type="sprite-button", sprite = attrib .. "_sprite", style = 'rounded_button', name='btLVU_'..vchar, tooltip={'xp_hint_'..vchar,format_number(bonus),format_number(Tbonus)}} btAttribute.style.font = "charxpmod_font_icons" btAttribute.style.width = 67 btAttribute.style.height = 67 btAttribute.style.margin = {0,0,0,0} btAttribute.style.padding = {0,0,0,0} btAttribute.style.horizontal_align = "center" local frametxtAttLv = tabAttrib.add{direction = "horizontal", type="frame"} frametxtAttLv.style.width = 67 frametxtAttLv.style.margin = {-5,0,0,0} frametxtAttLv.style.padding = {-5,0,0,0} frametxtAttLv.style.horizontal_align = "center" local txtAttLv = frametxtAttLv.add{type="label", caption=at_level} txtAttLv.style.font = "charxpmod_font_17" txtAttLv.style.width = 57 txtAttLv.style.horizontal_align = "center" txtAttLv.style.margin = {0,0,0,0} txtAttLv.style.padding = {0,0,0,0} btAttribute.enabled = PontosXP>=custo and at_level global.max_xp then XP = global.max_xp end local NextLevel = global.xp_table[Level] if not NextLevel then return end local XP_ant if Level==1 then XP_ant = 0 else XP_ant = global.xp_table[Level-1] end local Interval_XP = NextLevel - XP_ant local pbvalue = (XP-XP_ant)/Interval_XP return pbvalue end function CalculateXP_GAIN_LV(playername) local pbvalue = CalculateXP_PB(playername) local Level = global.personalxp.Level[playername] local NextLevel = global.xp_table[Level] if not NextLevel then return end local XP = global.personalxp.XP[playername] local xp_to_next_level = NextLevel - XP local next_partial = 0 if Level1 then PriorLVXP = global.xp_table[Level-1] end GainXP = math.ceil((NextLevel - PriorLVXP) * Perc) end return GainXP end function UpdatePanel(player, focus) -- BARRA DE XP tabtopframexp local TopXPbar = player.gui.top.chartopframe.tabtopframexp.TopXPbar local txtlv = player.gui.top.chartopframe.tabtopframexp.chartoplvtxt local Level = global.personalxp.Level[player.name] local pbvalue = CalculateXP_PB(player.name) txtlv.caption={'actual_lv',Level} TopXPbar.value=pbvalue local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if frame then expand_char_gui(player) end end function close_char_panel(player) local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if frame then frame.destroy() end end function reopen_char_panel(player) close_char_panel(player) expand_char_gui(player) end function open_close_char_gui(player) local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if frame then close_char_panel(player) else expand_char_gui(player) end end function expand_char_gui(player) local wid = 470 local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if not frame then frame = player.gui.screen.add{type="frame", name="char-panel", direction = "vertical", style=mod_gui.frame_style} frame.auto_center = true frame.style.minimal_height = 430 --frame.style.maximal_height = 430 frame.style.minimal_width = wid frame.style.maximal_width = 485 local title_table = frame.add{type="table", name="title_table", column_count=4, draw_horizontal_lines=false} title_table.style.horizontally_stretchable = true title_table.style.column_alignments[1] = "left" title_table.style.column_alignments[2] = "right" title_table.style.column_alignments[3] = "right" title_table.style.column_alignments[4] = "right" title_table.drag_target = frame local title_frame = title_table.add{type="frame", name="title_frame", caption={"panel-title", player.name}, style="ic_title_frame"} -- title_frame.ignored_by_interaction = true local tagfield = title_table.add{type="textfield", name="ctag_field", text=player.tag} tagfield.style.width=200 tagfield.visible=false local edittag = title_table.add{name="rpg_bt_edittag", type="sprite-button", sprite = "utility/rename_icon_normal", style = "shortcut_bar_button_small", tooltip={'player_tag'}} local closeb = title_table.add{name="rpg_bt_close", type="sprite-button", sprite = "utility/close_black", style = "shortcut_bar_button_small"} end if frame.tabcharScroll then frame.tabcharScroll.destroy() end local tabcharScroll = frame.add{type = "scroll-pane", name= "tabcharScroll", vertical_scroll_policy="auto", horizontal_scroll_policy="auto"} tabcharScroll.style.minimal_height = 400 --tabcharScroll.style.maximal_height = 1000 tabcharScroll.style.minimal_width = wid - 15 tabcharScroll.style.maximal_width = wid - 15 update_char_panel(player) end function UpdatePlayerLvStats(player, skip_inv) local name=player.name if player.character then player.character.character_crafting_speed_modifier = player.character.character_crafting_speed_modifier + global.personalxp.LV_Craft_Speed[name] * global.RPG_Bonus['LV_Craft_Speed']/100 player.character.character_mining_speed_modifier = player.character.character_mining_speed_modifier + global.personalxp.LV_Mining_Speed[name] * global.RPG_Bonus['LV_Mining_Speed']/100 player.character.character_running_speed_modifier = player.character.character_running_speed_modifier + global.personalxp.LV_Run_Speed[name] * global.RPG_Bonus['LV_Run_Speed']/100 player.character.character_build_distance_bonus = player.character.character_build_distance_bonus+ global.personalxp.LV_Reach_Dist[name] * global.RPG_Bonus['LV_Reach_Dist'] player.character.character_reach_distance_bonus = player.character.character_reach_distance_bonus+ global.personalxp.LV_Reach_Dist[name] * global.RPG_Bonus['LV_Reach_Dist'] player.character.character_item_drop_distance_bonus = player.character.character_item_drop_distance_bonus+ global.personalxp.LV_Reach_Dist[name] * global.RPG_Bonus['LV_Reach_Dist'] player.character.character_resource_reach_distance_bonus = player.character.character_resource_reach_distance_bonus+ global.personalxp.LV_Reach_Dist[name] * global.RPG_Bonus['LV_Reach_Dist'] if not skip_inv then player.character.character_inventory_slots_bonus = player.character.character_inventory_slots_bonus + global.personalxp.LV_Inv_Bonus[name] * global.RPG_Bonus['LV_Inv_Bonus'] end player.character.character_trash_slot_count_bonus = player.character.character_trash_slot_count_bonus + global.personalxp.LV_InvTrash_Bonus[name] * global.RPG_Bonus['LV_InvTrash_Bonus'] player.character.character_maximum_following_robot_count_bonus = player.character.character_maximum_following_robot_count_bonus + global.personalxp.LV_Robot_Bonus[name] * global.RPG_Bonus['LV_Robot_Bonus'] player.character.character_health_bonus = player.character.character_health_bonus+ global.personalxp.LV_Health_Bonus[name] * global.RPG_Bonus['LV_Health_Bonus'] if global.personalxp.opt_Pick_Extender[name] then player.character.character_item_pickup_distance_bonus = player.character.character_reach_distance_bonus player.character.character_loot_pickup_distance_bonus = player.character.character_reach_distance_bonus end end end local p_attribs = { 'character_crafting_speed_modifier', 'character_mining_speed_modifier', 'character_running_speed_modifier', 'character_reach_distance_bonus', 'character_item_drop_distance_bonus', 'character_resource_reach_distance_bonus', 'character_inventory_slots_bonus', 'character_trash_slot_count_bonus', 'character_maximum_following_robot_count_bonus', 'character_health_bonus', 'character_item_pickup_distance_bonus'} function Reset_Character_Bonuses(character) if character and character.valid then for a=1,#p_attribs do character[p_attribs[a]]=0 end end end function CopyPlayerStats(name) local player = game.players[name] if player and player.valid then local character_attribs = {} if player.character and player.character.valid then for a=1,#p_attribs do table.insert(character_attribs,player.character[p_attribs[a]]) end end local rpg_stats = {global.personalxp.Level[name], global.personalxp.XP[name], global.personalxp.Death[name], global.personalxp.opt_Pick_Extender[name], global.personal_kill_units[name], global.personal_kill_spawner[name], global.personal_kill_turrets[name], } for k=1,#global.Player_Attributes do local attrib = global.Player_Attributes[k] table.insert(rpg_stats, global.personalxp[attrib][name] ) end return {character_attribs=character_attribs, rpg_stats=rpg_stats} end end function PastePlayerStats(name,status) local player = game.players[name] if player and player.valid and status then local character_attribs = status.character_attribs if player.character and player.character.valid then for a=1,#p_attribs do player.character[p_attribs[a]]=character_attribs[a] end end local rpg_stats = status.rpg_stats global.personalxp.Level[name] = rpg_stats[1] global.personalxp.XP[name] = rpg_stats[2] global.personalxp.Death[name] = rpg_stats[3] global.personalxp.opt_Pick_Extender[name] = rpg_stats[4] global.personal_kill_units[name] = rpg_stats[5] global.personal_kill_spawner[name] = rpg_stats[6] global.personal_kill_turrets[name] = rpg_stats[7] for k=1,#global.Player_Attributes do local attrib = global.Player_Attributes[k] global.personalxp[attrib][name] = rpg_stats[k+7] end UpdatePanel(player) end end -- this will calculate the stat using sum, instead of replacing the value -- used for compatibility with other mods function AdjustPlayerStat(player,stat) local name=player.name if player.character ~= nil then if stat=='character_crafting_speed_modifier' then player.character[stat] = player.character[stat] + global.personalxp.LV_Craft_Speed[name] * global.RPG_Bonus['LV_Craft_Speed']/100 elseif stat=='character_mining_speed_modifier' then player.character[stat] = player.character[stat] + global.personalxp.LV_Mining_Speed[name] * global.RPG_Bonus['LV_Mining_Speed']/100 elseif stat=='character_running_speed_modifier' then player.character[stat] = player.character[stat] + global.personalxp.LV_Run_Speed[name] * global.RPG_Bonus['LV_Run_Speed']/100 elseif stat=='character_build_distance_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] elseif stat=='character_reach_distance_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] elseif stat=='character_item_drop_distance_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] elseif stat=='character_resource_reach_distance_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] elseif stat=='character_inventory_slots_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Inv_Bonus[name] * global.RPG_Bonus['LV_Inv_Bonus'] elseif stat=='character_trash_slot_count_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_InvTrash_Bonus[name]* global.RPG_Bonus['LV_InvTrash_Bonus'] elseif stat=='character_maximum_following_robot_count_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Robot_Bonus[name]* global.RPG_Bonus['LV_Robot_Bonus'] elseif stat=='character_health_bonus' then player.character[stat] = player.character[stat] + global.personalxp.LV_Health_Bonus[name]* global.RPG_Bonus['LV_Health_Bonus'] elseif stat=='character_item_pickup_distance_bonus' then if global.personalxp.opt_Pick_Extender[name] then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] end elseif stat=='character_loot_pickup_distance_bonus' then if global.personalxp.opt_Pick_Extender[name] then player.character[stat] = player.character[stat] + global.personalxp.LV_Reach_Dist[name]* global.RPG_Bonus['LV_Reach_Dist'] end end end end function LevelUPPlayer(player,btname) local name=player.name for A=1,#global.Player_Attributes do local attrib = global.Player_Attributes[A] if btname=='btLVU_global.personalxp.'.. attrib then global.personalxp[attrib][name] = global.personalxp[attrib][name] + 1 if btname=='btLVU_global.personalxp.LV_Craft_Speed' then player.character.character_crafting_speed_modifier = player.character.character_crafting_speed_modifier + global.RPG_Bonus[attrib]/100 end if btname=='btLVU_global.personalxp.LV_Mining_Speed' then player.character.character_mining_speed_modifier = player.character.character_mining_speed_modifier + global.RPG_Bonus[attrib]/100 end if btname=='btLVU_global.personalxp.LV_Run_Speed' then player.character.character_running_speed_modifier = player.character.character_running_speed_modifier + global.RPG_Bonus[attrib]/100 end if btname=='btLVU_global.personalxp.LV_Reach_Dist' then player.character.character_build_distance_bonus = player.character.character_build_distance_bonus + global.RPG_Bonus[attrib] player.character.character_reach_distance_bonus = player.character.character_reach_distance_bonus + global.RPG_Bonus[attrib] player.character.character_item_drop_distance_bonus = player.character.character_item_drop_distance_bonus + global.RPG_Bonus[attrib] player.character.character_resource_reach_distance_bonus = player.character.character_resource_reach_distance_bonus + global.RPG_Bonus[attrib] end if btname=='btLVU_global.personalxp.LV_Inv_Bonus' then player.character.character_inventory_slots_bonus = player.character.character_inventory_slots_bonus + global.RPG_Bonus[attrib] end if btname=='btLVU_global.personalxp.LV_InvTrash_Bonus' then player.character.character_trash_slot_count_bonus = player.character.character_trash_slot_count_bonus + global.RPG_Bonus[attrib] end if btname=='btLVU_global.personalxp.LV_Robot_Bonus' then player.character.character_maximum_following_robot_count_bonus = player.character.character_maximum_following_robot_count_bonus + global.RPG_Bonus[attrib] end if btname=='btLVU_global.personalxp.LV_Health_Bonus' then player.character.character_health_bonus = player.character.character_health_bonus + global.RPG_Bonus[attrib] end script.raise_event(on_player_updated_status, {player_index = player.index, player_level = global.personalxp.Level[name], attribute=attrib}) break end end if global.personalxp.opt_Pick_Extender[name] then player.character.character_item_pickup_distance_bonus = math.min(player.character.character_reach_distance_bonus,320) player.character.character_loot_pickup_distance_bonus = math.min(player.character.character_reach_distance_bonus,320) else player.character.character_item_pickup_distance_bonus = 0 player.character.character_loot_pickup_distance_bonus = 0 end end script.on_nth_tick(60 * 5,function (event) XP_UPDATE_tick() check_respawned_players() end) function check_respawned_players() for name,died in pairs (global.handle_respawn) do if died then if game.players[name] and game.players[name].valid and game.players[name].character and game.players[name].character.valid then global.handle_respawn[name]=false UpdatePlayerLvStats(game.players[name]) end end end end function Cria_Player(event) local player = game.players[event.player_index] SetupPlayer(player,true) end function on_force_created(event) local name = event.force.name SetForceValues(name) end function onPlayerJoin(event) local player = game.players[event.player_index] CheckPlayer(player) InitPlayerGui(player) end function On_Init() XPModSetup() end function on_configuration_changed(data) XPModSetup() end script.on_event(defines.events.on_player_created, Cria_Player) script.on_event(defines.events.on_player_joined_game, onPlayerJoin) script.on_event(defines.events.on_runtime_mod_setting_changed, ReadRunTimeSettings) --script.on_event(defines.events.on_tick, on_tick ) script.on_event(defines.events.on_force_created,on_force_created) script.on_configuration_changed(on_configuration_changed) script.on_init(On_Init) script.on_event("key-I", function(event) open_close_char_gui(game.players[event.player_index]) end) -- closes panel when player open inventory E script.on_event(defines.events.on_gui_opened, function(event) if event.gui_type and event.gui_type ==defines.gui_type.controller then close_char_panel(game.players[event.player_index]) end end) local function on_gui_click(event) local player = game.players[event.element.player_index] local element = event.element if element and element.valid then local name = element.name local frame = player.gui.center["char-panel"] or player.gui.screen["char-panel"] if (name == "btcharxp") then open_close_char_gui(player) elseif (name == "rpg_bt_edittag")then local tagfield = element.parent.ctag_field local text =tagfield.text if tagfield.visible then tagfield.visible = false element.sprite = "utility/rename_icon_normal" if player.tag~=text then player.tag = text player.print({"",{'player_tag'}, ': ', text}) end else tagfield.visible = true element.sprite = "utility/check_mark_green" end elseif string.sub(name,1,6)=='btLVU_' then if player.character and player.character.valid then LevelUPPlayer(player,name) expand_char_gui(player) end elseif name == "cb_pick_extender" then if player.character == nil then frame.tabcharScroll.cb_pick_extender.state = global.personalxp.opt_Pick_Extender[player.name] return end local cb_pick_extender = frame.tabcharScroll.cb_pick_extender.state global.personalxp.opt_Pick_Extender[player.name] = cb_pick_extender if cb_pick_extender then player.character.character_item_pickup_distance_bonus = player.character.character_reach_distance_bonus player.character.character_loot_pickup_distance_bonus = player.character.character_reach_distance_bonus else player.character.character_item_pickup_distance_bonus = 0 player.character.character_loot_pickup_distance_bonus = 0 end elseif name == "bt_destroy_my_parent" then if element and element.parent then element.parent.destroy() end elseif name == "rpg_bt_close" then element.parent.parent.destroy() end end end script.on_event(defines.events.on_gui_click, on_gui_click) script.on_event(defines.events.on_player_respawned, function(event) local player = game.players[event.player_index] global.handle_respawn[player.name]=false UpdatePlayerLvStats(player) end) script.on_event(defines.events.on_pre_player_died, function(event) local player = game.players[event.player_index] local name = player.name local XP = global.personalxp.XP[name] local Level = global.personalxp.Level[name] local NextLevel = global.xp_table[Level] local XP_ant if Level==1 then XP_ant = 0 else XP_ant = global.xp_table[Level-1] end local Interval_XP = NextLevel - XP_ant local Penal = math.floor((XP-XP_ant)*global.setting_death_penal/100) global.personalxp.Death[name] = global.personalxp.Death[name]+1 global.handle_respawn[name]=true if Penal>0 then global.personalxp.XP[name] = global.personalxp.XP[name]-Penal player.print({"", {'xp_lost'}, RPG_format_number(Penal)},colors.lightred) end end) function GetXPByKill(entity,killer,force) if force then if global.setting_allow_xp_by_kill then if not global.last_overkill or (global.last_overkill and global.last_overkill~=entity) then if entity and entity.valid then local XP = entity.prototype.max_health local player , plname if killer and killer.valid then if killer.is_player() then player=killer else if killer.type and killer.type == 'character' then player=killer.player force=killer.force end end end if player then plname=player.name end local nforce=force.name if force ~= entity.force and (not force.get_friend(entity.force)) then if entity.type == 'character' then XP = XP * 4 elseif entity.type == 'unit' then global.kills_units[nforce] = global.kills_units[nforce] + 1 if player then global.personal_kill_units[plname]=global.personal_kill_units[plname]+1 end elseif entity.type == 'unit-spawner' then XP = XP * 3 global.kills_spawner[nforce] = global.kills_spawner[nforce] +1 if player then global.personal_kill_spawner[plname]=global.personal_kill_spawner[plname]+1 end elseif entity.type == 'turret' then global.kills_worms[nforce] = global.kills_worms[nforce] +1 if player then global.personal_kill_turrets[plname]=global.personal_kill_turrets[plname]+1 end XP = XP * 2 end -- if XP > 999999 then XP=999999 end XP = math.ceil((1+force.evolution_factor) * global.XP_Mult * XP/3) if XP<1 then XP=1 end local teamxp = true if plname then if global.personalxp.XP[plname] then global.personalxp.XP[plname] = global.personalxp.XP[plname] + XP printXP(player,XP) teamxp = false end end if teamxp and global.XP_KILL_HP[nforce] then XP=math.ceil(XP/3) global.XP_KILL_HP[nforce] = global.XP_KILL_HP[nforce] +XP global.XP[nforce] = global.XP[nforce] + XP end end end end end global.last_overkill=nil end end --- XP FOR KILL script.on_event(defines.events.on_entity_died, function(event) if not event.force then return end local force=event.force -- force that kill local killer=event.cause --if event.entity.force.name == 'enemy' and force~='neutral' and force~='enemy' then --aliens if killer and killer.valid and global.kills_units[force.name] and event.entity.force~=game.forces.neutral then if event.entity.prototype and event.entity.prototype.max_health and (not force.get_friend(event.entity.force)) then if killer.type=='car' then if killer.get_driver() and killer.get_driver().valid then killer = killer.get_driver() elseif killer.get_passenger() and killer.get_passenger().valid then killer = killer.get_passenger() end end GetXPByKill(event.entity,killer,force) end end if not killer then if global.kills_units[force.name] and event.entity.force~=game.forces.neutral then GetXPByKill(event.entity,killer,force) end end end, {{filter = "type", type = "unit"}, {filter = "type", type = "unit-spawner"}, {filter = "type", type = "spider-vehicle"}, {filter = "type", type = "car"},{filter = "type", type = "electric-turret"}, {filter = "type", type = "artillery-turret"}, {filter = "type", type = "ammo-turret"}, {filter = "type", type = "fluid-turret"}, {filter = "type", type = "turret"}, {filter = "type", type = "character"}} ) -- event filters function create_crithit_effect(entity,level,damage) if string.find(entity.type, 'unit') or entity.type == 'character' or entity.type == 'turret' then create_blood_particles(entity.surface, 300+level*10, entity.position,2+level/10) create_guts_particles(entity.surface, 40 + level*2, entity.position,2+level/10) else create_remnants_particles(entity.surface, level, entity.position,1+level/10) end entity.surface.play_sound{path='utility/axe_fighting',position=entity.position,volume_modifier=1} if global.setting_print_critical then entity.surface.create_entity{name = "flying-text", position = entity.position, text = math.ceil(damage), color = colors.red} end end local crit = false if crit == true then -- damage bonus, criticals , natural armor script.on_event(defines.events.on_entity_damaged, function(event) local entity = event.entity local damage_type = event.damage_type local original_damage_amount = event.original_damage_amount local cause = event.cause if cause and cause.valid and entity and entity.valid and entity.health>0 and damage_type and original_damage_amount then -- NATURAL ARMOR if event.final_damage_amount>0 and entity.type == 'character' then local player = entity.player if player and player.valid then local armor_lv = global.personalxp.LV_Armor_Bonus[player.name] if armor_lv>0 then local bonus = (global.RPG_Bonus.LV_Armor_Bonus * armor_lv) local recover = event.final_damage_amount*bonus/100 entity.health = entity.health + recover end end end -- DAMAGE BONUS if cause.type == 'character' and damage_type.name~='poison' and damage_type.name~='cold' then local player = cause.player if player and player.valid then local dmg_lv = global.personalxp.LV_Damage_Bonus[player.name] local critical_lv = global.personalxp.LV_Damage_Critical[player.name] local new_damage = original_damage_amount if dmg_lv>0 then local bonus = 1+ (global.RPG_Bonus.LV_Damage_Bonus * dmg_lv/100) new_damage = original_damage_amount * bonus end -- CRITICAL HITS if critical_lv>0 and (string.find(entity.type, 'unit') or string.find(entity.type, 'turret') or entity.type=='car' or entity.type=='character' or entity.type=='spider-vehicle') then local proba = 100 if damage_type.name=='fire' then proba=proba*60 end --because damage per tick if math.random(proba)<=critical_lv * global.RPG_Bonus['LV_Damage_Critical'] then new_damage = math.ceil(new_damage * (5 + critical_lv/2)) if (not global.last_critical_effect_from[player.name]) or global.last_critical_effect_from[player.name]+60*stg_critical_interval original_damage_amount then local dif = new_damage - original_damage_amount if entity.health < dif then -- give kill xp to player because the extra damage will kill entity GetXPByKill(entity,cause,cause.force) global.last_overkill = event.entity end if entity.valid then entity.health = entity.health + event.final_damage_amount entity.damage(new_damage,player.force,damage_type.name) -- this fires the event again end end end end end end, {{filter = "type", type = "unit"}, {filter = "type", type = "unit-spawner"}, {filter = "type", type = "wall"}, {filter = "type", type = "gate"}, {filter = "type", type = "spider-vehicle"}, {filter = "type", type = "car"},{filter = "type", type = "electric-turret"}, {filter = "type", type = "artillery-turret"}, {filter = "type", type = "ammo-turret"}, {filter = "type", type = "fluid-turret"}, {filter = "type", type = "turret"}, {filter = "type", type = "character"}}) -- event filters end -- XP by research script.on_event(defines.events.on_research_finished, function(event) if global.setting_allow_xp_by_tech and game.tick > 3600 * 2 then if event.research.force then local force = event.research.force.name if force~='neutral' and force~='enemy' then if global.XP_TECH[force] then local techXP = event.research.research_unit_count * #event.research.research_unit_ingredients techXP = math.ceil(global.XP_Mult * techXP * (1+ (6*game.forces["enemy"].evolution_factor))) global.XP_TECH[force] = global.XP_TECH[force] +techXP global.XP[force] = global.XP[force] +techXP end end end end end) -- XP by Rocket script.on_event(defines.events.on_rocket_launched, function(event) if global.setting_allow_xp_by_rocket then local rocket = event.rocket local force = rocket.force local XP for p, PL in pairs (force.connected_players) do local r_count = global.personalxp.rocketsXP_count[PL.name] if r_count == nil then r_count=0 end XP = math.ceil(global.XP_Mult * global.personalxp.XP[PL.name]/(5+(r_count*2))) --20% inicial global.personalxp.XP[PL.name] = global.personalxp.XP[PL.name] + XP printXP(PL,XP) global.personalxp.rocketsXP_count[PL.name] = r_count+1 end end end) --- XP FOR Mining rocks, trees function XPByMiningRT(player,ent) local XP = 0 if ent.prototype.max_health then XP=ent.prototype.max_health if ent.type=='tree' then XP=XP/100 else XP=XP/400 end end if XP>0 then local plname = player.name XP = math.ceil(XP * global.personalxp.Level[plname] * global.XP_Mult) global.personalxp.XP[plname] = global.personalxp.XP[plname] + XP printXP(player,XP) end end script.on_event(defines.events.on_player_mined_entity, function(event) if global.setting_allow_xp_by_mining then local player = game.players[event.player_index] if not player.valid then return end local ent = event.entity local name= ent.name if ent.type=='tree' or (ent.type=='simple-entity' and name:find('rock')) then XPByMiningRT(player,ent) end end end, {{filter = "type", type = "tree"}, {filter = "type", type = "simple-entity"}} ) -- INTERFACE -- -------------------------------------------------------------------------------------- -- /c remote.call("RPG","TeamXP","player",1150) local interface = {} -- Give XP to Team (may be negative) function interface.TeamXP(forcename,XP) global.XP[forcename] = global.XP[forcename] + XP XP_UPDATE_tick() end -- Give XP to a player (may be negative) function interface.PlayerXP(playername,XP) global.personalxp.XP[playername] = global.personalxp.XP[playername] + XP printXP(game.players[playername],XP) XP_UPDATE_tick() end -- Give a fixed XP multiplyed by player level (may be negative) function interface.PlayerXPPerLevel(playername,XP) global.personalxp.XP[playername] = global.personalxp.XP[playername] + (XP * global.personalxp.Level[playername]) XP_UPDATE_tick() end -- Player gain one level function interface.PlayerGainLevel(playername) if global.personalxp.XP[playername] then local XP = CalculateXP_GAIN_LV(playername) global.personalxp.XP[playername] = global.personalxp.XP[playername] + XP XP_UPDATE_tick() end end -- Give player XP % of his current XP level bar - perc=0 to 1, eg 0.25 function interface.PlayerXPPercCurrentBar(playername,Perc) if global.personalxp.XP[playername] then local XP = CalculateXP_PERCENT_CURRENT_LV(playername,Perc) global.personalxp.XP[playername] = global.personalxp.XP[playername] + XP printXP(game.players[playername],XP) XP_UPDATE_tick() end end -- Give player XP % of his own XP function interface.PlayerXPPerc(playername,Perc) local XP = math.ceil(global.personalxp.XP[playername]*Perc/100) global.personalxp.XP[playername] = global.personalxp.XP[playername] + XP printXP(game.players[playername],XP) XP_UPDATE_tick() end -- Penalty XP for a % of his own XP function interface.PlayerXPPenalPerc(playername,Perc) global.personalxp.XP[playername] = global.personalxp.XP[playername] - math.ceil(global.personalxp.XP[playername]*Perc/100) XP_UPDATE_tick() end -- Give all force players a XP% of his own XP function interface.TeamXPPerc(forcename,Perc) local XP for p, PL in pairs (game.forces[forcename].connected_players) do XP = math.ceil(global.personalxp.XP[PL.name]*Perc/100) global.personalxp.XP[PL.name] = global.personalxp.XP[PL.name] + XP printXP(PL,XP) end XP_UPDATE_tick() end -- Used only for compatibility with other mods function interface.OtherEventsByPlayer(player,event_name,parameter) if event_name=='mine_rock' then XPByMiningRT(player.name,parameter) end if event_name=='adjust_player_stats' then AdjustPlayerStat(player,parameter) end end function interface.ResetAll() ResetAll() end interface.CopyPlayerStats = CopyPlayerStats function interface.PastePlayerStats(playername,stats) PastePlayerStats(playername,stats) end commands.add_command('rpg-reset-points', 'Reconstruct XP table and reset all habilities to zero. Players can spent all points again', function(event) local player = game.players[event.player_index] if player.admin then ResetPointSpent() game.print({'xp_reset_altert'}) end end) commands.add_command('rpg-reset-all', 'Reconstruct XP table and reset everything to zero, as a new game', function(event) local player = game.players[event.player_index] if player.admin then ResetAll() game.print({'xp_reset_altert'}) end end) commands.add_command('rpg-players-list', 'List all players', function(event) local player = game.players[event.player_index] ListAll(player) end) commands.add_command('rpg-listXPTable', 'List XP table', function(event) local player = game.players[event.player_index] ListXPTable(player) end) --[[ HOW TO subscribe to my 2 events below: script.on_event(remote.call("RPG", "get_on_player_updated_status"), function(event) --do your stuff end) WARNING: this has to be done within on_init and on_load, otherwise the game will error about the remote.call if your dependency on my mod is optional, remember to check if the remote interface exists before calling it: if remote.interfaces["RPG"] then --interface exists end]] function interface.get_on_player_updated_status() return on_player_updated_status end -- Returns : -- event.player_index = Index of the player that upgraded an attribute -- event.level = Player current XP Level -- event.attribute = The attribute that was upgraded function interface.get_on_player_level_up() return on_player_level_up end -- Returns : -- event.player_index = Index of the player that has just leveled up -- event.level = Player current XP Level --other mods --jetpack function interface.on_character_swapped(event) --local new_unit_number = event.new_unit_number --local old_unit_number = event.old_unit_number local new_character = event.new_character local old_character = event.old_character if new_character and new_character.valid then local player = new_character.player if player and player.valid then UpdatePlayerLvStats(player, true) end end end remote.add_interface("RPG", interface )