Modlaser fixes (#22550)

Fixes the easy stuff from: #22545

The only real balance change, dropped improvement per variable by 50%.
Should have been like this from the start, but I mistakenly assumed no
one would even reach close to the cap.

Makes repairs with welders go through .use_tool, fixes not needing
welding goggles and adds nice sparky visuals.
Much more robust handling of improvable variables, negatives don't break
improvement assignment now.
Fixes improvement cap, missed a *100 to convert from decimal to
percentage.
Fixes improvement potential being assigned to things that couldn't be
upgraded.
Fixes the Gatling mod upgrading fire delay (pretty useless on something
with a 3 second warmup)
Fixes the weapon analyzer print out showing completely incorrect
numbers.
Fixes the weapon analyzer eating your combitool and being
indestructible.
Gives some more feedback on why things can and can't be upgraded.
This commit is contained in:
FenodyreeAv
2026-06-03 15:24:32 +00:00
committed by GitHub
parent 6a88cb3a19
commit f66007e324
6 changed files with 150 additions and 28 deletions
@@ -387,9 +387,12 @@
while(improvement_potential > 0 && damaged_components.len)
var/list/upgradable_components = list()
for(var/obj/item/laser_components/component in damaged_components)
if(component.total_improved < IMPROVEMENT_CAP)
upgradable_components += component
for(var/obj/item/laser_components/component in damaged_components) //Only give it improvement potential if it's damaged.
if((component.total_improved + component.improvement_potential) < IMPROVEMENT_CAP) //Only give it improvement potential if it doesn't have enough to hit cap.
if(component.increasable_stats.len || component.decreaseable_stats.len) //Don't give it to components with nothing to improve.
upgradable_components += component
else
damaged_components.Remove(component) //If a component has reached the improvement cap, it can't be improved anymore.
if(!upgradable_components.len)
to_chat(user, SPAN_WARNING("There's nothing to improve on the components of this gun."))
@@ -527,10 +530,55 @@
return 1
/obj/item/gun/energy/laser/prototype/get_print_info()
. = ..(FALSE)
. = ""
var/l_modified_damage = 1 / max(1, burst - 1)
var/l_modified_max_shots = 1
for(var/i in list(capacitor, focusing_lens, modulator) + gun_mods)
var/obj/item/laser_components/l_component = i
if(!l_component)
continue
if(l_component.damage != 0)
l_modified_damage *= l_component.damage
if(l_component.shots != 0)
l_modified_max_shots *= l_component.shots
var/obj/projectile/P = new projectile_type
. += "Max Shots: [round(l_modified_max_shots)]<br>"
. += "Recharge Type: [self_recharge ? "self recharging" : "not self recharging"]<br>"
if(self_recharge)
. += "Recharge Time: [initial(recharge_time)]<br>"
. += "<br><b>Primary Projectile</b><br>"
. += "Damage: [round(min(60, l_modified_damage), 1)]<br>"
. += "Damage Type: [initial(P.damage_type)]<br>"
. += "Blocked by Armor Type: [initial(P.check_armor)]<br>"
. += "Stuns: [initial(P.stun) ? "true" : "false"]<br>"
if(initial(P.shrapnel_type))
var/obj/shrapnel = new P.shrapnel_type
. += "Shrapnel Type: [shrapnel.name]<br>"
. += "Armor Penetration: [initial(P.armor_penetration)]%<br>"
. += "Burst: [burst]<br>"
. += "Reliability: [reliability]<br>"
if(secondary_projectile_type)
var/obj/projectile/P_second = new secondary_projectile_type
. += "<br><b>Secondary Projectile</b><br>"
. += "Damage: [initial(P_second.damage)]<br>"
. += "Damage Type: [initial(P_second.damage_type)]<br>"
. += "Blocked by Armor Type: [initial(P_second.check_armor)]<br>"
. += "Stuns: [initial(P_second.stun) ? "true" : "false"]<br>"
if(initial(P_second.shrapnel_type))
var/obj/shrapnel_second = new P_second.shrapnel_type
. += "Shrapnel Type: [shrapnel_second.name]<br>"
. += "Armor Penetration: [initial(P_second.armor_penetration)]%<br>"
. += "<br>"
for(var/i in list(capacitor, focusing_lens, modulator) + gun_mods)
var/obj/item/laser_components/l_component = i
if(!l_component)
continue
. += "<br>Component Name: [initial(l_component.name)]</br><br>"
var/l_repair_name = initial(l_component.repair_item.name) ? initial(l_component.repair_item.name) : "nothing"
+68 -19
View File
@@ -42,7 +42,13 @@
condition = reliability
/obj/item/laser_components/proc/handle_improvement(var/skill_level, var/mob/user)
while (improvement_potential > 0)
if (total_improved >= IMPROVEMENT_CAP)
to_chat(user, SPAN_NOTICE("You don't see any way to improve \the [src] any further."))
improvement_potential = 0
return
while (improvement_potential > 0 && total_improved < IMPROVEMENT_CAP)
var/improvement = min(abs(improvement_potential / 100), 0.2) //Caps improvement from a single repair to 20%. This spreads the effect out across multiple stats
var/stat_direction = 1
@@ -66,8 +72,20 @@
break //No stats to improve, it shouldn't be possible to have improvement potential and no stats to improve, but just in case.
if (stat_name in src.vars)
var/initial_value = initial(src.vars[stat_name])
improvement_potential -= improvement * 100 //Decreases improvement potential before any skill modifiers.
if (initial_value < 0) //If the stat begins negative, such as base_malus for heat vents, handle comparisons by sign.
if (stat_direction > 0 && src.vars[stat_name] >= (initial_value * DECREASE_CAP))
continue
if (stat_direction < 0 && src.vars[stat_name] <= (initial_value * INCREASE_CAP))
continue
else
if (src.vars[stat_name] >= (initial_value * INCREASE_CAP) && stat_direction > 0) //It is possible to waste improvement potential by hitting the cap on a stat, this is fine, it should be harder to improve a component that's already of high quality.
continue
if (src.vars[stat_name] <= (initial_value * DECREASE_CAP) && stat_direction < 0)
continue
switch(skill_level ? skill_level : 6)
if(-INFINITY to 2)
improvement *= (rand(-5, -1) / 10) //Always damage it.
@@ -80,21 +98,37 @@
if(6 to INFINITY)
improvement *= (rand(8, 12) / 10)
if (src.vars[stat_name] > (initial(src.vars[stat_name]) * INCREASE_CAP) && stat_direction > 0) //It is possible to waste improvement potential by hitting the cap on a stat, this is fine, it should be harder to improve a component that's already of high quality.
continue
if (src.vars[stat_name] < (initial(src.vars[stat_name]) * DECREASE_CAP) && stat_direction < 0)
continue
src.vars[stat_name] += stat_direction * abs(initial(src.vars[stat_name]) * improvement) //Adds improvement % of the initial value to the stat.
src.vars[stat_name] += stat_direction * abs(initial_value * improvement) //Adds improvement % of the initial value to the stat.
if (improvement > 0)
to_chat(user, SPAN_NOTICE("Your careful repairs to \the [src] [stat_direction > 0 ? "increase" : "decrease"] its [replacetext(stat_name, "_", " ")] by [improvement * 100] percent!"))
total_improved += improvement
total_improved += improvement * 100
if (initial_value < 0)
if (stat_direction > 0 && src.vars[stat_name] >= initial_value * DECREASE_CAP)
to_chat(user, SPAN_NOTICE("Your repairs to \the [src] have improved its [replacetext(stat_name, "_", " ")] as far as you think is possible."))
else if (stat_direction < 0 && src.vars[stat_name] <= initial_value * INCREASE_CAP)
to_chat(user, SPAN_NOTICE("Your repairs to \the [src] have improved its [replacetext(stat_name, "_", " ")] as far as you think is possible."))
else
to_chat(user, SPAN_NOTICE("Your careful repairs to \the [src] [stat_direction > 0 ? "increase" : "decrease"] its [replacetext(stat_name, "_", " ")] by [improvement * 100] percent!"))
else
if(src.vars[stat_name] >= initial_value * INCREASE_CAP && stat_direction > 0)
to_chat(user, SPAN_NOTICE("Your repairs to \the [src] have improved its [replacetext(stat_name, "_", " ")] as far as you think is possible."))
else if(src.vars[stat_name] <= initial_value * DECREASE_CAP && stat_direction < 0)
to_chat(user, SPAN_NOTICE("Your repairs to \the [src] have improved its [replacetext(stat_name, "_", " ")] as far as you think is possible."))
else
to_chat(user, SPAN_NOTICE("Your careful repairs to \the [src] [stat_direction > 0 ? "increase" : "decrease"] its [replacetext(stat_name, "_", " ")] by [improvement * 100] percent!"))
else if (improvement == 0)
to_chat(user, SPAN_NOTICE("Your repairs to \the [src], don't seem to improve it, but at least you didn't make it worse."))
else
to_chat(user, SPAN_WARNING("Your repairs to \the [src] end up damaging it!"))
else
break //The stat to improve isn't on this component, something went wrong with the lists of stats or the component itself.
if (total_improved > IMPROVEMENT_CAP)
improvement_potential = 0
to_chat(user, SPAN_NOTICE("You have improved \the [src] as much as you can."))
/obj/item/laser_components/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(distance > 1)
@@ -150,9 +184,21 @@
if (condition == 0 && malus == base_malus)
to_chat(user, SPAN_WARNING("\The [src] is not damaged."))
return ..()
to_chat(user, SPAN_WARNING("You begin repairing \the [src]."))
var/skill_level = (GET_SKILL_LEVEL(user, FIREARMS_SKILL_COMPONENT) + GET_SKILL_LEVEL(user, RESEARCH_SKILL_COMPONENT))
if(do_after(user, rand(2 SECONDS, 6 SECONDS), src, DO_UNIQUE) && repair_module(attacking_item, skill_level, user))
if(attacking_item.tool_behaviour == TOOL_WELDER)
var/obj/item/weldingtool/WT = attacking_item
if(WT.isOn() && WT.use_tool(src, user, rand(2 SECONDS, (10 - skill_level) SECONDS), volume = 50) && WT.use(0, user) && repair_module(attacking_item, skill_level, user))
user.visible_message(
SPAN_WARNING("[user] begins repairing \the [src]."),
SPAN_NOTICE("You begin repairing \the [src]."),
"You hear a welding torch on metal."
)
else
to_chat(user, SPAN_WARNING("You fail to repair \the [src]."))
else if(do_after(user, rand(2 SECONDS, (10 - skill_level) SECONDS), src, DO_UNIQUE) && repair_module(attacking_item, skill_level, user)) //Used if the repair item is not a tool.
to_chat(user, SPAN_NOTICE("You repair \the [src]."))
else
to_chat(user, SPAN_WARNING("You fail to repair \the [src]."))
@@ -189,7 +235,7 @@
return
if(malus == base_malus)
return 0
if(W.use(2))
if(W.use(1)) //Welders burn fuel while active
handle_improvement(skill_level, user)
malus = max(malus - 5, base_malus)
return 1
@@ -332,8 +378,10 @@
var/success = FALSE
if(!istype(A))
return ..()
if(!ready_to_craft)
to_chat(user, SPAN_WARNING("You cannot modify \the [src] by hand, you need to use a weapons analyzer."))
var/skill_level = (GET_SKILL_LEVEL(user, FIREARMS_SKILL_COMPONENT) + GET_SKILL_LEVEL(user, RESEARCH_SKILL_COMPONENT))
if(!ready_to_craft && skill_level < 5)
to_chat(user, SPAN_WARNING("You cannot modify \the [src] by hand at your current skill level, you need to use a weapons analyzer."))
return
if(ismodifier(A) && gun_mods.len < modifier_cap)
@@ -389,9 +437,7 @@
/obj/item/laser_assembly/proc/finish()
var/obj/structure/machinery/r_n_d/weapons_analyzer/an = analyzer.resolve()
if(!an)
return FALSE
var/obj/structure/machinery/r_n_d/weapons_analyzer/an = analyzer ? analyzer.resolve() : null
var/obj/item/gun/energy/laser/prototype/A = new /obj/item/gun/energy/laser/prototype
A.icon_state = icon_state
@@ -410,8 +456,11 @@
mod.forceMove(A)
if(mod.gun_overlay)
A.underlays += mod.gun_overlay
A.forceMove(an)
an.item = A
if(an)
A.forceMove(an)
an.item = A
else
A.forceMove(get_turf(src))
A.updatetype()
A.try_recharge()
A.pin = null
@@ -303,7 +303,7 @@
accuracy = -1
icon_state = "rotating_lens"
increasable_stats = list()
decreaseable_stats = list("fire_delay", "chargetime")
decreaseable_stats = list("burst_delay", "chargetime")
/obj/item/laser_components/modifier/scope
name = "telescopic sight"
+10 -2
View File
@@ -23,6 +23,13 @@
var/mob/living/carbon/human/H = user
if(default_deconstruction_screwdriver(user, attacking_item))
return TRUE
if(default_deconstruction_crowbar(user, attacking_item))
return TRUE
if(default_part_replacement(user, attacking_item))
return TRUE
if(istype(attacking_item, /obj/item/gun))
check_swap(user, attacking_item)
item = attacking_item
@@ -55,7 +62,8 @@
addtimer(CALLBACK(src, PROC_REF(reset)), 15)
process = TRUE
update_icon()
else if(istype(attacking_item, /obj/item/combitool))
return
else if(attacking_item)
check_swap(user, attacking_item)
item = attacking_item
@@ -120,7 +128,7 @@
if(istype(item, /obj/item/laser_assembly))
var/obj/item/laser_assembly/A = item
A.update_icon()
icon_state = process ? "[icon_state]_working" : "[icon_state]_on"
icon_state = process ? "[icon_state]_working" : "[icon_state]_on"
Icon_used = new /icon(item.icon, item.icon_state)
else if(item)
icon_state = "[icon_state]_on"