diff --git a/code/modules/ai/_defines.dm b/code/modules/ai/_defines.dm index e94d26b3c3..7b49f18ddb 100644 --- a/code/modules/ai/_defines.dm +++ b/code/modules/ai/_defines.dm @@ -20,6 +20,11 @@ #define MOVEMENT_FAILED 0 // Move() returned false for whatever reason and the mob didn't move. #define MOVEMENT_SUCCESSFUL 1 // Move() returned true and the mob hopefully moved. +// Results of pre-attack checks +#define ATTACK_ON_COOLDOWN -1 // Recently attacked and needs to try again soon. +#define ATTACK_FAILED 0 // Something else went wrong! Maybe they moved away! +#define ATTACK_SUCCESSFUL 1 // We attacked (or tried to, misses count too) + // Reasons for targets to not be valid. Based on why, the AI responds differently. #define AI_TARGET_VALID 0 // We can fight them. #define AI_TARGET_INVIS 1 // They were in field of view but became invisible. Switch to STANCE_BLINDFIGHT if no other viable targets exist. diff --git a/code/modules/ai/ai_holder_combat.dm b/code/modules/ai/ai_holder_combat.dm index 65fd1785b1..a56f03777d 100644 --- a/code/modules/ai/ai_holder_combat.dm +++ b/code/modules/ai/ai_holder_combat.dm @@ -70,21 +70,21 @@ /datum/ai_holder/proc/melee_attack(atom/A) pre_melee_attack(A) . = holder.IAttack(A) - if(.) + if(. == ATTACK_SUCCESSFUL) post_melee_attack(A) // Ditto. /datum/ai_holder/proc/ranged_attack(atom/A) pre_ranged_attack(A) . = holder.IRangedAttack(A) - if(.) + if(. == ATTACK_SUCCESSFUL) post_ranged_attack(A) // Most mobs probably won't have this defined but we don't care. /datum/ai_holder/proc/special_attack(atom/movable/AM) pre_special_attack(AM) . = holder.ISpecialAttack(AM) - if(.) + if(. == ATTACK_SUCCESSFUL) post_special_attack(AM) // Called when within striking/shooting distance, however cooldown is not considered. @@ -218,7 +218,6 @@ var/dir_to_target = get_dir(holder, target_atom) holder.face_atom(target_atom) - ai_log("breakthrough() : Exiting", AI_LOG_DEBUG) // Sometimes the mob will try to hit something diagonally, and generally this fails. // So instead we will try two more times with some adjustments if the attack fails. @@ -274,31 +273,31 @@ for(var/obj/structure/window/W in problem_turf) if(W.dir == reverse_dir[holder.dir]) // So that windows get smashed in the right order ai_log("destroy_surroundings() : Attacking side window.", AI_LOG_INFO) - return holder.IAttack(W) + return melee_attack(W) else if(W.is_fulltile()) ai_log("destroy_surroundings() : Attacking full tile window.", AI_LOG_INFO) - return holder.IAttack(W) + return melee_attack(W) // Kill hull shields in the way. for(var/obj/effect/energy_field/shield in problem_turf) if(shield.density) // Don't attack shields that are already down. ai_log("destroy_surroundings() : Attacking hull shield.", AI_LOG_INFO) - return holder.IAttack(shield) + return melee_attack(shield) // Kill common obstacle in the way like tables. var/obj/structure/obstacle = locate(/obj/structure, problem_turf) if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille)) ai_log("destroy_surroundings() : Attacking generic structure.", AI_LOG_INFO) - return holder.IAttack(obstacle) + return melee_attack(obstacle) for(var/obj/machinery/door/D in problem_turf) // Required since firelocks take up the same turf. if(D.density) ai_log("destroy_surroundings() : Attacking closed door.", AI_LOG_INFO) - return holder.IAttack(D) + return melee_attack(D) ai_log("destroy_surroundings() : Exiting due to nothing to attack.", AI_LOG_INFO) - return FALSE // Nothing to attack. + return ATTACK_FAILED // Nothing to attack. // Override for special behaviour. /datum/ai_holder/proc/can_violently_breakthrough() diff --git a/code/modules/ai/ai_holder_movement.dm b/code/modules/ai/ai_holder_movement.dm index 58b8c9d5ee..4ba8003ade 100644 --- a/code/modules/ai/ai_holder_movement.dm +++ b/code/modules/ai/ai_holder_movement.dm @@ -16,6 +16,8 @@ var/base_wander_delay = 2 // What the above var gets set to when it wanders. Note that a tick happens every half a second. var/wander_when_pulled = FALSE // If the mob will refrain from wandering if someone is pulling it. + // Breakthrough + var/failed_breakthroughs = 0 // How many times we've failed to breakthrough something lately /datum/ai_holder/proc/walk_to_destination() ai_log("walk_to_destination() : Entering.",AI_LOG_TRACE) @@ -90,7 +92,9 @@ // step_to(holder, A) if(holder.IMove(get_step_to(holder, A)) == MOVEMENT_FAILED) ai_log("walk_path() : Failed to move, attempting breakthrough.", AI_LOG_INFO) - breakthrough(A) // We failed to move, time to smash things. + if(!breakthrough(A) && failed_breakthroughs++ >= 5) // We failed to move, time to smash things. + give_up_movement() + failed_breakthroughs = 0 return if(move_once() == FALSE) // Start walking the path. @@ -106,7 +110,9 @@ ai_log("walk_path() : Going to IMove().", AI_LOG_TRACE) if(holder.IMove(get_step_to(holder, A)) == MOVEMENT_FAILED ) ai_log("walk_path() : Failed to move, attempting breakthrough.", AI_LOG_INFO) - breakthrough(A) // We failed to move, time to smash things. + if(!breakthrough(A) && failed_breakthroughs++ >= 5) // We failed to move, time to smash things. + give_up_movement() + failed_breakthroughs = 0 ai_log("walk_path() : Exited.", AI_LOG_TRACE) diff --git a/code/modules/ai/interfaces.dm b/code/modules/ai/interfaces.dm index 59ffbeea72..b4323782d3 100644 --- a/code/modules/ai/interfaces.dm +++ b/code/modules/ai/interfaces.dm @@ -8,7 +8,7 @@ /mob/living/simple_mob/IAttack(atom/A) if(!canClick()) // Still on cooldown from a "click". - return FALSE + return ATTACK_ON_COOLDOWN return attack_target(A) // This will set click cooldown. /mob/living/proc/IRangedAttack(atom/A) @@ -16,7 +16,7 @@ /mob/living/simple_mob/IRangedAttack(atom/A) if(!canClick()) // Still on cooldown from a "click". - return FALSE + return ATTACK_ON_COOLDOWN return shoot_target(A) // Test if the AI is allowed to attempt a ranged attack. diff --git a/code/modules/mob/_modifiers/fire.dm b/code/modules/mob/_modifiers/fire.dm index 7f0cb81c4c..3a3c53a9dc 100644 --- a/code/modules/mob/_modifiers/fire.dm +++ b/code/modules/mob/_modifiers/fire.dm @@ -32,8 +32,11 @@ expire() else if(holder.fire_stacks > 0) - holder.fire_stacks -= 1 + holder.fire_stacks -= 0.5 /datum/modifier/fire/stack_managed/intense mob_overlay_state = "on_fire_intense" damage_per_tick = 10 + +/datum/modifier/fire/stack_managed/weak + damage_per_tick = 1 diff --git a/code/modules/mob/living/carbon/human/human_resist.dm b/code/modules/mob/living/carbon/human/human_resist.dm index 37e20d0d21..56d42c1a15 100644 --- a/code/modules/mob/living/carbon/human/human_resist.dm +++ b/code/modules/mob/living/carbon/human/human_resist.dm @@ -1,6 +1,6 @@ /mob/living/carbon/human/process_resist() //drop && roll - if(on_fire && !buckled) + if((on_fire || has_modifier_of_type(/datum/modifier/fire)) && !buckled) adjust_fire_stacks(-1.2) Weaken(3) spin(32,2) @@ -9,7 +9,7 @@ "You stop, drop, and roll!" ) sleep(30) - if(fire_stacks <= 0) + if(fire_stacks <= 0 && !(has_modifier_of_type(/datum/modifier/fire))) visible_message( "[src] has successfully extinguished themselves!", "You extinguish yourself." diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index d53d307e76..0184a54d59 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -363,6 +363,9 @@ handle_light() update_fire() + if(has_modifier_of_type(/datum/modifier/fire)) + remove_modifiers_of_type(/datum/modifier/fire) + /mob/living/proc/update_fire() return diff --git a/code/modules/mob/living/simple_mob/combat.dm b/code/modules/mob/living/simple_mob/combat.dm index 0f3205fb8c..046a4ef988 100644 --- a/code/modules/mob/living/simple_mob/combat.dm +++ b/code/modules/mob/living/simple_mob/combat.dm @@ -3,26 +3,24 @@ set waitfor = FALSE // For attack animations. Don't want the AI processor to get held up. if(!A.Adjacent(src)) - return FALSE + return ATTACK_FAILED var/turf/their_T = get_turf(A) face_atom(A) if(melee_attack_delay) - // their_T.color = "#FF0000" melee_pre_animation(A) + . = ATTACK_SUCCESSFUL //Shoving this in here as a 'best guess' since this proc is about to sleep and return and we won't be able to know the real value handle_attack_delay(A, melee_attack_delay) // This will sleep this proc for a bit, which is why waitfor is false. // Cooldown testing is done at click code (for players) and interface code (for AI). setClickCooldown(get_attack_speed()) + // Returns a value, but will be lost if . = do_attack(A, their_T) if(melee_attack_delay) melee_post_animation(A) - // their_T.color = "#FFFFFF" - - // This does the actual attack. // This is a seperate proc for the purposes of attack animations. diff --git a/code/modules/projectiles/guns/magnetic/gasthrower.dm b/code/modules/projectiles/guns/magnetic/gasthrower.dm index f42ae95061..742b5bd6c5 100644 --- a/code/modules/projectiles/guns/magnetic/gasthrower.dm +++ b/code/modules/projectiles/guns/magnetic/gasthrower.dm @@ -9,6 +9,7 @@ one_handed_penalty = 20 origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 4, TECH_ILLEGAL = 2, TECH_PHORON = 4) w_class = ITEMSIZE_LARGE + slowdown = 1 burst = 3 burst_delay = 1 diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 06144e01f8..e05739d194 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -271,10 +271,11 @@ /obj/item/projectile/bullet/incendiary/flamethrower/tiny damage = 2 incendiary = 0 - modifier_type_to_apply = /datum/modifier/fire/weak + flammability = 2 + modifier_type_to_apply = /datum/modifier/fire/stack_managed/weak modifier_duration = 20 SECONDS - range = 7 - agony = 3 + range = 6 + agony = 0 /* Practice rounds and blanks */ diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm index ed68723d15..c2ff36ea10 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -175,10 +175,10 @@ S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") // Then extinguish people on fire. - var/needed = L.fire_stacks * 5 + var/needed = max(0,L.fire_stacks) * 5 if(amount > needed) L.ExtinguishMob() - L.adjust_fire_stacks(-(amount / 5)) + L.water_act(amount / 25) // Div by 25, as water_act multiplies it by 5 in order to calculate firestack modification. remove_self(needed) /* //VOREStation Edit Start. Stops slimes from dying from water. Fixes fuel affect_ingest, too. /datum/reagent/water/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) diff --git a/icons/obj/pda_holo.dmi b/icons/obj/pda_holo.dmi index add15b941f..4e92a6d6d9 100644 Binary files a/icons/obj/pda_holo.dmi and b/icons/obj/pda_holo.dmi differ