|
59 | 59 | SKILL_FITNESS = EXP_NONE, |
60 | 60 | ) |
61 | 61 |
|
62 | | - /// Progress towards increasing their skill level |
| 62 | + /// Progress towards increasing their skill level. |
63 | 63 | var/list/exp_progress = list( |
64 | 64 | SKILL_PHYSIOLOGY = 0, |
65 | 65 | SKILL_MECHANICAL = 0, |
|
68 | 68 | SKILL_FITNESS = 0, |
69 | 69 | ) |
70 | 70 |
|
| 71 | + /// One-time experience gains that have already been acquired. |
| 72 | + var/list/exp_sources = list() |
| 73 | + |
71 | 74 | /// Free skill points to allocate |
72 | 75 | var/skill_points = 0 |
73 | 76 |
|
|
118 | 121 | key = _key |
119 | 122 | soulOwner = src |
120 | 123 | martial_art = default_martial_art |
| 124 | + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_EXCEPTIONAL_SKILL), PROC_REF(update_skills)) |
121 | 125 |
|
122 | 126 | /datum/mind/Destroy() |
123 | 127 | SSticker.minds -= src |
|
804 | 808 | return FALSE |
805 | 809 | return (mind.skills[skill] >= amount) |
806 | 810 |
|
807 | | -/// Adds progress towards increasing skill level. Returns TRUE if it improved the skill. |
808 | | -/mob/proc/add_exp(skill, amount) |
| 811 | +/// Adds progress towards increasing skill level. Returns TRUE if it added progress. Adding a source prevents gaining exp from that source again. |
| 812 | +/mob/proc/add_exp(skill, amount, source) |
809 | 813 | if(!mind) |
810 | 814 | return FALSE |
811 | | - if(mind.skill_points > 0) |
| 815 | + if(!amount) |
812 | 816 | return FALSE |
813 | | - var/exp_required = EXPERIENCE_PER_LEVEL * (2**mind.skills[skill]) // exp required scales exponentially |
814 | | - if(mind.exp_progress[skill] + amount >= exp_required) |
815 | | - var/levels_gained = round(log(2, 1 + (mind.exp_progress[skill] + amount) / exp_required)) // in case you gained so much you go up more than one level |
816 | | - var/levels_allocated = hud_used?.skill_menu ? hud_used.skill_menu.allocated_skills[skill] : 0 |
817 | | - if(levels_allocated > 0) // adjust any already allocated skills to prevent shenanigans (you know who you are) |
818 | | - hud_used.skill_menu.allocated_points -= min(levels_gained, levels_allocated) |
819 | | - hud_used.skill_menu.allocated_skills[skill] -= min(levels_gained, levels_allocated) |
820 | | - mind.exp_progress[skill] += amount - exp_required * (2**(levels_gained - 1)) |
821 | | - adjust_skill(skill, levels_gained) |
822 | | - to_chat(src, span_boldnotice("Your [skill] skill is now level [get_skill(skill)]!")) |
823 | | - return TRUE |
| 817 | + if(source && (source in mind.exp_sources)) |
| 818 | + return FALSE |
| 819 | + mind.exp_sources.Add(source) |
824 | 820 | mind.exp_progress[skill] += amount |
825 | | - return FALSE |
| 821 | + var/levels_gained = check_exp(skill) |
| 822 | + if(levels_gained) // remove an equal amount of unallocated skill points to prevent exploits |
| 823 | + mind.skill_points = max(mind.skill_points - levels_gained, 0) |
| 824 | + return TRUE |
| 825 | + |
| 826 | +/// Levels up a skill if it has enough experience to do so. |
| 827 | +/mob/proc/check_exp(skill) |
| 828 | + if(!mind) |
| 829 | + return FALSE |
| 830 | + var/current_level = get_skill(skill) |
| 831 | + var/exp_required = EXPERIENCE_PER_LEVEL * (2**current_level) // exp required scales exponentially |
| 832 | + if(mind.exp_progress[skill] < exp_required) |
| 833 | + return FALSE |
| 834 | + var/skill_cap = EXP_MASTER + HAS_MIND_TRAIT(src, TRAIT_EXCEPTIONAL_SKILL) |
| 835 | + var/levels_gained = min(round(log(2, 1 + (mind.exp_progress[skill] / exp_required))), max(skill_cap - current_level)) // in case you gained so much you go up more than one level |
| 836 | + if(levels_gained < 1) |
| 837 | + return FALSE |
| 838 | + var/levels_allocated = hud_used?.skill_menu ? hud_used.skill_menu.allocated_skills[skill] : 0 |
| 839 | + if(levels_allocated > 0) // adjust any already allocated skills to prevent shenanigans (you know who you are) |
| 840 | + hud_used.skill_menu.allocated_points -= min(levels_gained, levels_allocated) |
| 841 | + hud_used.skill_menu.allocated_skills[skill] -= min(levels_gained, levels_allocated) |
| 842 | + mind.exp_progress[skill] -= exp_required * (((2**round(levels_gained + 1)) / 2) - 1) |
| 843 | + adjust_skill(skill, levels_gained, max_skill = skill_cap) |
| 844 | + to_chat(src, span_boldnotice("Your [skill] skill is now level [get_skill(skill)]!")) |
| 845 | + return levels_gained |
| 846 | + |
| 847 | +/// Returns whether experience has been gained from a given source. |
| 848 | +/mob/proc/has_exp(source) |
| 849 | + if(!mind) |
| 850 | + return FALSE |
| 851 | + return (source in mind.exp_sources) ? TRUE : FALSE |
826 | 852 |
|
827 | 853 | /// Adds skill points to be allocated at will. |
828 | 854 | /mob/proc/add_skill_points(amount) |
|
831 | 857 | mind.skill_points += amount |
832 | 858 | throw_alert("skill points", /atom/movable/screen/alert/skill_up) |
833 | 859 |
|
| 860 | +/// Called when [TRAIT_EXCEPTIONAL_SKILL] is added to the mob. |
| 861 | +/datum/mind/proc/update_skills(datum/source) |
| 862 | + SIGNAL_HANDLER |
| 863 | + if(!current) |
| 864 | + return |
| 865 | + for(var/skill in skills) |
| 866 | + current.check_exp(skill) |
| 867 | + |
834 | 868 | /datum/mind/proc/has_martialart(string) |
835 | 869 | if(martial_art && martial_art.id == string) |
836 | 870 | return martial_art |
|
0 commit comments