mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 @@
|
||||
"<span class='notice'>You stop, drop, and roll!</span>"
|
||||
)
|
||||
sleep(30)
|
||||
if(fire_stacks <= 0)
|
||||
if(fire_stacks <= 0 && !(has_modifier_of_type(/datum/modifier/fire)))
|
||||
visible_message(
|
||||
"<span class='danger'>[src] has successfully extinguished themselves!</span>",
|
||||
"<span class='notice'>You extinguish yourself.</span>"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -175,10 +175,10 @@
|
||||
S.visible_message("<span class='warning'>[S]'s flesh sizzles where the water touches it!</span>", "<span class='danger'>Your flesh burns in the water!</span>")
|
||||
|
||||
// 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)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 7.0 KiB |
Reference in New Issue
Block a user