diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 79e7beb87c..eff4517984 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -201,20 +201,22 @@ L.resist() if("mov_intent") - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - if(C.legcuffed) - C << "You are legcuffed! You cannot run until you get [C.legcuffed] removed!" - C.m_intent = "walk" //Just incase - C.hud_used.move_intent.icon_state = "walking" - return 1 - switch(usr.m_intent) + if(isliving(usr)) + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + if(C.legcuffed) + C << "You are legcuffed! You cannot run until you get [C.legcuffed] removed!" + C.m_intent = "walk" //Just incase + C.hud_used.move_intent.icon_state = "walking" + return 1 + var/mob/living/L = usr + switch(L.m_intent) if("run") - usr.m_intent = "walk" - usr.hud_used.move_intent.icon_state = "walking" + L.m_intent = "walk" + L.hud_used.move_intent.icon_state = "walking" if("walk") - usr.m_intent = "run" - usr.hud_used.move_intent.icon_state = "running" + L.m_intent = "run" + L.hud_used.move_intent.icon_state = "running" if("m_intent") if(!usr.m_int) switch(usr.m_intent) @@ -486,7 +488,7 @@ var/mob/living/silicon/ai/AI = usr AI.view_images() else - return 0 + return attempt_vr(src,"Click_vr",list(location,control,params)) //VOREStation Add - Additional things. return 1 /obj/screen/inventory/Click() diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index a80ff05eac..e2a4c28c6b 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -73,27 +73,38 @@ Animals */ /mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity) - if(!..()) - return - - if(prob(spattack_prob)) - if(spattack_min_range <= 1) - target_mob = A - SpecialAtkTarget() - target_mob = null - return - - if(melee_damage_upper == 0 && istype(A,/mob/living)) - custom_emote(1,"[friendly] [A]!") + if(!(. = ..())) return setClickCooldown(get_attack_speed()) - if(isliving(A)) - target_mob = A - PunchTarget() - target_mob = null - else - A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext) + + if(has_hands && istype(A,/obj) && a_intent != I_HURT) + var/obj/O = A + return O.attack_hand(src) + + switch(a_intent) + if(I_HELP) + if(isliving(A)) + custom_emote(1,"[pick(friendly)] [A]!") + + if(I_HURT) + if(prob(spattack_prob)) + if(spattack_min_range <= 1) + SpecialAtkTarget() + + else if(melee_damage_upper == 0 && istype(A,/mob/living)) + custom_emote(1,"[pick(friendly)] [A]!") + + else + DoPunch(A) + + if(I_GRAB) + if(has_hands) + A.attack_hand(src) + + if(I_DISARM) + if(has_hands) + A.attack_hand(src) /mob/living/simple_animal/RangedAttack(var/atom/A) setClickCooldown(get_attack_speed()) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index eb29aaff41..c95f0ac49e 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -52,7 +52,7 @@ if(!canremove) return - if (ishuman(usr) || issmall(usr)) //so monkeys can take off their backpacks -- Urist + if (ishuman(usr) || issmall(usr) || isanimal(usr)) //so monkeys can take off their backpacks -- Urist if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech. why? return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 54551db698..9846c4f109 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -137,33 +137,6 @@ return shock_damage -/mob/proc/swap_hand() - return - -/mob/living/carbon/swap_hand() - src.hand = !( src.hand ) - if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) - if(hand) //This being 1 means the left hand is in use - hud_used.l_hand_hud_object.icon_state = "l_hand_active" - hud_used.r_hand_hud_object.icon_state = "r_hand_inactive" - else - hud_used.l_hand_hud_object.icon_state = "l_hand_inactive" - hud_used.r_hand_hud_object.icon_state = "r_hand_active" - return - -/mob/living/carbon/proc/activate_hand(var/selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand. - - if(istext(selhand)) - selhand = lowertext(selhand) - - if(selhand == "right" || selhand == "r") - selhand = 0 - if(selhand == "left" || selhand == "l") - selhand = 1 - - if(selhand != src.hand) - swap_hand() - /mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) if (src.health >= config.health_threshold_crit) if(src == M && istype(src, /mob/living/carbon/human)) @@ -321,62 +294,6 @@ update_icons_layers(FALSE) //apply the now updated overlays to the mob update_icons_body() -//Throwing stuff -/mob/proc/throw_item(atom/target) - return - -/mob/living/carbon/throw_item(atom/target) - src.throw_mode_off() - if(usr.stat || !target) - return - if(target.type == /obj/screen) return - - var/atom/movable/item = src.get_active_hand() - - if(!item) return - - var/throw_range = item.throw_range - if (istype(item, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/G = item - item = G.throw_held() //throw the person instead of the grab - if(ismob(item)) - var/mob/M = item - - //limit throw range by relative mob size - throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1)) - - var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors - var/turf/end_T = get_turf(target) - if(start_T && end_T) - var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]" - var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]" - - M.attack_log += text("\[[time_stamp()]\] Has been thrown by [usr.name] ([usr.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") - usr.attack_log += text("\[[time_stamp()]\] Has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") - msg_admin_attack("[usr.name] ([usr.ckey]) has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor] (JMP)") - - src.drop_from_inventory(item) - if(!item || !isturf(item.loc)) - return - - //actually throw it! - src.visible_message("[src] has thrown [item].") - - if(!src.lastarea) - src.lastarea = get_area(src.loc) - if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0)) - src.inertia_dir = get_dir(target, src) - step(src, inertia_dir) - - -/* - if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction - src.inertia_dir = get_dir(target, src) - step(src, inertia_dir) -*/ - - - item.throw_at(target, throw_range, item.throw_speed, src) /mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) ..() diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 7acb587fbd..7d15678bb1 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -17,7 +17,7 @@ return u_attack return null -/mob/living/carbon/human/attack_hand(mob/living/carbon/M as mob) +/mob/living/carbon/human/attack_hand(mob/living/M as mob) var/datum/gender/TT = gender_datums[M.get_visible_gender()] var/mob/living/carbon/human/H = M if(istype(H)) @@ -27,7 +27,8 @@ if(!temp || !temp.is_usable()) H << "You can't use your hand." return - H.break_cloak() + M.break_cloak() + ..() // Should this all be in Touch()? @@ -73,7 +74,8 @@ return if(istype(M,/mob/living/carbon)) - M.spread_disease_to(src, "Contact") + var/mob/living/carbon/C = M + C.spread_disease_to(src, "Contact") switch(M.a_intent) if(I_HELP) @@ -419,7 +421,7 @@ return 0 var/datum/gender/TU = gender_datums[user.get_visible_gender()] - + if(user == src) user.visible_message("\The [user] starts applying pressure to [TU.his] [organ.name]!", "You start applying pressure to your [organ.name]!") else diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 440489f568..50b529768d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1132,3 +1132,79 @@ default behaviour is: else // No colors, so remove the client's color. animate(client, color = null, time = 10) +/mob/living/swap_hand() + src.hand = !( src.hand ) + if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) + if(hand) //This being 1 means the left hand is in use + hud_used.l_hand_hud_object.icon_state = "l_hand_active" + hud_used.r_hand_hud_object.icon_state = "r_hand_inactive" + else + hud_used.l_hand_hud_object.icon_state = "l_hand_inactive" + hud_used.r_hand_hud_object.icon_state = "r_hand_active" + return + +/mob/living/proc/activate_hand(var/selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand. + + if(istext(selhand)) + selhand = lowertext(selhand) + + if(selhand == "right" || selhand == "r") + selhand = 0 + if(selhand == "left" || selhand == "l") + selhand = 1 + + if(selhand != src.hand) + swap_hand() + +/mob/living/throw_item(atom/target) + src.throw_mode_off() + if(usr.stat || !target) + return + if(target.type == /obj/screen) return + + var/atom/movable/item = src.get_active_hand() + + if(!item) return + + var/throw_range = item.throw_range + if (istype(item, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = item + item = G.throw_held() //throw the person instead of the grab + if(ismob(item)) + var/mob/M = item + + //limit throw range by relative mob size + throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1)) + + var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors + var/turf/end_T = get_turf(target) + if(start_T && end_T) + var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]" + var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]" + + M.attack_log += text("\[[time_stamp()]\] Has been thrown by [usr.name] ([usr.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") + usr.attack_log += text("\[[time_stamp()]\] Has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") + msg_admin_attack("[usr.name] ([usr.ckey]) has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor] (JMP)") + + src.drop_from_inventory(item) + if(!item || !isturf(item.loc)) + return + + //actually throw it! + src.visible_message("[src] has thrown [item].") + + if(!src.lastarea) + src.lastarea = get_area(src.loc) + if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0)) + src.inertia_dir = get_dir(target, src) + step(src, inertia_dir) + + +/* + if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction + src.inertia_dir = get_dir(target, src) + step(src, inertia_dir) +*/ + + + item.throw_at(target, throw_range, item.throw_speed, src) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 43d157da71..42f5f4b535 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -16,6 +16,12 @@ //Settings for played mobs var/show_stat_health = 1 // Does the percentage health show in the stat panel for the mob var/ai_inactive = 0 // Set to 1 to turn off most AI actions + var/has_hands = 0 // Set to 1 to enable the use of hands and the hands hud + var/list/hud_gears // Slots to show on the hud (typically none) + var/ui_icons // Icon file path to use for the HUD, otherwise generic icons are used + var/r_hand_sprite // If they have hands, + var/l_hand_sprite // they could use some icons. + var/player_msg // Message to print to players about 'how' to play this mob on login. //Mob icon/appearance settings var/icon_living = "" // The iconstate if we're alive, required @@ -71,7 +77,7 @@ var/cold_damage_per_tick = 2 // Same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp var/fire_alert = 0 // 0 = fine, 1 = hot, 2 = cold - var/min_oxy = 5 // Oxygen in moles, minimum, 0 is 'no minimum + var/min_oxy = 5 // Oxygen in moles, minimum, 0 is 'no minimum' var/max_oxy = 0 // Oxygen in moles, maximum, 0 is 'no maximum' var/min_tox = 0 // Phoron min var/max_tox = 1 // Phoron max @@ -171,6 +177,7 @@ home_turf = get_turf(src) path_overlay = new(path_icon,path_icon_state) move_to_delay = max(2,move_to_delay) //Protection against people coding things incorrectly and A* pathing 100% of the time + maxHealth = health for(var/L in has_langs) languages |= all_languages[L] @@ -209,21 +216,17 @@ //Client attached /mob/living/simple_animal/Login() - if(src && src.client) - src.client.screen = list() - src.client.screen += src.client.void - ai_inactive = 1 - handle_stance(STANCE_IDLE) - LoseTarget() - src.client << "Mob AI disabled while you are controlling the mob." - ..() + . = ..() + ai_inactive = 1 + handle_stance(STANCE_IDLE) + LoseTarget() + to_chat(src,"Mob AI disabled while you are controlling the mob.
You are \the [src]. [player_msg]") //Client detatched /mob/living/simple_animal/Logout() - if(src && !src.client) - spawn(15 SECONDS) //15 seconds to get back into the mob before it goes wild - if(src && !src.client) - ai_inactive = initial(ai_inactive) //So if they never have an AI, they stay that way. + spawn(15 SECONDS) //15 seconds to get back into the mob before it goes wild + if(src && !src.client) + ai_inactive = initial(ai_inactive) //So if they never have an AI, they stay that way. ..() //For debug purposes! @@ -243,23 +246,74 @@ if(health > getMaxHealth()) health = getMaxHealth() + //Update our hud if we have one + if(healths) + if(stat != DEAD) + var/heal_per = (health / getMaxHealth()) * 100 + switch(heal_per) + if(100 to INFINITY) + healths.icon_state = "health0" + if(80 to 100) + healths.icon_state = "health1" + if(60 to 80) + healths.icon_state = "health2" + if(40 to 60) + healths.icon_state = "health3" + if(20 to 40) + healths.icon_state = "health4" + if(0 to 20) + healths.icon_state = "health5" + else + healths.icon_state = "health6" + else + healths.icon_state = "health7" + + //Updates the nutrition while we're here + if(nutrition_icon) + var/food_per = (nutrition / initial(nutrition)) * 100 + switch(food_per) + if(90 to INFINITY) + nutrition_icon.icon_state = "nutrition0" + if(75 to 90) + nutrition_icon.icon_state = "nutrition1" + if(50 to 75) + nutrition_icon.icon_state = "nutrition2" + if(25 to 50) + nutrition_icon.icon_state = "nutrition3" + if(0 to 25) + nutrition_icon.icon_state = "nutrition4" + /mob/living/simple_animal/update_icon() - ..() + . = ..() + var/mutable_appearance/ma = new(src) + ma.layer = layer + ma.plane = plane + + ma.overlays = list(modifier_overlay) + //Awake and normal if((stat == CONSCIOUS) && (!icon_rest || !resting || !incapacitated(INCAPACITATION_DISABLED) )) - icon_state = icon_living + ma.icon_state = icon_living //Dead else if(stat >= DEAD) - icon_state = icon_dead + ma.icon_state = icon_dead //Resting or KO'd else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest) - icon_state = icon_rest + ma.icon_state = icon_rest //Backup else - icon_state = initial(icon_state) + ma.icon_state = initial(icon_state) + + if(has_hands) + if(r_hand_sprite) + ma.overlays += r_hand_sprite + if(l_hand_sprite) + ma.overlays += l_hand_sprite + + appearance = ma // If your simple mob's update_icon() call calls overlays.Cut(), this needs to be called after this, or manually apply modifier_overly to overlays. /mob/living/simple_animal/update_modifier_visuals() @@ -300,7 +354,6 @@ handle_paralysed() handle_supernatural() handle_atmos() //Atmos - update_icon() ai_log("Life() - stance=[stance] ai_inactive=[ai_inactive]", 4) @@ -325,7 +378,7 @@ if(istype(loc,/obj/structure/closet)) var/obj/structure/closet/C = loc if(C.welded) - resist() + handle_resist() else C.open() @@ -398,7 +451,7 @@ // Handle interacting with and taking damage from atmos // TODO - Refactor this to use handle_environment() like a good /mob/living /mob/living/simple_animal/proc/handle_atmos() - var/atmos_suitable = 1 + var/atmos_unsuitable = 0 var/atom/A = src.loc @@ -414,41 +467,52 @@ if(min_oxy) if(Environment.gas["oxygen"] < min_oxy) - atmos_suitable = 0 + atmos_unsuitable = 1 if(max_oxy) if(Environment.gas["oxygen"] > max_oxy) - atmos_suitable = 0 + atmos_unsuitable = 1 if(min_tox) if(Environment.gas["phoron"] < min_tox) - atmos_suitable = 0 + atmos_unsuitable = 2 if(max_tox) if(Environment.gas["phoron"] > max_tox) - atmos_suitable = 0 + atmos_unsuitable = 2 if(min_n2) if(Environment.gas["nitrogen"] < min_n2) - atmos_suitable = 0 + atmos_unsuitable = 1 if(max_n2) if(Environment.gas["nitrogen"] > max_n2) - atmos_suitable = 0 + atmos_unsuitable = 1 if(min_co2) if(Environment.gas["carbon_dioxide"] < min_co2) - atmos_suitable = 0 + atmos_unsuitable = 1 if(max_co2) if(Environment.gas["carbon_dioxide"] > max_co2) - atmos_suitable = 0 + atmos_unsuitable = 1 //Atmos effect if(bodytemperature < minbodytemp) fire_alert = 2 adjustBruteLoss(cold_damage_per_tick) + if(fire) + fire.icon_state = "fire1" else if(bodytemperature > maxbodytemp) fire_alert = 1 adjustBruteLoss(heat_damage_per_tick) + if(fire) + fire.icon_state = "fire2" else fire_alert = 0 + if(fire) + fire.icon_state = "fire0" - if(!atmos_suitable) + if(atmos_unsuitable) adjustBruteLoss(unsuitable_atoms_damage) + if(oxygen) + oxygen.icon_state = "oxy1" + else if(oxygen) + if(oxygen) + oxygen.icon_state = "oxy0" // For setting the stance WITHOUT processing it /mob/living/simple_animal/proc/set_stance(var/new_stance) @@ -518,26 +582,13 @@ custom_emote(2, act_desc) /mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) - if(!Proj) - return ai_log("bullet_act() I was shot by: [Proj.firer]",2) - if(Proj.taser_effect) - stun_effect_act(0, Proj.agony) - - if(!Proj.nodamage) - var/true_damage = Proj.damage - if(!Proj.SA_vulnerability || Proj.SA_vulnerability == intelligence_level) - true_damage += Proj.SA_bonus_damage - adjustBruteLoss(true_damage) + . = ..() if(Proj.firer) react_to_attack(Proj.firer) - Proj.on_hit(src) - - return 0 - // When someone clicks us with an empty hand /mob/living/simple_animal/attack_hand(mob/living/carbon/human/M as mob) ..() @@ -610,24 +661,25 @@ if(O.force) react_to_attack(user) -/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) - visible_message("\The [src] has been attacked with \the [O] by [user].") + return ..() +/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + effective_force = O.force + + //Animals can't be stunned(?) + if(O.damtype == HALLOSS) + effective_force = 0 + if(supernatural && istype(O,/obj/item/weapon/nullrod)) + effective_force *= 2 + purge = 3 if(O.force <= resistance) - user << "This weapon is ineffective, it does no damage." + to_chat(user,"This weapon is ineffective, it does no damage.") return 2 - var/damage = O.force - if (O.damtype == HALLOSS) - damage = 0 - if(supernatural && istype(O,/obj/item/weapon/nullrod)) - damage *= 2 - purge = 3 - adjustBruteLoss(damage) ai_log("hit_with_weapon() I was h_w_weapon'd by: [user]",2) react_to_attack(user) - return 0 + . = ..() // When someone throws something at us /mob/living/simple_animal/hitby(atom/movable/AM) @@ -660,6 +712,9 @@ tally = 1 tally *= purge + if(m_intent == "walk") + tally *= 1.5 + return tally+config.animal_delay /mob/living/simple_animal/Stat() @@ -674,6 +729,7 @@ icon_state = icon_rest else icon_state = icon_living + update_icon() /mob/living/simple_animal/death(gibbed, deathmessage = "dies!") density = 0 //We don't block even if we did before @@ -755,7 +811,6 @@ /mob/living/simple_animal/handle_fire() return - /mob/living/simple_animal/update_fire() return /mob/living/simple_animal/IgniteMob() @@ -765,7 +820,7 @@ //We got hit! Consider hitting them back! /mob/living/simple_animal/proc/react_to_attack(var/mob/living/M) - if(stat || M == target_mob) return //Not if we're dead or already hitting them + if(ai_inactive || stat || M == target_mob) return //Not if we're dead or already hitting them if(M in friends || M.faction == faction) return //I'll overlook it THIS time... ai_log("react_to_attack([M])",1) if(retaliate && set_target(M, 1)) @@ -1204,8 +1259,8 @@ if(prob(melee_miss_chance)) src.attack_log += text("\[[time_stamp()]\] attacked [L.name] ([L.ckey])") L.attack_log += text("\[[time_stamp()]\] was attacked by [src.name] ([src.ckey])") - src.visible_message("[src] misses [L]!") - src.do_attack_animation(src) + visible_message("[src] misses [L]!") + do_attack_animation(src) return L else DoPunch(L) @@ -1217,7 +1272,7 @@ // This is the actual act of 'punching'. Override for special behaviour. /mob/living/simple_animal/proc/DoPunch(var/atom/A) - if(!Adjacent(target_mob)) // They could've moved in the meantime. + if(!Adjacent(A)) // They could've moved in the meantime. return FALSE var/damage_to_do = rand(melee_damage_lower, melee_damage_upper) @@ -1226,16 +1281,14 @@ if(!isnull(M.outgoing_melee_damage_percent)) damage_to_do *= M.outgoing_melee_damage_percent - if(attack_sound) - playsound(src, attack_sound, 75, 1) - // SA attacks can be blocked with shields. if(ishuman(A)) var/mob/living/carbon/human/H = A if(H.check_shields(damage = damage_to_do, damage_source = src, attacker = src, def_zone = null, attack_text = "the attack")) return FALSE - A.attack_generic(src, damage_to_do, pick(attacktext)) + if(A.attack_generic(src, damage_to_do, pick(attacktext)) && attack_sound) + playsound(src, attack_sound, 75, 1) return TRUE //The actual top-level ranged attack proc @@ -1500,10 +1553,134 @@ /mob/living/simple_animal/is_sentient() return intelligence_level != SA_PLANT && intelligence_level != SA_ROBOTIC +// Hand procs for player-controlled SA's +/mob/living/simple_animal/swap_hand() + src.hand = !( src.hand ) + if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) + if(hand) //This being 1 means the left hand is in use + hud_used.l_hand_hud_object.icon_state = "l_hand_active" + hud_used.r_hand_hud_object.icon_state = "r_hand_inactive" + else + hud_used.l_hand_hud_object.icon_state = "l_hand_inactive" + hud_used.r_hand_hud_object.icon_state = "r_hand_active" + return + +/mob/living/simple_animal/put_in_active_hand(var/obj/item/I) + if(!has_hands || !istype(I)) + return + +//Puts the item into our active hand if possible. returns 1 on success. +/mob/living/simple_animal/put_in_active_hand(var/obj/item/W) + if(!has_hands) + return FALSE + return (hand ? put_in_l_hand(W) : put_in_r_hand(W)) + +/mob/living/simple_animal/put_in_l_hand(var/obj/item/W) + if(!..() || l_hand) + return 0 + W.forceMove(src) + l_hand = W + W.equipped(src,slot_l_hand) + W.add_fingerprint(src) + update_inv_l_hand() + return TRUE + +/mob/living/simple_animal/put_in_r_hand(var/obj/item/W) + if(!..() || r_hand) + return 0 + W.forceMove(src) + r_hand = W + W.equipped(src,slot_r_hand) + W.add_fingerprint(src) + update_inv_r_hand() + return TRUE + +/mob/living/simple_animal/update_inv_r_hand() + if(QDESTROYING(src)) + return + + if(r_hand) + r_hand.screen_loc = ui_rhand //TODO + + //determine icon state to use + var/t_state + if(r_hand.item_state_slots && r_hand.item_state_slots[slot_r_hand_str]) + t_state = r_hand.item_state_slots[slot_r_hand_str] + else if(r_hand.item_state) + t_state = r_hand.item_state + else + t_state = r_hand.icon_state + + //determine icon to use + var/icon/t_icon + if(r_hand.item_icons && (slot_r_hand_str in r_hand.item_icons)) + t_icon = r_hand.item_icons[slot_r_hand_str] + else if(r_hand.icon_override) + t_state += "_r" + t_icon = r_hand.icon_override + else + t_icon = INV_R_HAND_DEF_ICON + + //apply color + var/image/standing = image(icon = t_icon, icon_state = t_state) + standing.color = r_hand.color + + r_hand_sprite = standing + + else + r_hand_sprite = null + + update_icon() + +/mob/living/simple_animal/update_inv_l_hand() + if(QDESTROYING(src)) + return + + if(l_hand) + l_hand.screen_loc = ui_lhand //TODO + + //determine icon state to use + var/t_state + if(l_hand.item_state_slots && l_hand.item_state_slots[slot_l_hand_str]) + t_state = l_hand.item_state_slots[slot_l_hand_str] + else if(l_hand.item_state) + t_state = l_hand.item_state + else + t_state = l_hand.icon_state + + //determine icon to use + var/icon/t_icon + if(l_hand.item_icons && (slot_l_hand_str in l_hand.item_icons)) + t_icon = l_hand.item_icons[slot_l_hand_str] + else if(l_hand.icon_override) + t_state += "_l" + t_icon = l_hand.icon_override + else + t_icon = INV_L_HAND_DEF_ICON + + //apply color + var/image/standing = image(icon = t_icon, icon_state = t_state) + standing.color = l_hand.color + + l_hand_sprite = standing + + else + l_hand_sprite = null + + update_icon() + +//Can insert extra huds into the hud holder here. +/mob/living/simple_animal/proc/extra_huds(var/datum/hud/hud,var/icon/ui_style,var/list/hud_elements) + return + +//If they can or cannot use tools/machines/etc +/mob/living/simple_animal/IsAdvancedToolUser() + return has_hands + //Commands, reactions, etc /mob/living/simple_animal/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) ..() - if(reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language)) + if(!ai_inactive && reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language)) var/mob/living/L = speaker if(L.faction == faction) spawn(10) diff --git a/code/modules/mob/living/simple_animal/simple_hud.dm b/code/modules/mob/living/simple_animal/simple_hud.dm new file mode 100644 index 0000000000..72d7bf07a3 --- /dev/null +++ b/code/modules/mob/living/simple_animal/simple_hud.dm @@ -0,0 +1,308 @@ +/mob/living/simple_animal/instantiate_hud(var/datum/hud/hud) + if(!client) + return //Why bother. + + var/ui_style = 'icons/mob/screen1_animal.dmi' + if(ui_icons) + ui_style = ui_icons + + var/ui_color = "#ffffff" + var/ui_alpha = 255 + + var/list/adding = list() + var/list/other = list() + var/list/hotkeybuttons = list() + + hud.adding = adding + hud.other = other + hud.hotkeybuttons = hotkeybuttons + + var/list/hud_elements = list() + var/obj/screen/using + var/obj/screen/inventory/inv_box + + var/has_hidden_gear + if(LAZYLEN(hud_gears)) + for(var/gear_slot in hud_gears) + inv_box = new /obj/screen/inventory() + inv_box.icon = ui_style + inv_box.color = ui_color + inv_box.alpha = ui_alpha + + var/list/slot_data = hud_gears[gear_slot] + inv_box.name = gear_slot + inv_box.screen_loc = slot_data["loc"] + inv_box.slot_id = slot_data["slot"] + inv_box.icon_state = slot_data["state"] + + if(slot_data["dir"]) + inv_box.set_dir(slot_data["dir"]) + + if(slot_data["toggle"]) + other += inv_box + has_hidden_gear = 1 + else + adding += inv_box + + if(has_hidden_gear) + using = new /obj/screen() + using.name = "toggle" + using.icon = ui_style + using.icon_state = "other" + using.screen_loc = ui_inventory + using.hud_layerise() + using.color = ui_color + using.alpha = ui_alpha + adding += using + + //Intent Backdrop + using = new /obj/screen() + using.name = "act_intent" + using.icon = ui_style + using.icon_state = "intent_"+a_intent + using.screen_loc = ui_acti + using.color = ui_color + using.alpha = ui_alpha + hud.adding += using + hud.action_intent = using + + hud_elements |= using + + //Small intent quarters + var/icon/ico + + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height()) + using = new /obj/screen( src ) + using.name = I_HELP + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = LAYER_HUD_ITEM //These sit on the intent box + hud.adding += using + hud.help_intent = using + + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height()) + using = new /obj/screen( src ) + using.name = I_DISARM + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = LAYER_HUD_ITEM + hud.adding += using + hud.disarm_intent = using + + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2) + using = new /obj/screen( src ) + using.name = I_GRAB + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = LAYER_HUD_ITEM + hud.adding += using + hud.grab_intent = using + + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2) + using = new /obj/screen( src ) + using.name = I_HURT + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = LAYER_HUD_ITEM + hud.adding += using + hud.hurt_intent = using + + //Move intent (walk/run) + using = new /obj/screen() + using.name = "mov_intent" + using.icon = ui_style + using.icon_state = (m_intent == "run" ? "running" : "walking") + using.screen_loc = ui_movi + using.color = ui_color + using.alpha = ui_alpha + hud.adding += using + hud.move_intent = using + + //Resist button + using = new /obj/screen() + using.name = "resist" + using.icon = ui_style + using.icon_state = "act_resist" + using.screen_loc = ui_pull_resist + using.color = ui_color + using.alpha = ui_alpha + hud.hotkeybuttons += using + + //Pull button + pullin = new /obj/screen() + pullin.icon = ui_style + pullin.icon_state = "pull0" + pullin.name = "pull" + pullin.screen_loc = ui_pull_resist + hud.hotkeybuttons += pullin + hud_elements |= pullin + + //Health status + healths = new /obj/screen() + healths.icon = ui_style + healths.icon_state = "health0" + healths.name = "health" + healths.screen_loc = ui_health + hud_elements |= healths + + //Oxygen dep icon + oxygen = new /obj/screen() + oxygen.icon = ui_style + oxygen.icon_state = "oxy0" + oxygen.name = "oxygen" + oxygen.screen_loc = ui_oxygen + hud_elements |= oxygen + + //Toxins present icon + toxin = new /obj/screen() + toxin.icon = ui_style + toxin.icon_state = "tox0" + toxin.name = "toxin" + toxin.screen_loc = ui_toxin + hud_elements |= toxin + + //Fire warning + fire = new /obj/screen() + fire.icon = ui_style + fire.icon_state = "fire0" + fire.name = "fire" + fire.screen_loc = ui_fire + hud_elements |= fire + + //Pressure warning + pressure = new /obj/screen() + pressure.icon = ui_style + pressure.icon_state = "pressure0" + pressure.name = "pressure" + pressure.screen_loc = ui_pressure + hud_elements |= pressure + + //Body temp warning + bodytemp = new /obj/screen() + bodytemp.icon = ui_style + bodytemp.icon_state = "temp0" + bodytemp.name = "body temperature" + bodytemp.screen_loc = ui_temp + hud_elements |= bodytemp + + //Nutrition status + nutrition_icon = new /obj/screen() + nutrition_icon.icon = ui_style + nutrition_icon.icon_state = "nutrition0" + nutrition_icon.name = "nutrition" + nutrition_icon.screen_loc = ui_nutrition + hud_elements |= nutrition_icon + + pain = new /obj/screen( null ) + + zone_sel = new /obj/screen/zone_sel( null ) + zone_sel.icon = ui_style + zone_sel.color = ui_color + zone_sel.alpha = ui_alpha + zone_sel.overlays.Cut() + zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[zone_sel.selecting]") + hud_elements |= zone_sel + + //Hand things + if(has_hands) + //Drop button + using = new /obj/screen() + using.name = "drop" + using.icon = ui_style + using.icon_state = "act_drop" + using.screen_loc = ui_drop_throw + using.color = ui_color + using.alpha = ui_alpha + hud.hotkeybuttons += using + + //Equip detail + using = new /obj/screen() + using.name = "equip" + using.icon = ui_style + using.icon_state = "act_equip" + using.screen_loc = ui_equip + using.color = ui_color + using.alpha = ui_alpha + hud.adding += using + + //Hand slots themselves + inv_box = new /obj/screen/inventory/hand() + inv_box.hud = src + inv_box.name = "r_hand" + inv_box.icon = ui_style + inv_box.icon_state = "r_hand_inactive" + if(!hand) //This being 0 or null means the right hand is in use + inv_box.icon_state = "r_hand_active" + inv_box.screen_loc = ui_rhand + inv_box.slot_id = slot_r_hand + inv_box.color = ui_color + inv_box.alpha = ui_alpha + + hud.r_hand_hud_object = inv_box + hud.adding += inv_box + + inv_box = new /obj/screen/inventory/hand() + inv_box.hud = src + inv_box.name = "l_hand" + inv_box.icon = ui_style + inv_box.icon_state = "l_hand_inactive" + if(hand) //This being 1 means the left hand is in use + inv_box.icon_state = "l_hand_active" + inv_box.screen_loc = ui_lhand + inv_box.slot_id = slot_l_hand + inv_box.color = ui_color + inv_box.alpha = ui_alpha + hud.l_hand_hud_object = inv_box + hud.adding += inv_box + + //Swaphand titlebar + using = new /obj/screen/inventory() + using.name = "hand" + using.icon = ui_style + using.icon_state = "hand1" + using.screen_loc = ui_swaphand1 + using.color = ui_color + using.alpha = ui_alpha + hud.adding += using + + using = new /obj/screen/inventory() + using.name = "hand" + using.icon = ui_style + using.icon_state = "hand2" + using.screen_loc = ui_swaphand2 + using.color = ui_color + using.alpha = ui_alpha + hud.adding += using + + //Throw button + throw_icon = new /obj/screen() + throw_icon.icon = ui_style + throw_icon.icon_state = "act_throw_off" + throw_icon.name = "throw" + throw_icon.screen_loc = ui_drop_throw + throw_icon.color = ui_color + throw_icon.alpha = ui_alpha + hud.hotkeybuttons += throw_icon + hud_elements |= throw_icon + + extra_huds(hud,ui_style,hud_elements) + + client.screen = list() + + client.screen += hud_elements + client.screen += adding + hotkeybuttons + client.screen += client.void + + return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 54769eea5b..72cfec9453 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1133,4 +1133,11 @@ mob/proc/yank_out_object() /mob/proc/update_client_color() if(client && client.color) animate(client, color = null, time = 10) - return \ No newline at end of file + return + +/mob/proc/swap_hand() + return + +//Throwing stuff +/mob/proc/throw_item(atom/target) + return diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index cf14862981..1602c8cb47 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -181,6 +181,9 @@ //Updating pixelshift, position and direction //Gets called on process, when the grab gets upgraded or the assailant moves /obj/item/weapon/grab/proc/adjust_position() + if(!affecting) + qdel(src) + return if(affecting.buckled) animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1, LINEAR_EASING) return @@ -236,7 +239,7 @@ if(!assailant.canmove || assailant.lying) qdel(src) return - + var/datum/gender/TU = gender_datums[assailant.get_visible_gender()] last_action = world.time diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0a623059eb..a990e5ae40 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -323,7 +323,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) set name = "a-intent" set hidden = 1 - if(ishuman(src) || isbrain(src) || isslime(src)) + if(isliving(src)) switch(input) if(I_HELP,I_DISARM,I_GRAB,I_HURT) a_intent = input diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 09367dbf95..a64be018fb 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -51,14 +51,14 @@ attack_self() return if(SOUTHWEST) - if(iscarbon(usr)) + if(isliving(usr)) var/mob/living/carbon/C = usr C.toggle_throw_mode() else usr << "This mob type cannot throw items." return if(NORTHWEST) - if(iscarbon(usr)) + if(isliving(usr)) var/mob/living/carbon/C = usr if(!C.get_active_hand()) usr << "You have nothing to drop in your hand." @@ -79,8 +79,9 @@ /client/verb/swap_hand() set hidden = 1 - if(istype(mob, /mob/living/carbon)) - mob:swap_hand() + if(istype(mob, /mob/living)) + var/mob/living/L = mob + L.swap_hand() if(istype(mob,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = mob R.cycle_modules() diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm index 3eab4b967f..ae6e01a249 100644 --- a/code/modules/mob/update_icons.dm +++ b/code/modules/mob/update_icons.dm @@ -5,6 +5,7 @@ return /mob/proc/update_icons() + update_icon() //Ugh. return /mob/proc/update_icons_layers(var/update_icons = TRUE) diff --git a/icons/mob/screen1_animal.dmi b/icons/mob/screen1_animal.dmi new file mode 100644 index 0000000000..51b971a075 Binary files /dev/null and b/icons/mob/screen1_animal.dmi differ diff --git a/vorestation.dme b/vorestation.dme index e809a59984..0601e5aa45 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2075,6 +2075,7 @@ #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\simple_animal_vr.dm" +#include "code\modules\mob\living\simple_animal\simple_hud.dm" #include "code\modules\mob\living\simple_animal\aliens\alien.dm" #include "code\modules\mob\living\simple_animal\aliens\creature.dm" #include "code\modules\mob\living\simple_animal\aliens\drone.dm"