Files
Paradise/code/modules/mob/mob_grab.dm
Tigercat2000 e3b3daba49 Mob grab/eating refactor
This refactors the mob-eat-mob code and fixes a few bugs along the way.
- Bursting out of a stomach now has a 0.4 second delay between attacks,
  so the message cannot be spammed.

- The list of mobs that can eat other mobs has been refactored to be a
  subproc instead of a 255char~ list on one line.

- Mob grab uses #defines for the time it takes to eat something else,
  now.

- Fixed xenomorphs bugging out the grab system, and made sure that fat
  people can't actually eat them because of this.
2015-05-02 04:40:46 -07:00

250 lines
8.1 KiB
Plaintext

#define UPGRADE_COOLDOWN 40
#define UPGRADE_KILL_TIMER 100
//times it takes for a mob to eat
#define EAT_TIME_XENO 30
#define EAT_TIME_FAT 100
//time it takes for a mob to be eaten (in deciseconds) (overrides mob eat time)
#define EAT_TIME_MOUSE 30
/obj/item/weapon/grab
name = "grab"
flags = NOBLUDGEON | ABSTRACT
var/obj/screen/grab/hud = null
var/mob/affecting = null
var/mob/assailant = null
var/state = GRAB_PASSIVE
var/allow_upgrade = 1
var/last_upgrade = 0
layer = 21
item_state = "nothing"
w_class = 5.0
/obj/item/weapon/grab/New(mob/user, mob/victim)
..()
loc = user
assailant = user
affecting = victim
if(affecting.anchored)
del(src)
return
hud = new /obj/screen/grab(src)
hud.icon_state = "reinforce"
hud.name = "reinforce grab"
hud.master = src
//Used by throw code to hand over the mob, instead of throwing the grab. The grab is then deleted by the throw code.
/obj/item/weapon/grab/proc/throw()
if(affecting)
if(affecting.buckled)
return null
if(state >= GRAB_AGGRESSIVE)
return affecting
return null
//This makes sure that the grab screen object is displayed in the correct hand.
/obj/item/weapon/grab/proc/synch()
if(affecting)
if(assailant.r_hand == src)
hud.screen_loc = ui_rhand
else
hud.screen_loc = ui_lhand
/obj/item/weapon/grab/process()
confirm()
if(assailant.client)
assailant.client.screen -= hud
assailant.client.screen += hud
if(assailant.pulling == affecting)
assailant.stop_pulling()
if(state <= GRAB_AGGRESSIVE)
allow_upgrade = 1
if((assailant.l_hand && assailant.l_hand != src && istype(assailant.l_hand, /obj/item/weapon/grab)))
var/obj/item/weapon/grab/G = assailant.l_hand
if(G.affecting != affecting)
allow_upgrade = 0
if((assailant.r_hand && assailant.r_hand != src && istype(assailant.r_hand, /obj/item/weapon/grab)))
var/obj/item/weapon/grab/G = assailant.r_hand
if(G.affecting != affecting)
allow_upgrade = 0
if(state == GRAB_AGGRESSIVE)
var/h = affecting.hand
affecting.hand = 0
affecting.drop_item()
affecting.hand = 1
affecting.drop_item()
affecting.hand = h
for(var/obj/item/weapon/grab/G in affecting.grabbed_by)
if(G == src) continue
if(G.state == GRAB_AGGRESSIVE)
allow_upgrade = 0
if(allow_upgrade)
hud.icon_state = "reinforce"
else
hud.icon_state = "!reinforce"
else
if(!affecting.buckled)
affecting.loc = assailant.loc
if(state >= GRAB_NECK)
affecting.Stun(5) //It will hamper your voice, being choked and all.
if(isliving(affecting))
var/mob/living/L = affecting
L.adjustOxyLoss(1)
if(state >= GRAB_KILL)
affecting.Weaken(5) //Should keep you down unless you get help.
affecting.losebreath = min(affecting.losebreath + 2, 3)
/obj/item/weapon/grab/attack_self(mob/user)
s_click(hud)
/obj/item/weapon/grab/proc/s_click(obj/screen/S)
if(!affecting)
return
if(state == GRAB_UPGRADING)
return
if(assailant.next_move > world.time)
return
if(world.time < (last_upgrade + UPGRADE_COOLDOWN))
return
if(!assailant.canmove || assailant.lying)
del(src)
return
last_upgrade = world.time
if(state < GRAB_AGGRESSIVE)
if(!allow_upgrade)
return
assailant.visible_message("<span class='warning'>[assailant] has grabbed [affecting] aggressively (now hands)!</span>")
state = GRAB_AGGRESSIVE
icon_state = "grabbed1"
else
if(state < GRAB_NECK)
if(isslime(affecting))
assailant << "<span class='notice'>You squeeze [affecting], but nothing interesting happens.</span>"
return
assailant.visible_message("<span class='warning'>[assailant] has reinforced \his grip on [affecting] (now neck)!</span>")
state = GRAB_NECK
icon_state = "grabbed+1"
if(!affecting.buckled)
affecting.loc = assailant.loc
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their neck grabbed by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Grabbed the neck of [affecting.name] ([affecting.ckey])</font>"
log_attack("<font color='red'>[assailant.name] ([assailant.ckey]) grabbed the neck of [affecting.name] ([affecting.ckey])</font>")
if(!iscarbon(assailant))
affecting.LAssailant = null
else
affecting.LAssailant = assailant
hud.icon_state = "disarm/kill"
hud.name = "disarm/kill"
else
if(state < GRAB_UPGRADING)
assailant.visible_message("<span class='danger'>[assailant] starts to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill1"
state = GRAB_UPGRADING
if(do_after(assailant, UPGRADE_KILL_TIMER))
if(state == GRAB_KILL)
return
if(!affecting)
del(src)
return
if(!assailant.canmove || assailant.lying)
del(src)
return
state = GRAB_KILL
assailant.visible_message("<span class='danger'>[assailant] has tightened \his grip on [affecting]'s neck!</span>")
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>"
log_attack("<font color='red'>[assailant.name] ([assailant.ckey]) Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>")
if(!iscarbon(assailant))
affecting.LAssailant = null
else
affecting.LAssailant = assailant
assailant.changeNext_move(CLICK_CD_TKSTRANGLE)
affecting.losebreath += 1
else
assailant.visible_message("<span class='warning'>[assailant] was unable to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill"
state = GRAB_NECK
//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.
/obj/item/weapon/grab/proc/confirm()
if(!assailant || !affecting)
del(src)
return 0
if(affecting)
if(!isturf(assailant.loc) || ( !isturf(affecting.loc) || assailant.loc != affecting.loc && get_dist(assailant, affecting) > 1) )
del(src)
return 0
return 1
/obj/item/weapon/grab/attack(mob/M, mob/user)
if(!affecting)
return
if(M == affecting) //what the actual fuck is this
s_click(hud)
return
if(M == assailant && state >= GRAB_AGGRESSIVE) //no eatin unless you have an agressive grab
if(checkvalid(user, affecting)) //wut
var/mob/living/carbon/attacker = user
user.visible_message("<span class='danger'>[user] is attempting to devour \the [affecting]!</span>")
if(!do_mob(user, affecting) || !do_after(user, checktime(user, affecting))) return
user.visible_message("<span class='danger'>[user] devours \the [affecting]!</span>")
affecting.loc = user //add the mob to the user
attacker.stomach_contents.Add(affecting) //list keeping
del(src)
/obj/item/weapon/grab/proc/checkvalid(var/mob/attacker, var/mob/prey) //does all the checking for the attack proc to see if a mob can eat another with the grab
if(ishuman(attacker) && (FAT in attacker.mutations) && iscarbon(prey)) //Fat people eating carbon mobs
return 1
if(isalien(attacker) && iscarbon(prey)) //Xenomorphs eating carbon mobs
return 1
if(ishuman(attacker) && attacker.get_species() == "Kidan" && istype(prey,/mob/living/carbon/monkey/diona)) //Kidan eating nymphs
return 1
if(ishuman(attacker) && attacker.get_species() == "Tajaran" && istype(prey,/mob/living/simple_animal/mouse)) //Tajaran eating mice. Meow!
return 1
return 0
/obj/item/weapon/grab/proc/checktime(var/mob/attacker, var/mob/prey) //Returns the time the attacker has to wait before they eat the prey
if(isalien(attacker))
return EAT_TIME_XENO //xenos get a speed boost
if(istype(prey,/mob/living/simple_animal/mouse)) //mice get eaten at xeno-eating-speed regardless
return EAT_TIME_MOUSE
return EAT_TIME_FAT //if it doesn't fit into the above, it's probably a fat guy, take EAT_TIME_FAT to do it
/obj/item/weapon/grab/dropped()
del(src)
/obj/item/weapon/grab/Destroy()
del(hud)
..()
#undef EAT_TIME_XENO
#undef EAT_TIME_FAT
#undef EAT_TIME_MOUSE