mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-18 18:46:24 +01:00
Merge branch 'master' of https://github.com/PolarisSS13/Polaris into attackcall
This commit is contained in:
@@ -183,6 +183,7 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/overlay_random_map,
|
||||
/client/proc/delete_random_map,
|
||||
/client/proc/show_plant_genes,
|
||||
/client/proc/show_xenobio_genes,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_target,
|
||||
|
||||
@@ -400,7 +400,7 @@
|
||||
"potassium",
|
||||
"plasticide",
|
||||
"mutationtoxin",
|
||||
"amutationtoxin",
|
||||
"docilitytoxin",
|
||||
"inaprovaline",
|
||||
"space_drugs",
|
||||
"paroxetine",
|
||||
|
||||
@@ -57,16 +57,16 @@
|
||||
|
||||
switch(stance)
|
||||
|
||||
if(HOSTILE_STANCE_TIRED)
|
||||
if(STANCE_TIRED)
|
||||
stop_automated_movement = 1
|
||||
stance_step++
|
||||
if(stance_step >= 10) //rests for 10 ticks
|
||||
if(target_mob && target_mob in ListTargets(10))
|
||||
stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
|
||||
stance = STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
|
||||
else
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
stance = STANCE_IDLE
|
||||
|
||||
if(HOSTILE_STANCE_ALERT)
|
||||
if(STANCE_ALERT)
|
||||
stop_automated_movement = 1
|
||||
var/found_mob = 0
|
||||
if(target_mob && target_mob in ListTargets(10))
|
||||
@@ -84,14 +84,14 @@
|
||||
stance_step--
|
||||
|
||||
if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
stance = STANCE_IDLE
|
||||
if(stance_step >= 7) //If we have been staring at a mob for 7 ticks,
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
stance = STANCE_ATTACK
|
||||
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
if(STANCE_ATTACKING)
|
||||
if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
|
||||
custom_emote(1, "is worn out and needs to rest." )
|
||||
stance = HOSTILE_STANCE_TIRED
|
||||
stance = STANCE_TIRED
|
||||
stance_step = 0
|
||||
walk(src, 0) //This stops the bear's walking
|
||||
return
|
||||
@@ -99,15 +99,15 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
|
||||
stance = HOSTILE_STANCE_ALERT
|
||||
if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
|
||||
stance = STANCE_ALERT
|
||||
stance_step = 6
|
||||
target_mob = user
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob)
|
||||
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
|
||||
stance = HOSTILE_STANCE_ALERT
|
||||
if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
|
||||
stance = STANCE_ALERT
|
||||
stance_step = 6
|
||||
target_mob = M
|
||||
..()
|
||||
@@ -119,7 +119,7 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1,"stares alertly at [.]")
|
||||
stance = HOSTILE_STANCE_ALERT
|
||||
stance = STANCE_ALERT
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/LoseTarget()
|
||||
..(5)
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
/mob/living/simple_animal/hostile/giant_spider/Life()
|
||||
..()
|
||||
if(!stat)
|
||||
if(stance == HOSTILE_STANCE_IDLE)
|
||||
if(stance == STANCE_IDLE)
|
||||
//1% chance to skitter madly away
|
||||
if(!busy && prob(1))
|
||||
/*var/list/move_targets = list()
|
||||
@@ -113,7 +113,7 @@
|
||||
/mob/living/simple_animal/hostile/giant_spider/nurse/Life()
|
||||
..()
|
||||
if(!stat)
|
||||
if(stance == HOSTILE_STANCE_IDLE)
|
||||
if(stance == STANCE_IDLE)
|
||||
var/list/can_see = view(src, 10)
|
||||
//30% chance to stop wandering and do something
|
||||
if(!busy && prob(30))
|
||||
|
||||
@@ -1,234 +1,15 @@
|
||||
/mob/living/simple_animal/hostile
|
||||
faction = "hostile"
|
||||
var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior
|
||||
var/mob/living/target_mob
|
||||
var/attack_same = 0
|
||||
var/ranged = 0
|
||||
var/rapid = 0
|
||||
var/projectiletype
|
||||
var/projectilesound
|
||||
var/casingtype
|
||||
var/move_to_delay = 4 //delay for the automated movement.
|
||||
var/list/friends = list()
|
||||
var/break_stuff_probability = 10
|
||||
break_stuff_probability = 10
|
||||
stop_automated_movement_when_pulled = 0
|
||||
var/destroy_surroundings = 1
|
||||
destroy_surroundings = 1
|
||||
a_intent = I_HURT
|
||||
hostile = 1
|
||||
|
||||
var/shuttletarget = null
|
||||
var/enroute = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/FindTarget()
|
||||
|
||||
var/atom/T = null
|
||||
stop_automated_movement = 0
|
||||
for(var/atom/A in ListTargets(10))
|
||||
|
||||
if(A == src)
|
||||
continue
|
||||
|
||||
var/atom/F = Found(A)
|
||||
if(F)
|
||||
T = F
|
||||
break
|
||||
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(L.faction == src.faction && !attack_same)
|
||||
continue
|
||||
else if(L in friends)
|
||||
continue
|
||||
else
|
||||
if(!L.stat)
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
T = L
|
||||
break
|
||||
|
||||
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
|
||||
var/obj/mecha/M = A
|
||||
if (M.occupant)
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
T = M
|
||||
break
|
||||
return T
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/MoveToTarget()
|
||||
stop_automated_movement = 1
|
||||
if(!target_mob || SA_attackable(target_mob))
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
if(target_mob in ListTargets(10))
|
||||
if(ranged)
|
||||
if(get_dist(src, target_mob) <= 6)
|
||||
OpenFire(target_mob)
|
||||
else
|
||||
walk_to(src, target_mob, 1, move_to_delay)
|
||||
else
|
||||
stance = HOSTILE_STANCE_ATTACKING
|
||||
walk_to(src, target_mob, 1, move_to_delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/AttackTarget()
|
||||
|
||||
stop_automated_movement = 1
|
||||
if(!target_mob || SA_attackable(target_mob))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(!(target_mob in ListTargets(10)))
|
||||
LostTarget()
|
||||
return 0
|
||||
if(get_dist(src, target_mob) <= 1) //Attacking
|
||||
AttackingTarget()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/AttackingTarget()
|
||||
if(!Adjacent(target_mob))
|
||||
return
|
||||
if(isliving(target_mob))
|
||||
var/mob/living/L = target_mob
|
||||
L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return L
|
||||
if(istype(target_mob,/obj/mecha))
|
||||
var/obj/mecha/M = target_mob
|
||||
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return M
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LoseTarget()
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
target_mob = null
|
||||
walk(src, 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LostTarget()
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
walk(src, 0)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7)
|
||||
var/list/L = hearers(src, dist)
|
||||
|
||||
for (var/obj/mecha/M in mechas_list)
|
||||
if (M.z == src.z && get_dist(src, M) <= dist)
|
||||
L += M
|
||||
|
||||
return L
|
||||
|
||||
/mob/living/simple_animal/hostile/death()
|
||||
..()
|
||||
walk(src, 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/Life()
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
walk(src, 0)
|
||||
return 0
|
||||
if(client)
|
||||
return 0
|
||||
|
||||
if(!stat)
|
||||
switch(stance)
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
target_mob = FindTarget()
|
||||
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
MoveToTarget()
|
||||
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
AttackTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/OpenFire(target_mob)
|
||||
var/target = target_mob
|
||||
visible_message("\red <b>[src]</b> fires at [target]!", 1)
|
||||
|
||||
var/tturf = get_turf(target)
|
||||
if(rapid)
|
||||
spawn(1)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
spawn(4)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
spawn(6)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
else
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype
|
||||
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
target_mob = null
|
||||
return
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
|
||||
if(target == start)
|
||||
return
|
||||
|
||||
var/obj/item/projectile/A = new projectiletype(user:loc)
|
||||
playsound(user, projectilesound, 100, 1)
|
||||
if(!A) return
|
||||
|
||||
if (!istype(target, /turf))
|
||||
qdel(A)
|
||||
return
|
||||
A.launch(target)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
|
||||
if(prob(break_stuff_probability))
|
||||
for(var/dir in cardinal) // North, South, East, West
|
||||
for(var/obj/structure/window/obstacle in get_step(src, dir))
|
||||
if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
|
||||
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return
|
||||
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
|
||||
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
|
||||
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/check_horde()
|
||||
return 0
|
||||
if(emergency_shuttle.shuttle.location)
|
||||
if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway
|
||||
if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick
|
||||
shuttletarget = pick(escape_list) //Pick a shuttle target
|
||||
enroute = 1
|
||||
stop_automated_movement = 1
|
||||
spawn()
|
||||
if(!src.stat)
|
||||
horde()
|
||||
|
||||
if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway
|
||||
enroute = 0
|
||||
stop_automated_movement = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/horde()
|
||||
var/turf/T = get_step_to(src, shuttletarget)
|
||||
for(var/atom/A in T)
|
||||
if(istype(A,/obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/D = A
|
||||
D.open(1)
|
||||
else if(istype(A,/obj/structure/simple_door))
|
||||
var/obj/structure/simple_door/D = A
|
||||
if(D.density)
|
||||
D.Open()
|
||||
else if(istype(A,/obj/structure/cult/pylon))
|
||||
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
|
||||
else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille))
|
||||
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
|
||||
Move(T)
|
||||
FindTarget()
|
||||
if(!target_mob || enroute)
|
||||
spawn(10)
|
||||
if(!src.stat)
|
||||
horde()
|
||||
return 0
|
||||
@@ -5,14 +5,14 @@
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(!L.stat)
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
stance = STANCE_ATTACK
|
||||
return L
|
||||
else
|
||||
enemies -= L
|
||||
else if(istype(A, /obj/mecha))
|
||||
var/obj/mecha/M = A
|
||||
if(M.occupant)
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
stance = STANCE_ATTACK
|
||||
return A
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/ListTargets()
|
||||
|
||||
@@ -66,6 +66,33 @@
|
||||
var/supernatural = 0
|
||||
var/purge = 0
|
||||
|
||||
//Pulling hostile mob vars down
|
||||
var/stance = STANCE_IDLE //Used to determine behavior
|
||||
var/mob/living/target_mob
|
||||
var/attack_same = 0
|
||||
var/ranged = 0
|
||||
var/rapid = 0
|
||||
var/projectiletype
|
||||
var/projectilesound
|
||||
var/casingtype
|
||||
var/move_to_delay = 4 //delay for the automated movement.
|
||||
var/list/friends = list()
|
||||
var/break_stuff_probability = 0
|
||||
var/destroy_surroundings = 0
|
||||
var/shuttletarget = null
|
||||
var/enroute = 0
|
||||
|
||||
var/list/resistances = list(
|
||||
HALLOSS = 0,
|
||||
BRUTE = 1,
|
||||
BURN = 1,
|
||||
TOX = 1,
|
||||
OXY = 0,
|
||||
CLONE = 0
|
||||
)
|
||||
|
||||
var/hostile = 0
|
||||
|
||||
/mob/living/simple_animal/New()
|
||||
..()
|
||||
verbs -= /mob/verb/observe
|
||||
@@ -204,6 +231,23 @@
|
||||
|
||||
if(!atmos_suitable)
|
||||
adjustBruteLoss(unsuitable_atoms_damage)
|
||||
|
||||
//Hostility
|
||||
if(!stat && !client && hostile)
|
||||
switch(stance)
|
||||
if(STANCE_IDLE)
|
||||
target_mob = FindTarget()
|
||||
|
||||
if(STANCE_ATTACK)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
MoveToTarget()
|
||||
|
||||
if(STANCE_ATTACKING)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
AttackTarget()
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/proc/handle_supernatural()
|
||||
@@ -299,7 +343,7 @@
|
||||
if(O.force <= resistance)
|
||||
user << "<span class='danger'>This weapon is ineffective, it does no damage.</span>"
|
||||
return 2
|
||||
|
||||
|
||||
var/damage = O.force
|
||||
if (O.damtype == HALLOSS)
|
||||
damage = 0
|
||||
@@ -402,3 +446,191 @@
|
||||
return
|
||||
/mob/living/simple_animal/ExtinguishMob()
|
||||
return
|
||||
|
||||
//Hostile procs moved down
|
||||
/mob/living/simple_animal/proc/FindTarget()
|
||||
|
||||
var/atom/T = null
|
||||
stop_automated_movement = 0
|
||||
for(var/atom/A in ListTargets(10))
|
||||
|
||||
if(A == src)
|
||||
continue
|
||||
|
||||
var/atom/F = Found(A)
|
||||
if(F)
|
||||
T = F
|
||||
break
|
||||
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(L.faction == src.faction && !attack_same)
|
||||
continue
|
||||
else if(L in friends)
|
||||
continue
|
||||
else
|
||||
if(!L.stat)
|
||||
stance = STANCE_ATTACK
|
||||
T = L
|
||||
break
|
||||
|
||||
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
|
||||
var/obj/mecha/M = A
|
||||
if (M.occupant)
|
||||
stance = STANCE_ATTACK
|
||||
T = M
|
||||
break
|
||||
return T
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/Found(var/atom/A)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/proc/MoveToTarget()
|
||||
stop_automated_movement = 1
|
||||
if(!target_mob || SA_attackable(target_mob))
|
||||
stance = STANCE_IDLE
|
||||
if(target_mob in ListTargets(10))
|
||||
if(ranged)
|
||||
if(get_dist(src, target_mob) <= 6)
|
||||
OpenFire(target_mob)
|
||||
else
|
||||
walk_to(src, target_mob, 1, move_to_delay)
|
||||
else
|
||||
stance = STANCE_ATTACKING
|
||||
walk_to(src, target_mob, 1, move_to_delay)
|
||||
|
||||
/mob/living/simple_animal/proc/AttackTarget()
|
||||
|
||||
stop_automated_movement = 1
|
||||
if(!target_mob || SA_attackable(target_mob))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(!(target_mob in ListTargets(10)))
|
||||
LostTarget()
|
||||
return 0
|
||||
if(get_dist(src, target_mob) <= 1) //Attacking
|
||||
AttackingTarget()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/proc/AttackingTarget()
|
||||
if(!Adjacent(target_mob))
|
||||
return
|
||||
if(isliving(target_mob))
|
||||
var/mob/living/L = target_mob
|
||||
L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return L
|
||||
if(istype(target_mob,/obj/mecha))
|
||||
var/obj/mecha/M = target_mob
|
||||
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return M
|
||||
|
||||
/mob/living/simple_animal/proc/LoseTarget()
|
||||
stance = STANCE_IDLE
|
||||
target_mob = null
|
||||
walk(src, 0)
|
||||
|
||||
/mob/living/simple_animal/proc/LostTarget()
|
||||
stance = STANCE_IDLE
|
||||
walk(src, 0)
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/ListTargets(var/dist = 7)
|
||||
var/list/L = hearers(src, dist)
|
||||
|
||||
for (var/obj/mecha/M in mechas_list)
|
||||
if (M.z == src.z && get_dist(src, M) <= dist)
|
||||
L += M
|
||||
|
||||
return L
|
||||
|
||||
/mob/living/simple_animal/proc/OpenFire(target_mob)
|
||||
var/target = target_mob
|
||||
visible_message("\red <b>[src]</b> fires at [target]!", 1)
|
||||
|
||||
var/tturf = get_turf(target)
|
||||
if(rapid)
|
||||
spawn(1)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
spawn(4)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
spawn(6)
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype(get_turf(src))
|
||||
else
|
||||
Shoot(tturf, src.loc, src)
|
||||
if(casingtype)
|
||||
new casingtype
|
||||
|
||||
stance = STANCE_IDLE
|
||||
target_mob = null
|
||||
return
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
|
||||
if(target == start)
|
||||
return
|
||||
|
||||
var/obj/item/projectile/A = new projectiletype(user:loc)
|
||||
playsound(user, projectilesound, 100, 1)
|
||||
if(!A) return
|
||||
|
||||
if (!istype(target, /turf))
|
||||
qdel(A)
|
||||
return
|
||||
A.launch(target)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/proc/DestroySurroundings()
|
||||
if(prob(break_stuff_probability))
|
||||
for(var/dir in cardinal) // North, South, East, West
|
||||
for(var/obj/structure/window/obstacle in get_step(src, dir))
|
||||
if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
|
||||
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
return
|
||||
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
|
||||
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
|
||||
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/check_horde()
|
||||
return 0
|
||||
if(emergency_shuttle.shuttle.location)
|
||||
if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway
|
||||
if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick
|
||||
shuttletarget = pick(escape_list) //Pick a shuttle target
|
||||
enroute = 1
|
||||
stop_automated_movement = 1
|
||||
spawn()
|
||||
if(!src.stat)
|
||||
horde()
|
||||
|
||||
if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway
|
||||
enroute = 0
|
||||
stop_automated_movement = 0
|
||||
|
||||
/mob/living/simple_animal/proc/horde()
|
||||
var/turf/T = get_step_to(src, shuttletarget)
|
||||
for(var/atom/A in T)
|
||||
if(istype(A,/obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/D = A
|
||||
D.open(1)
|
||||
else if(istype(A,/obj/structure/simple_door))
|
||||
var/obj/structure/simple_door/D = A
|
||||
if(D.density)
|
||||
D.Open()
|
||||
else if(istype(A,/obj/structure/cult/pylon))
|
||||
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
|
||||
else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille))
|
||||
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
|
||||
Move(T)
|
||||
FindTarget()
|
||||
if(!target_mob || enroute)
|
||||
spawn(10)
|
||||
if(!src.stat)
|
||||
horde()
|
||||
@@ -383,6 +383,10 @@
|
||||
if(type == CHEM_TOUCH)
|
||||
var/datum/reagents/R = C.touching
|
||||
return trans_to_holder(R, amount, multiplier, copy)
|
||||
else if(isxeno(target))
|
||||
var/mob/living/simple_animal/xeno/X = target
|
||||
var/datum/reagents/R = X.reagents
|
||||
return trans_to_holder(R, amount, multiplier, copy)
|
||||
else
|
||||
var/datum/reagents/R = new /datum/reagents(amount)
|
||||
. = trans_to_holder(R, amount, multiplier, copy)
|
||||
|
||||
@@ -474,42 +474,46 @@
|
||||
color = "#13BC5E"
|
||||
|
||||
/datum/reagent/slimetoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species.name != "Promethean")
|
||||
M << "<span class='danger'>Your flesh rapidly mutates!</span>"
|
||||
H.set_species("Promethean")
|
||||
H.shapeshifter_set_colour("#05FF9B")
|
||||
H.verbs -= /mob/living/carbon/human/proc/shapeshifter_select_colour
|
||||
if(M.isSynthetic())
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H) && (H.species.flags & NO_SCAN))
|
||||
return
|
||||
|
||||
if(M.dna)
|
||||
if(prob(removed * 0.1))
|
||||
randmuti(M)
|
||||
if(prob(98))
|
||||
randmutb(M)
|
||||
else
|
||||
randmutg(M)
|
||||
domutcheck(M, null)
|
||||
M.UpdateAppearance()
|
||||
M.apply_effect(16 * removed, IRRADIATE, 0)
|
||||
|
||||
/datum/reagent/aslimetoxin
|
||||
name = "Advanced Mutation Toxin"
|
||||
id = "amutationtoxin"
|
||||
description = "An advanced corruptive toxin produced by slimes."
|
||||
name = "Docility Toxin"
|
||||
id = "docilitytoxin"
|
||||
description = "A corruptive toxin produced by slimes."
|
||||
reagent_state = LIQUID
|
||||
color = "#13BC5E"
|
||||
color = "#FF69B4"
|
||||
|
||||
/datum/reagent/aslimetoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) // TODO: check if there's similar code anywhere else
|
||||
if(M.transforming)
|
||||
if(M.isSynthetic())
|
||||
return
|
||||
M << "<span class='danger'>Your flesh rapidly mutates!</span>"
|
||||
M.transforming = 1
|
||||
M.canmove = 0
|
||||
M.icon = null
|
||||
M.overlays.Cut()
|
||||
M.invisibility = 101
|
||||
for(var/obj/item/W in M)
|
||||
if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something
|
||||
qdel(W)
|
||||
continue
|
||||
W.layer = initial(W.layer)
|
||||
W.loc = M.loc
|
||||
W.dropped(M)
|
||||
var/mob/living/carbon/slime/new_mob = new /mob/living/carbon/slime(M.loc)
|
||||
new_mob.a_intent = "hurt"
|
||||
new_mob.universal_speak = 1
|
||||
if(M.mind)
|
||||
M.mind.transfer_to(new_mob)
|
||||
else
|
||||
new_mob.key = M.key
|
||||
qdel(M)
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H) && (H.species.flags & NO_SCAN))
|
||||
return
|
||||
|
||||
if(M.dna)
|
||||
if(prob(removed * 0.1))
|
||||
randmuti(M)
|
||||
if(prob(98))
|
||||
randmutb(M)
|
||||
else
|
||||
randmutg(M)
|
||||
domutcheck(M, null)
|
||||
M.UpdateAppearance()
|
||||
M.apply_effect(6 * removed, IRRADIATE, 0)
|
||||
|
||||
@@ -998,333 +998,25 @@
|
||||
/datum/chemical_reaction/slime
|
||||
var/required = null
|
||||
|
||||
//Slimed monkeys
|
||||
/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder)
|
||||
if(holder.my_atom && istype(holder.my_atom, required))
|
||||
var/obj/item/slime_extract/T = holder.my_atom
|
||||
if(T.Uses > 0)
|
||||
return ..()
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder)
|
||||
var/obj/item/slime_extract/T = holder.my_atom
|
||||
T.Uses--
|
||||
if(T.Uses <= 0)
|
||||
T.visible_message("\icon[T]<span class='notice'>\The [T]'s power is consumed in the reaction.</span>")
|
||||
T.name = "used slime extract"
|
||||
T.desc = "This extract has been used up."
|
||||
|
||||
//Grey
|
||||
/datum/chemical_reaction/slime/spawn
|
||||
name = "Slime Spawn"
|
||||
id = "m_spawn"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/grey
|
||||
|
||||
/datum/chemical_reaction/slime/spawn/on_reaction(var/datum/reagents/holder)
|
||||
holder.my_atom.visible_message("<span class='warning'>Infused with phoron, the core begins to quiver and grow, and soon a new baby slime emerges from it!</span>")
|
||||
var/mob/living/carbon/slime/S = new /mob/living/carbon/slime
|
||||
S.loc = get_turf(holder.my_atom)
|
||||
..()
|
||||
|
||||
/datum/chemical_reaction/slime/monkey
|
||||
name = "Slime Monkey"
|
||||
id = "m_monkey"
|
||||
result = null
|
||||
required_reagents = list("blood" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/grey
|
||||
|
||||
/datum/chemical_reaction/slime/monkey/on_reaction(var/datum/reagents/holder)
|
||||
for(var/i = 1, i <= 3, i++)
|
||||
var /obj/item/weapon/reagent_containers/food/snacks/monkeycube/M = new /obj/item/weapon/reagent_containers/food/snacks/monkeycube
|
||||
M.loc = get_turf(holder.my_atom)
|
||||
..()
|
||||
|
||||
//Green
|
||||
/datum/chemical_reaction/slime/mutate
|
||||
name = "Mutation Toxin"
|
||||
id = "mutationtoxin"
|
||||
result = "mutationtoxin"
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/green
|
||||
|
||||
//Metal
|
||||
/datum/chemical_reaction/slime/metal
|
||||
name = "Slime Metal"
|
||||
id = "m_metal"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/metal
|
||||
|
||||
/datum/chemical_reaction/slime/metal/on_reaction(var/datum/reagents/holder)
|
||||
var/obj/item/stack/material/steel/M = new /obj/item/stack/material/steel
|
||||
M.amount = 15
|
||||
M.loc = get_turf(holder.my_atom)
|
||||
var/obj/item/stack/material/plasteel/P = new /obj/item/stack/material/plasteel
|
||||
P.amount = 5
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
..()
|
||||
|
||||
//Gold - removed
|
||||
/datum/chemical_reaction/slime/crit
|
||||
name = "Slime Crit"
|
||||
id = "m_tele"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/gold
|
||||
mix_message = "The slime core fizzles disappointingly."
|
||||
|
||||
//Silver
|
||||
/datum/chemical_reaction/slime/bork
|
||||
name = "Slime Bork"
|
||||
id = "m_tele2"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/silver
|
||||
|
||||
/datum/chemical_reaction/slime/bork/on_reaction(var/datum/reagents/holder)
|
||||
var/list/borks = typesof(/obj/item/weapon/reagent_containers/food/snacks) - /obj/item/weapon/reagent_containers/food/snacks
|
||||
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1)
|
||||
for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null))
|
||||
if(M.eyecheck() <= 0)
|
||||
flick("e_flash", M.flash)
|
||||
|
||||
for(var/i = 1, i <= 4 + rand(1,2), i++)
|
||||
var/chosen = pick(borks)
|
||||
var/obj/B = new chosen
|
||||
if(B)
|
||||
B.loc = get_turf(holder.my_atom)
|
||||
if(prob(50))
|
||||
for(var/j = 1, j <= rand(1, 3), j++)
|
||||
step(B, pick(NORTH, SOUTH, EAST, WEST))
|
||||
..()
|
||||
|
||||
//Blue
|
||||
/datum/chemical_reaction/slime/frost
|
||||
name = "Slime Frost Oil"
|
||||
id = "m_frostoil"
|
||||
result = "frostoil"
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 10
|
||||
required = /obj/item/slime_extract/blue
|
||||
|
||||
//Dark Blue
|
||||
/datum/chemical_reaction/slime/freeze
|
||||
name = "Slime Freeze"
|
||||
id = "m_freeze"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/darkblue
|
||||
mix_message = "The slime extract begins to vibrate violently!"
|
||||
|
||||
/datum/chemical_reaction/slime/freeze/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
sleep(50)
|
||||
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1)
|
||||
for(var/mob/living/M in range (get_turf(holder.my_atom), 7))
|
||||
M.bodytemperature -= 140
|
||||
M << "<span class='warning'>You feel a chill!</span>"
|
||||
|
||||
//Orange
|
||||
/datum/chemical_reaction/slime/casp
|
||||
name = "Slime Capsaicin Oil"
|
||||
id = "m_capsaicinoil"
|
||||
result = "capsaicin"
|
||||
required_reagents = list("blood" = 1)
|
||||
result_amount = 10
|
||||
required = /obj/item/slime_extract/orange
|
||||
|
||||
/datum/chemical_reaction/slime/fire
|
||||
name = "Slime fire"
|
||||
id = "m_fire"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/orange
|
||||
mix_message = "The slime extract begins to vibrate violently!"
|
||||
|
||||
/datum/chemical_reaction/slime/fire/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
sleep(50)
|
||||
var/turf/location = get_turf(holder.my_atom.loc)
|
||||
for(var/turf/simulated/floor/target_tile in range(0, location))
|
||||
target_tile.assume_gas("phoron", 25, 1400)
|
||||
spawn (0)
|
||||
target_tile.hotspot_expose(700, 400)
|
||||
|
||||
//Yellow
|
||||
/datum/chemical_reaction/slime/overload
|
||||
name = "Slime EMP"
|
||||
id = "m_emp"
|
||||
result = null
|
||||
required_reagents = list("blood" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/yellow
|
||||
|
||||
/datum/chemical_reaction/slime/overload/on_reaction(var/datum/reagents/holder, var/created_volume)
|
||||
..()
|
||||
empulse(get_turf(holder.my_atom), 3, 7)
|
||||
|
||||
/datum/chemical_reaction/slime/cell
|
||||
name = "Slime Powercell"
|
||||
id = "m_cell"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/yellow
|
||||
|
||||
/datum/chemical_reaction/slime/cell/on_reaction(var/datum/reagents/holder, var/created_volume)
|
||||
var/obj/item/weapon/cell/slime/P = new /obj/item/weapon/cell/slime
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
|
||||
/datum/chemical_reaction/slime/glow
|
||||
name = "Slime Glow"
|
||||
id = "m_glow"
|
||||
result = null
|
||||
required_reagents = list("water" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/yellow
|
||||
mix_message = "The contents of the slime core harden and begin to emit a warm, bright light."
|
||||
|
||||
/datum/chemical_reaction/slime/glow/on_reaction(var/datum/reagents/holder, var/created_volume)
|
||||
..()
|
||||
var/obj/item/device/flashlight/slime/F = new /obj/item/device/flashlight/slime
|
||||
F.loc = get_turf(holder.my_atom)
|
||||
|
||||
//Purple
|
||||
/datum/chemical_reaction/slime/psteroid
|
||||
name = "Slime Steroid"
|
||||
id = "m_steroid"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/purple
|
||||
|
||||
/datum/chemical_reaction/slime/psteroid/on_reaction(var/datum/reagents/holder, var/created_volume)
|
||||
..()
|
||||
var/obj/item/weapon/slimesteroid/P = new /obj/item/weapon/slimesteroid
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
|
||||
/datum/chemical_reaction/slime/jam
|
||||
name = "Slime Jam"
|
||||
id = "m_jam"
|
||||
result = "slimejelly"
|
||||
required_reagents = list("sugar" = 1)
|
||||
result_amount = 10
|
||||
required = /obj/item/slime_extract/purple
|
||||
|
||||
//Dark Purple
|
||||
/datum/chemical_reaction/slime/plasma
|
||||
name = "Slime Plasma"
|
||||
id = "m_plasma"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/darkpurple
|
||||
|
||||
/datum/chemical_reaction/slime/plasma/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
var/obj/item/stack/material/phoron/P = new /obj/item/stack/material/phoron
|
||||
P.amount = 10
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
|
||||
//Red
|
||||
/datum/chemical_reaction/slime/glycerol
|
||||
name = "Slime Glycerol"
|
||||
id = "m_glycerol"
|
||||
result = "glycerol"
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 8
|
||||
required = /obj/item/slime_extract/red
|
||||
|
||||
/datum/chemical_reaction/slime/bloodlust
|
||||
name = "Bloodlust"
|
||||
id = "m_bloodlust"
|
||||
result = null
|
||||
required_reagents = list("blood" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/red
|
||||
|
||||
/datum/chemical_reaction/slime/bloodlust/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null))
|
||||
slime.rabid = 1
|
||||
slime.visible_message("<span class='warning'>The [slime] is driven into a frenzy!</span>")
|
||||
|
||||
//Pink
|
||||
/datum/chemical_reaction/slime/ppotion
|
||||
name = "Slime Potion"
|
||||
id = "m_potion"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/pink
|
||||
|
||||
/datum/chemical_reaction/slime/ppotion/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
var/obj/item/weapon/slimepotion/P = new /obj/item/weapon/slimepotion
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
|
||||
//Black
|
||||
/datum/chemical_reaction/slime/mutate2
|
||||
name = "Advanced Mutation Toxin"
|
||||
id = "mutationtoxin2"
|
||||
result = "amutationtoxin"
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/black
|
||||
|
||||
//Oil
|
||||
/datum/chemical_reaction/slime/explosion
|
||||
name = "Slime Explosion"
|
||||
id = "m_explosion"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/oil
|
||||
mix_message = "The slime extract begins to vibrate violently!"
|
||||
|
||||
/datum/chemical_reaction/slime/explosion/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
sleep(50)
|
||||
explosion(get_turf(holder.my_atom), 1, 3, 6)
|
||||
|
||||
//Light Pink
|
||||
/datum/chemical_reaction/slime/potion2
|
||||
name = "Slime Potion 2"
|
||||
id = "m_potion2"
|
||||
result = null
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/lightpink
|
||||
required_reagents = list("phoron" = 1)
|
||||
|
||||
/datum/chemical_reaction/slime/potion2/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
var/obj/item/weapon/slimepotion2/P = new /obj/item/weapon/slimepotion2
|
||||
P.loc = get_turf(holder.my_atom)
|
||||
|
||||
//Adamantine
|
||||
|
||||
/datum/chemical_reaction/slime/golem
|
||||
name = "Slime Golem"
|
||||
id = "m_golem"
|
||||
name = "Prometheans"
|
||||
id = "m_promethean"
|
||||
result = null
|
||||
required_reagents = list("phoron" = 1)
|
||||
required_reagents = list("mutationtoxin" = 1)
|
||||
result_amount = 1
|
||||
required = /obj/item/slime_extract/adamantine
|
||||
required = /obj/item/weapon/reagent_containers/food/snacks/monkeycube
|
||||
|
||||
/datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder)
|
||||
..()
|
||||
var/obj/effect/golemrune/Z = new /obj/effect/golemrune
|
||||
Z.loc = get_turf(holder.my_atom)
|
||||
Z.announce_to_ghosts()
|
||||
|
||||
var/location = get_turf(holder.my_atom)
|
||||
new /obj/item/slime_cube(location)
|
||||
qdel(holder.my_atom)
|
||||
|
||||
/* Food */
|
||||
|
||||
/datum/chemical_reaction/tofu
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
//Important definitions for xenos, traits datum.
|
||||
|
||||
//Definitions for gene grouping.
|
||||
#define GENE_XENO_BIOCHEMISTRY "biochemistry"
|
||||
#define GENE_XENO_HEALTH "health"
|
||||
#define GENE_XENO_RESISTANCES "resistances"
|
||||
#define GENE_XENO_INTERNAL "internal"
|
||||
#define GENE_XENO_COLOR "color"
|
||||
#define GENE_XENO_GLOW "glow"
|
||||
#define GENE_XENO_LEARN "learn"
|
||||
#define GENE_XENO_SPEAK "speak"
|
||||
#define GENE_XENO_SPEED "speed"
|
||||
#define GENE_XENO_SPECIAL "special"
|
||||
|
||||
#define ALL_XENO_GENES list(GENE_XENO_BIOCHEMISTRY, GENE_XENO_HEALTH, GENE_XENO_RESISTANCES, GENE_XENO_INTERNAL, GENE_XENO_COLOR, GENE_XENO_LEARN, GENE_XENO_SPEAK, GENE_XENO_SPEED, GENE_XENO_SPECIAL)
|
||||
|
||||
//Definitions for traits.
|
||||
|
||||
#define TRAIT_XENO_COLOR "color"
|
||||
#define TRAIT_XENO_CHEMISTRY "chems"
|
||||
#define TRAIT_XENO_CHEMVOL "chem_vol"
|
||||
#define TRAIT_XENO_HEALTH "health"
|
||||
#define TRAIT_XENO_HUNGER "hunger"
|
||||
#define TRAIT_XENO_STARVEDAMAGE "starvedamage"
|
||||
#define TRAIT_XENO_EATS "eats"
|
||||
#define TRAIT_XENO_CHROMATIC "chrom"
|
||||
#define TRAIT_XENO_HOSTILE "hostile"
|
||||
#define TRAIT_XENO_BIOLUMESCENT "biolum"
|
||||
#define TRAIT_XENO_BIO_COLOR "biocolor"
|
||||
#define TRAIT_XENO_GLOW_STRENGTH "biostrength"
|
||||
#define TRAIT_XENO_GLOW_RANGE "biorange"
|
||||
#define TRAIT_XENO_TOXIC_CHEMS "tox_chems"
|
||||
#define TRAIT_XENO_NUTRITIONAL_CHEMS "nutr_chems"
|
||||
#define TRAIT_XENO_HEALING_CHEMS "heal_chems"
|
||||
#define TRAIT_XENO_MUTATING_CHEMS "mut_chems"
|
||||
#define TRAIT_XENO_SPEED "speed"
|
||||
#define TRAIT_XENO_COLDRES "cold_resistance"
|
||||
#define TRAIT_XENO_HEATRES "heat_resistance"
|
||||
#define TRAIT_XENO_LEARNCHANCE "learn_chance"
|
||||
#define TRAIT_XENO_CANLEARN "can_learn"
|
||||
#define TRAIT_XENO_SPEAKCHANCE "speak_chance"
|
||||
#define TRAIT_XENO_CANSPEAK "can_speak"
|
||||
#define TRAIT_XENO_STRENGTH "melee_strength"
|
||||
#define TRAIT_XENO_STR_RANGE "melee_range"
|
||||
|
||||
//Maleability defines.
|
||||
#define MAX_MALEABLE 2
|
||||
#define MINOR_MALEABLE 1
|
||||
#define MIN_MALEABLE 0
|
||||
|
||||
var/global/list/xenoChemList = list("mutationtoxin",
|
||||
"psilocybin",
|
||||
"mindbreaker",
|
||||
"impedrezene",
|
||||
"cryptobiolin",
|
||||
"space_drugs",
|
||||
"chloralhydrate",
|
||||
"stoxin",
|
||||
"mutagen",
|
||||
"lexorin",
|
||||
"pacid",
|
||||
"cyanide",
|
||||
"phoron",
|
||||
"plasticide",
|
||||
"amatoxin",
|
||||
"carbon",
|
||||
"radium",
|
||||
"sacid",
|
||||
"sugar",
|
||||
"kelotane",
|
||||
"dermaline",
|
||||
"anti_toxin",
|
||||
"dexalin",
|
||||
"synaptizine",
|
||||
"alkysine",
|
||||
"imidazoline",
|
||||
"peridaxon",
|
||||
"rezadone",
|
||||
"mutationtoxin",
|
||||
"docilitytoxin")
|
||||
|
||||
/datum/xeno/traits
|
||||
var/list/traits = list()
|
||||
var/list/chemlist = list()
|
||||
var/list/chems = list()
|
||||
var/source = "unknown"
|
||||
|
||||
/datum/xeno/traits/proc/set_trait(var/trait, var/newval)
|
||||
traits["[trait]"] = newval
|
||||
return
|
||||
|
||||
/datum/xeno/traits/proc/get_trait(var/trait)
|
||||
var/val = traits["[trait]"]
|
||||
return val
|
||||
|
||||
/datum/xeno/traits/New()
|
||||
..()
|
||||
set_trait(TRAIT_XENO_COLOR, "#CACACA")
|
||||
set_trait(TRAIT_XENO_CHEMVOL, 100)
|
||||
set_trait(TRAIT_XENO_HEALTH, 20)
|
||||
set_trait(TRAIT_XENO_HUNGER, 2)
|
||||
set_trait(TRAIT_XENO_STARVEDAMAGE, 0)
|
||||
set_trait(TRAIT_XENO_EATS, 1)
|
||||
set_trait(TRAIT_XENO_CHROMATIC, 0)
|
||||
set_trait(TRAIT_XENO_HOSTILE, 0)
|
||||
set_trait(TRAIT_XENO_BIOLUMESCENT, 0)
|
||||
set_trait(TRAIT_XENO_BIO_COLOR, "#CACACA")
|
||||
set_trait(TRAIT_XENO_GLOW_STRENGTH, 0)
|
||||
set_trait(TRAIT_XENO_GLOW_RANGE, 0)
|
||||
set_trait(TRAIT_XENO_SPEED, 4)
|
||||
set_trait(TRAIT_XENO_COLDRES, 20)
|
||||
set_trait(TRAIT_XENO_HEATRES, 20)
|
||||
set_trait(TRAIT_XENO_LEARNCHANCE, 100)
|
||||
set_trait(TRAIT_XENO_CANLEARN, 1)
|
||||
set_trait(TRAIT_XENO_SPEAKCHANCE, 1)
|
||||
set_trait(TRAIT_XENO_CANSPEAK, 1)
|
||||
set_trait(TRAIT_XENO_STRENGTH, 0)
|
||||
set_trait(TRAIT_XENO_STR_RANGE, 0)
|
||||
|
||||
/datum/xeno/traits/proc/get_gene(var/genetype)
|
||||
|
||||
if(!genetype) return 0
|
||||
|
||||
var/datum/xeno/genes/G = new()
|
||||
G.genetype = genetype
|
||||
G.values = list()
|
||||
|
||||
switch(genetype)
|
||||
if(GENE_XENO_BIOCHEMISTRY)
|
||||
G.values["[TRAIT_XENO_CHEMVOL]"] = get_trait(TRAIT_XENO_CHEMVOL)
|
||||
G.chems = chems
|
||||
if(GENE_XENO_HEALTH)
|
||||
G.values["[TRAIT_XENO_HEALTH]"] = get_trait(TRAIT_XENO_HEALTH)
|
||||
G.values["[TRAIT_XENO_STRENGTH]"] = get_trait(TRAIT_XENO_STRENGTH)
|
||||
G.values["[TRAIT_XENO_STR_RANGE]"] = get_trait(TRAIT_XENO_STR_RANGE)
|
||||
if(GENE_XENO_RESISTANCES)
|
||||
G.values["[TRAIT_XENO_COLDRES]"] = get_trait(TRAIT_XENO_HEALTH)
|
||||
G.values["[TRAIT_XENO_HEATRES]"] = get_trait(TRAIT_XENO_STRENGTH)
|
||||
if(GENE_XENO_INTERNAL)
|
||||
G.values["[TRAIT_XENO_NUTRITIONAL_CHEMS]"] = get_trait(TRAIT_XENO_NUTRITIONAL_CHEMS)
|
||||
G.values["[TRAIT_XENO_HEALING_CHEMS]"] = get_trait(TRAIT_XENO_HEALING_CHEMS)
|
||||
G.values["[TRAIT_XENO_TOXIC_CHEMS]"] = get_trait(TRAIT_XENO_TOXIC_CHEMS)
|
||||
G.values["[TRAIT_XENO_MUTATING_CHEMS]"] = get_trait(TRAIT_XENO_MUTATING_CHEMS)
|
||||
if(GENE_XENO_COLOR)
|
||||
G.values["[TRAIT_XENO_COLOR]"] = get_trait(TRAIT_XENO_COLOR)
|
||||
G.values["[TRAIT_XENO_BIO_COLOR]"] = get_trait(TRAIT_XENO_BIO_COLOR)
|
||||
if(GENE_XENO_GLOW)
|
||||
G.values["[TRAIT_XENO_BIOLUMESCENT]"] = get_trait(TRAIT_XENO_BIOLUMESCENT)
|
||||
G.values["[TRAIT_XENO_GLOW_RANGE]"] = get_trait(TRAIT_XENO_GLOW_RANGE)
|
||||
G.values["[TRAIT_XENO_GLOW_STRENGTH]"] = get_trait(TRAIT_XENO_GLOW_STRENGTH)
|
||||
if(GENE_XENO_LEARN)
|
||||
G.values["[TRAIT_XENO_LEARNCHANCE]"] = get_trait(TRAIT_XENO_LEARNCHANCE)
|
||||
G.values["[TRAIT_XENO_CANLEARN]"] = get_trait(TRAIT_XENO_CANLEARN)
|
||||
if(GENE_XENO_SPEAK)
|
||||
G.values["[TRAIT_XENO_SPEAKCHANCE]"] = get_trait(TRAIT_XENO_SPEAKCHANCE)
|
||||
G.values["[TRAIT_XENO_CANSPEAK]"] = get_trait(TRAIT_XENO_CANSPEAK)
|
||||
if(GENE_XENO_SPEED)
|
||||
G.values["[TRAIT_XENO_SPEED]"] = get_trait(TRAIT_XENO_SPEED)
|
||||
if(GENE_XENO_SPECIAL)
|
||||
G.values["[TRAIT_XENO_HOSTILE]"] = get_trait(TRAIT_XENO_HOSTILE)
|
||||
G.values["[TRAIT_XENO_CHROMATIC]"] = get_trait(TRAIT_XENO_CHROMATIC)
|
||||
|
||||
return G
|
||||
|
||||
/datum/xeno/traits/proc/apply_gene(var/datum/xeno/genes/genes)
|
||||
if(!genes.genetype) return 0
|
||||
|
||||
switch(genes.genetype)
|
||||
if(GENE_XENO_BIOCHEMISTRY)
|
||||
set_trait(TRAIT_XENO_CHEMVOL, genes.values["[TRAIT_XENO_CHEMVOL]"])
|
||||
for(var/reagent in genes.chems)
|
||||
chems[reagent] = genes[reagent]
|
||||
|
||||
if(GENE_XENO_HEALTH)
|
||||
set_trait(TRAIT_XENO_HEALTH, genes.values["[TRAIT_XENO_HEALTH]"])
|
||||
set_trait(TRAIT_XENO_STRENGTH, genes.values["[TRAIT_XENO_STRENGTH]"])
|
||||
set_trait(TRAIT_XENO_STR_RANGE, genes.values["[TRAIT_XENO_STR_RANGE]"])
|
||||
if(GENE_XENO_RESISTANCES)
|
||||
set_trait(TRAIT_XENO_COLDRES, genes.values["[TRAIT_XENO_COLDRES]"])
|
||||
set_trait(TRAIT_XENO_HEATRES, genes.values["[TRAIT_XENO_HEATRES]"])
|
||||
if(GENE_XENO_INTERNAL)
|
||||
set_trait(TRAIT_XENO_NUTRITIONAL_CHEMS, genes.values["[TRAIT_XENO_NUTRITIONAL_CHEMS]"])
|
||||
set_trait(TRAIT_XENO_HEALING_CHEMS, genes.values["[TRAIT_XENO_HEALING_CHEMS]"])
|
||||
set_trait(TRAIT_XENO_TOXIC_CHEMS, genes.values["[TRAIT_XENO_TOXIC_CHEMS]"])
|
||||
set_trait(TRAIT_XENO_MUTATING_CHEMS, genes.values["[TRAIT_XENO_MUTATING_CHEMS]"])
|
||||
if(GENE_XENO_COLOR)
|
||||
set_trait(TRAIT_XENO_COLOR, genes.values["[TRAIT_XENO_COLOR]"])
|
||||
set_trait(TRAIT_XENO_BIO_COLOR, genes.values["[TRAIT_XENO_BIO_COLOR]"])
|
||||
if(GENE_XENO_GLOW)
|
||||
set_trait(TRAIT_XENO_BIOLUMESCENT, genes.values["[TRAIT_XENO_BIOLUMESCENT]"])
|
||||
set_trait(TRAIT_XENO_GLOW_RANGE, genes.values["[TRAIT_XENO_GLOW_RANGE]"])
|
||||
set_trait(TRAIT_XENO_GLOW_STRENGTH, genes.values["[TRAIT_XENO_GLOW_STRENGTH]"])
|
||||
if(GENE_XENO_LEARN)
|
||||
set_trait(TRAIT_XENO_LEARNCHANCE, genes.values["[TRAIT_XENO_LEARNCHANCE]"])
|
||||
set_trait(TRAIT_XENO_CANLEARN, genes.values["[TRAIT_XENO_CANLEARN]"])
|
||||
if(GENE_XENO_SPEAK)
|
||||
set_trait(TRAIT_XENO_SPEAKCHANCE, genes.values["[TRAIT_XENO_SPEAKCHANCE]"])
|
||||
set_trait(TRAIT_XENO_CANSPEAK, genes.values["[TRAIT_XENO_CANSPEAK]"])
|
||||
if(GENE_XENO_SPEED)
|
||||
set_trait(TRAIT_XENO_SPEED ,genes.values["[TRAIT_XENO_SPEED]"])
|
||||
if(GENE_XENO_SPECIAL)
|
||||
set_trait(TRAIT_XENO_HOSTILE, genes.values["[TRAIT_XENO_HOSTILE]"])
|
||||
set_trait(TRAIT_XENO_CHROMATIC, genes.values["[TRAIT_XENO_CHROMATIC]"])
|
||||
|
||||
/datum/xeno/genes
|
||||
var/genetype //Label for specifying what gene is used.
|
||||
var/list/values //What's going to be put into specific traits
|
||||
var/list/chems
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//Used to create the gene mask. Shamelessly stolen from the plant controller and cut down.
|
||||
|
||||
/client/proc/show_xenobio_genes()
|
||||
set category = "Debug"
|
||||
set name = "Show Xenobio Genes"
|
||||
set desc = "Prints the round's plant xenobio masks."
|
||||
|
||||
if(!holder) return
|
||||
|
||||
if(!xenobio_controller || !xenobio_controller.gene_tag_masks)
|
||||
usr << "Gene masks not set."
|
||||
return
|
||||
|
||||
for(var/mask in xenobio_controller.gene_tag_masks)
|
||||
usr << "[mask]: [xenobio_controller.gene_tag_masks[mask]]"
|
||||
|
||||
var/global/datum/controller/xenobio/xenobio_controller // Set in New().
|
||||
|
||||
/datum/controller/xenobio
|
||||
|
||||
var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness.
|
||||
|
||||
/datum/controller/xenobio/New()
|
||||
if(xenobio_controller && xenobio_controller != src)
|
||||
log_debug("Rebuilding xenobio controller.")
|
||||
qdel(xenobio_controller)
|
||||
xenobio_controller = src
|
||||
setup()
|
||||
|
||||
|
||||
/datum/controller/xenobio/proc/setup()
|
||||
|
||||
var/list/used_masks = list()
|
||||
var/list/xenobio_traits = ALL_XENO_GENES
|
||||
while(xenobio_traits && xenobio_traits.len)
|
||||
var/gene_tag = pick(xenobio_traits)
|
||||
var/gene_mask = "[uppertext(num2hex(rand(0,255)))]"
|
||||
|
||||
while(gene_mask in used_masks)
|
||||
gene_mask = "[uppertext(num2hex(rand(0,255)))]"
|
||||
|
||||
used_masks += gene_mask
|
||||
xenobio_traits -= gene_tag
|
||||
gene_tag_masks[gene_tag] = gene_mask
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Here lives the slime core extractor
|
||||
This machine extracts slime cores at the cost of the slime itself.
|
||||
To create more of these slimes, stick the slime core in the extractor.
|
||||
*/
|
||||
/obj/machinery/slime/extractor
|
||||
name = "Slime extractor"
|
||||
desc = "A machine for cutting up slimes to get to their cores."
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "scanner_0old"
|
||||
density = 1
|
||||
anchored = 1
|
||||
circuit = /obj/item/weapon/circuitboard/slimeextractor
|
||||
var/inuse
|
||||
var/mob/living/simple_animal/xeno/slime/occupant = null
|
||||
var/occupiedcolor = "#22FF22"
|
||||
var/emptycolor = "#FF2222"
|
||||
var/operatingcolor = "#FFFF22"
|
||||
|
||||
|
||||
/obj/machinery/slime/extractor/New()
|
||||
..()
|
||||
update_light_color()
|
||||
circuit = new circuit(src)
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/slime/extractor/attackby(var/obj/item/W, var/mob/user)
|
||||
|
||||
//Let's try to deconstruct first.
|
||||
if(istype(W, /obj/item/weapon/screwdriver) && !inuse)
|
||||
default_deconstruction_screwdriver(user, W)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/crowbar))
|
||||
default_deconstruction_crowbar(user, W)
|
||||
return
|
||||
|
||||
if(panel_open)
|
||||
user << "<span class='warning'>Close the panel first!</span>"
|
||||
|
||||
var/obj/item/weapon/grab/G = W
|
||||
|
||||
if(!istype(G))
|
||||
return ..()
|
||||
|
||||
if(G.state < 2)
|
||||
user << "<span class='danger'>You need a better grip to do that!</span>"
|
||||
return
|
||||
|
||||
move_into_extractor(user,G.affecting)
|
||||
|
||||
/obj/machinery/slime/extractor/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.restrained())
|
||||
return
|
||||
move_into_extractor(user,target)
|
||||
|
||||
/obj/machinery/slime/extractor/proc/move_into_extractor(var/mob/user,var/mob/living/victim)
|
||||
|
||||
if(src.occupant)
|
||||
user << "<span class='danger'>The core extractor is full, empty it first!</span>"
|
||||
return
|
||||
|
||||
if(inuse)
|
||||
user << "<span class='danger'>The core extractor is locked and running, wait for it to finish.</span>"
|
||||
return
|
||||
|
||||
if(!(istype(victim, /mob/living/simple_animal/xeno/slime)) )
|
||||
user << "<span class='danger'>This is not a suitable subject for the core extractor!</span>"
|
||||
return
|
||||
|
||||
var/mob/living/simple_animal/xeno/slime/S = victim
|
||||
if(S.is_child)
|
||||
user << "<span class='danger'>This subject is not developed enough for the core extractor!</span>"
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>[user] starts to put [victim] into the core extractor!</span>")
|
||||
src.add_fingerprint(user)
|
||||
if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant)
|
||||
user.visible_message("<span class='danger'>[user] stuffs [victim] into the core extractor!</span>")
|
||||
if(victim.client)
|
||||
victim.client.perspective = EYE_PERSPECTIVE
|
||||
victim.client.eye = src
|
||||
victim.forceMove(src)
|
||||
src.occupant = victim
|
||||
update_light_color()
|
||||
|
||||
/obj/machinery/slime/extractor/proc/update_light_color()
|
||||
if(src.occupant && !(inuse))
|
||||
set_light(2, 2, occupiedcolor)
|
||||
else if(src.occupant)
|
||||
set_light(2, 2, operatingcolor)
|
||||
else
|
||||
set_light(2, 2, emptycolor)
|
||||
|
||||
/obj/machinery/slime/extractor/proc/extract_cores()
|
||||
if(!src.occupant)
|
||||
src.visible_message("\icon[src] [src] pings unhappily.")
|
||||
else if(inuse)
|
||||
return
|
||||
|
||||
inuse = 1
|
||||
update_light_color()
|
||||
spawn(30)
|
||||
icon_state = "scanner_1old"
|
||||
for(var/i=1 to occupant.cores)
|
||||
var/obj/item/xenoproduct/slime/core/C = new(src)
|
||||
C.traits = occupant.traitdat
|
||||
|
||||
C.create_reagents(C.traits.traits[TRAIT_XENO_CHEMVOL])
|
||||
for(var/reagent in occupant.traitdat.chems)
|
||||
C.reagents.add_reagent(reagent, occupant.traitdat.chems[reagent])
|
||||
|
||||
C.color = C.traits.traits[TRAIT_XENO_COLOR]
|
||||
if(occupant.traitdat.get_trait(TRAIT_XENO_BIOLUMESCENT))
|
||||
C.set_light(occupant.traitdat.get_trait(TRAIT_XENO_GLOW_STRENGTH),occupant.traitdat.get_trait(TRAIT_XENO_GLOW_RANGE), occupant.traitdat.get_trait(TRAIT_XENO_BIO_COLOR))
|
||||
|
||||
spawn(30)
|
||||
icon_state = "scanner_0old"
|
||||
qdel(occupant)
|
||||
inuse = 0
|
||||
eject_contents()
|
||||
update_light_color()
|
||||
src.updateUsrDialog()
|
||||
|
||||
/obj/machinery/slime/extractor/proc/eject_slime()
|
||||
if(occupant)
|
||||
occupant.forceMove(loc)
|
||||
occupant = null
|
||||
|
||||
/obj/machinery/slime/extractor/proc/eject_core()
|
||||
for(var/obj/thing in (contents - component_parts - circuit))
|
||||
thing.forceMove(loc)
|
||||
|
||||
/obj/machinery/slime/extractor/proc/eject_contents()
|
||||
eject_core()
|
||||
eject_slime()
|
||||
|
||||
//Here lies the UI
|
||||
/obj/machinery/slime/extractor/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/slime/extractor/interact(mob/user as mob)
|
||||
var/dat = ""
|
||||
if(!inuse)
|
||||
dat = {"
|
||||
<b>Slime held:</b><br>
|
||||
[occupant]<br>
|
||||
"}
|
||||
if (occupant && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=\ref[src];action=extract'>Start the core extraction.</a><BR>"
|
||||
if(occupant)
|
||||
dat += "<A href='?src=\ref[src];action=eject'>Eject the slime</a><BR>"
|
||||
else
|
||||
dat += "Please wait..."
|
||||
var/datum/browser/popup = new(user, "Slime Extractor", "Slime Extractor", src)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/slime/extractor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
switch(href_list["action"])
|
||||
if ("extract")
|
||||
extract_cores()
|
||||
if("eject")
|
||||
eject_slime()
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
//Circuit board below,
|
||||
/obj/item/weapon/circuitboard/slimeextractor
|
||||
name = T_BOARD("Slime extractor")
|
||||
build_path = "/obj/machinery/slime/extractor"
|
||||
board_type = "machine"
|
||||
origin_tech = list(TECH_DATA = 3, TECH_BIO = 3)
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/manipulator = 2,
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/stock_parts/micro_laser = 2
|
||||
)
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
This file contains:
|
||||
|
||||
Xenobiological disk:
|
||||
Holds traits that can be taken from cores and transplanted into slimes.
|
||||
|
||||
Biological Product Destructive Analyzer:
|
||||
Takes certain traits in gene grouping from a core and places them into a disk.
|
||||
|
||||
Biological genetic bombarder:
|
||||
Takes traits from a disk and replaces/adds to the genes in a xenobiological creature.
|
||||
*/
|
||||
/obj/item/weapon/disk/xenobio
|
||||
name = "biological data disk"
|
||||
desc = "A small disk used for carrying data on genetics."
|
||||
icon = 'icons/obj/hydroponics_machines.dmi'
|
||||
icon_state = "disk"
|
||||
w_class = 1.0
|
||||
|
||||
var/list/genes = list()
|
||||
var/genesource = "unknown"
|
||||
|
||||
/obj/item/weapon/disk/xenobio/attack_self(var/mob/user as mob)
|
||||
if(genes.len)
|
||||
var/choice = alert(user, "Are you sure you want to wipe the disk?", "Xenobiological Data", "No", "Yes")
|
||||
if(src && user && genes && choice && choice == "Yes" && user.Adjacent(get_turf(src)))
|
||||
user << "You wipe the disk data."
|
||||
name = initial(name)
|
||||
desc = initial(name)
|
||||
genes = list()
|
||||
genesource = "unknown"
|
||||
|
||||
/obj/item/weapon/storage/box/xenobiodisk
|
||||
name = "biological disk box"
|
||||
desc = "A box of biological data disks, apparently."
|
||||
|
||||
/obj/item/weapon/storage/box/xenobiodisk/New()
|
||||
..()
|
||||
for(var/i = 0 to 7)
|
||||
new /obj/item/weapon/disk/xenobio(src)
|
||||
|
||||
/obj/machinery/xenobio
|
||||
density = 1
|
||||
anchored = 1
|
||||
use_power = 1
|
||||
|
||||
var/obj/item/weapon/disk/xenobio/loaded_disk //Currently loaded data disk.
|
||||
|
||||
var/open = 0
|
||||
var/active = 0
|
||||
var/action_time = 5
|
||||
var/last_action = 0
|
||||
var/eject_disk = 0
|
||||
var/failed_task = 0
|
||||
var/disk_needs_genes = 0
|
||||
|
||||
/obj/machinery/xenobio/attack_ai(mob/user as mob)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/xenobio/attack_hand(mob/user as mob)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/xenobio/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(default_deconstruction_screwdriver(user, W))
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, W))
|
||||
return
|
||||
if(istype(W,/obj/item/weapon/disk/xenobio))
|
||||
if(loaded_disk)
|
||||
user << "There is already a data disk loaded."
|
||||
return
|
||||
else
|
||||
var/obj/item/weapon/disk/xenobio/B = W
|
||||
|
||||
if(B.genes && B.genes.len)
|
||||
if(!disk_needs_genes)
|
||||
user << "That disk already has gene data loaded."
|
||||
return
|
||||
else
|
||||
if(disk_needs_genes)
|
||||
user << "That disk does not have any gene data loaded."
|
||||
return
|
||||
|
||||
user.drop_from_inventory(W)
|
||||
W.forceMove(src)
|
||||
loaded_disk = W
|
||||
user << "You load [W] into [src]."
|
||||
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/xenobio/process()
|
||||
|
||||
..()
|
||||
if(!active) return
|
||||
|
||||
if(world.time > last_action + action_time)
|
||||
finished_task()
|
||||
|
||||
/obj/machinery/xenobio/proc/finished_task()
|
||||
active = 0
|
||||
if(failed_task)
|
||||
failed_task = 0
|
||||
visible_message("\icon[src] [src] pings unhappily, flashing a red warning light.")
|
||||
else
|
||||
visible_message("\icon[src] [src] pings happily.")
|
||||
|
||||
if(eject_disk)
|
||||
eject_disk = 0
|
||||
if(loaded_disk)
|
||||
loaded_disk.forceMove(get_turf(src))
|
||||
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
|
||||
loaded_disk = null
|
||||
|
||||
/obj/machinery/xenobio/extractor
|
||||
name = "biological product destructive analyzer"
|
||||
icon = 'icons/obj/hydroponics_machines.dmi'
|
||||
icon_state = "traitcopier"
|
||||
circuit = /obj/item/weapon/circuitboard/bioproddestanalyzer
|
||||
|
||||
var/obj/item/xenoproduct/product
|
||||
var/datum/xeno/traits/genetics // Currently scanned xeno genetic structure.
|
||||
var/degradation = 0 // Increments with each scan, stops allowing gene mods after a certain point.
|
||||
|
||||
/obj/machinery/xenobio/extractor/New()
|
||||
..()
|
||||
circuit = new circuit(src)
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/xenobio/extractor/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/xenoproduct))
|
||||
if(product)
|
||||
user << "There is already a xenobiological product loaded."
|
||||
return
|
||||
else
|
||||
var/obj/item/xenoproduct/B = W
|
||||
user.drop_from_inventory(B)
|
||||
B.forceMove(src)
|
||||
product = B
|
||||
user << "You load [B] into [src]."
|
||||
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/xenobio/extractor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
var/list/geneMasks[0]
|
||||
for(var/gene_tag in xenobio_controller.gene_tag_masks)
|
||||
geneMasks.Add(list(list("tag" = gene_tag, "mask" = xenobio_controller.gene_tag_masks[gene_tag])))
|
||||
data["geneMasks"] = geneMasks
|
||||
|
||||
data["activity"] = active
|
||||
data["degradation"] = degradation
|
||||
|
||||
if(loaded_disk)
|
||||
data["disk"] = 1
|
||||
else
|
||||
data["disk"] = 0
|
||||
|
||||
if(product)
|
||||
data["loaded"] = "[product.source] [product.product]"
|
||||
else
|
||||
data["loaded"] = 0
|
||||
|
||||
if(genetics)
|
||||
data["hasGenetics"] = 1
|
||||
data["sourceName"] = genetics.source
|
||||
else
|
||||
data["hasGenetics"] = 0
|
||||
data["sourceName"] = 0
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "xenobio_isolator.tmpl", "B.P.D. Analyzer UI", 470, 450)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/xenobio/proc/eject_disk()
|
||||
if(!loaded_disk) return
|
||||
loaded_disk.forceMove(loc)
|
||||
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
|
||||
loaded_disk = null
|
||||
|
||||
/obj/machinery/xenobio/extractor/Topic(href, href_list)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["eject_product"])
|
||||
if(!product) return
|
||||
|
||||
product.forceMove(get_turf(src))
|
||||
visible_message("\icon[src] [src] beeps and spits out [product].")
|
||||
product = null
|
||||
|
||||
if(href_list["eject_disk"])
|
||||
eject_disk()
|
||||
|
||||
if(href_list["scan_genome"])
|
||||
|
||||
if(!product) return
|
||||
|
||||
last_action = world.time
|
||||
active = 1
|
||||
|
||||
if(product && product.product)
|
||||
genetics = product.traits
|
||||
degradation = 0
|
||||
|
||||
qdel(product)
|
||||
product = null
|
||||
|
||||
if(href_list["get_gene"])
|
||||
|
||||
if(!genetics || !loaded_disk) return
|
||||
|
||||
last_action = world.time
|
||||
active = 1
|
||||
|
||||
var/datum/xeno/genes/G = genetics.get_gene(href_list["get_gene"])
|
||||
if(!G) return
|
||||
loaded_disk.genes += G
|
||||
|
||||
loaded_disk.genesource = "[genetics.source]"
|
||||
|
||||
loaded_disk.name += " ([xenobio_controller.gene_tag_masks[href_list["get_gene"]]], [genetics.source])"
|
||||
loaded_disk.desc += " The label reads \'gene [xenobio_controller.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.source]\'."
|
||||
eject_disk = 1
|
||||
|
||||
degradation += rand(20,60)
|
||||
if(degradation >= 100)
|
||||
failed_task = 1
|
||||
genetics = null
|
||||
degradation = 0
|
||||
|
||||
if(href_list["clear_buffer"])
|
||||
if(!genetics) return
|
||||
genetics = null
|
||||
degradation = 0
|
||||
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/xenobio/editor
|
||||
name = "biological genetic bombarder"
|
||||
icon = 'icons/obj/cryogenics.dmi'
|
||||
icon_state = "cellold0"
|
||||
disk_needs_genes = 1
|
||||
circuit = /obj/item/weapon/circuitboard/biobombarder
|
||||
|
||||
var/mob/living/simple_animal/xeno/slime/occupant
|
||||
|
||||
/obj/machinery/xenobio/editor/New()
|
||||
..()
|
||||
circuit = new circuit(src)
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/xenobio/editor/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/weapon/grab))
|
||||
var/obj/item/weapon/grab/G = W
|
||||
if(occupant)
|
||||
user << "There is already an organism loaded."
|
||||
return
|
||||
else
|
||||
if(isxeno(G.affecting))
|
||||
var/mob/living/simple_animal/xeno/X = G.affecting
|
||||
if(do_after(user, 30) && X.Adjacent(src) && user.Adjacent(src) && X.Adjacent(user) && !occupant)
|
||||
user.drop_from_inventory(G)
|
||||
X.forceMove(src)
|
||||
occupant = X
|
||||
user << "You load [X] into [src]."
|
||||
else
|
||||
user << "<span class='danger'>This specimen is incompatible with the machinery!</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/xenobio/editor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
|
||||
if(!user)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
data["activity"] = active
|
||||
|
||||
if(occupant)
|
||||
data["degradation"] = occupant.stability
|
||||
else
|
||||
data["degradation"] = 0
|
||||
|
||||
if(loaded_disk && loaded_disk.genes.len)
|
||||
data["disk"] = 1
|
||||
data["sourceName"] = loaded_disk.genesource
|
||||
data["locus"] = ""
|
||||
|
||||
for(var/datum/xeno/genes/X in loaded_disk.genes)
|
||||
if(data["locus"] != "") data["locus"] += ", "
|
||||
data["locus"] += "[xenobio_controller.gene_tag_masks[X.genetype]]"
|
||||
|
||||
else
|
||||
data["disk"] = 0
|
||||
data["sourceName"] = 0
|
||||
data["locus"] = 0
|
||||
|
||||
if(occupant)
|
||||
data["loaded"] = "[occupant]"
|
||||
else
|
||||
data["loaded"] = 0
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "xenobio_editor.tmpl", "Biological Genetic Bombarder UI", 470, 450)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/xenobio/editor/Topic(href, href_list)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["apply_gene"])
|
||||
if(!loaded_disk || !occupant) return
|
||||
|
||||
last_action = world.time
|
||||
active = 1
|
||||
occupant.nameVar = "modified"
|
||||
|
||||
if(prob(occupant.stability))
|
||||
failed_task = 1
|
||||
occupant.stability = 101
|
||||
|
||||
for(var/datum/xeno/genes/gene in loaded_disk.genes)
|
||||
occupant.traitdat.apply_gene(gene)
|
||||
occupant.stability += rand(5,10)
|
||||
occupant.ProcessTraits()
|
||||
|
||||
if(href_list["eject_disk"])
|
||||
eject_disk()
|
||||
|
||||
if(href_list["eject_xeno"])
|
||||
eject_xeno()
|
||||
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/xenobio/editor/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.restrained())
|
||||
return
|
||||
move_into_editor(user,target)
|
||||
|
||||
/obj/machinery/xenobio/editor/proc/move_into_editor(var/mob/user,var/mob/living/victim)
|
||||
|
||||
if(src.occupant)
|
||||
user << "<span class='danger'>The biological genetic bombarder is full, empty it first!</span>"
|
||||
return
|
||||
|
||||
if(in_use)
|
||||
user << "<span class='danger'>The biological genetic bombarder is locked and running, wait for it to finish.</span>"
|
||||
return
|
||||
|
||||
if(!(istype(victim, /mob/living/simple_animal/xeno/slime)) )
|
||||
user << "<span class='danger'>This is not a suitable subject for the biological genetic bombarder!</span>"
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>[user] starts to put [victim] into the biological genetic bombarder!</span>")
|
||||
src.add_fingerprint(user)
|
||||
if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant)
|
||||
user.visible_message("<span class='danger'>[user] stuffs [victim] into the biological genetic bombarder!</span>")
|
||||
if(victim.client)
|
||||
victim.client.perspective = EYE_PERSPECTIVE
|
||||
victim.client.eye = src
|
||||
victim.forceMove(src)
|
||||
occupant = victim
|
||||
|
||||
/obj/machinery/xenobio/editor/proc/eject_contents()
|
||||
eject_disk()
|
||||
eject_xeno()
|
||||
|
||||
/obj/machinery/xenobio/editor/proc/eject_xeno()
|
||||
if(occupant)
|
||||
occupant.forceMove(loc)
|
||||
occupant = null
|
||||
|
||||
/obj/item/weapon/circuitboard/bioproddestanalyzer
|
||||
name = T_BOARD("biological product destructive analyzer")
|
||||
build_path = "/obj/machinery/xenobio/extractor"
|
||||
board_type = "machine"
|
||||
origin_tech = list(TECH_DATA = 4, TECH_BIO = 4)
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/manipulator = 2,
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/stock_parts/scanning_module = 3
|
||||
)
|
||||
|
||||
/obj/item/weapon/circuitboard/biobombarder
|
||||
name = T_BOARD("biological genetic bombarder")
|
||||
build_path = "/obj/machinery/xenobio/editor"
|
||||
board_type = "machine"
|
||||
origin_tech = list(TECH_DATA = 4, TECH_BIO = 4)
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/manipulator = 2,
|
||||
/obj/item/weapon/stock_parts/matter_bin = 2,
|
||||
/obj/item/weapon/stock_parts/scanning_module = 2
|
||||
)
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
This file contains:
|
||||
|
||||
Manual Injector:
|
||||
Manually injects chemicals into a xenobiological creature from a linked machine.
|
||||
|
||||
*/
|
||||
/obj/machinery/xenobio2/manualinjector
|
||||
name = "biological injector"
|
||||
desc = "Injects biological organisms that are inserted with the contents of an inserted beaker at the command of a remote computer."
|
||||
density = 1
|
||||
anchored = 1
|
||||
use_power = 1
|
||||
icon = 'icons/obj/biogenerator.dmi'
|
||||
icon_state = "biogen-work"
|
||||
var/mob/living/occupant
|
||||
var/obj/item/weapon/reagent_containers/glass/beaker
|
||||
var/obj/machinery/computer/xenobio2/computer
|
||||
|
||||
circuit = /obj/item/weapon/circuitboard/xenobioinjectormachine
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/New()
|
||||
..()
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
reagents = R
|
||||
R.my_atom = src
|
||||
beaker = new /obj/item/weapon/reagent_containers/glass/beaker(src)
|
||||
circuit = new circuit(src)
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/update_icon()
|
||||
if(beaker)
|
||||
if(occupant)
|
||||
icon_state = "biogen-stand"
|
||||
else
|
||||
icon_state = "biogen-work"
|
||||
else
|
||||
icon_state = "biogen-empty"
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.restrained())
|
||||
return
|
||||
move_into_injector(user,target)
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/proc/move_into_injector(var/mob/user,var/mob/living/victim)
|
||||
if(src.occupant)
|
||||
user << "<span class='danger'>The injector is full, empty it first!</span>"
|
||||
return
|
||||
|
||||
if(!(istype(victim, /mob/living/simple_animal/xeno)) && !emagged)
|
||||
user << "<span class='danger'>This is not a suitable subject for the injector!</span>"
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>[user] starts to put [victim] into the injector!</span>")
|
||||
src.add_fingerprint(user)
|
||||
if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant)
|
||||
user.visible_message("<span class='danger'>[user] stuffs [victim] into the injector!</span>")
|
||||
if(victim.client)
|
||||
victim.client.perspective = EYE_PERSPECTIVE
|
||||
victim.client.eye = src
|
||||
victim.forceMove(src)
|
||||
src.occupant = victim
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/proc/eject_contents()
|
||||
for(var/obj/thing in (contents - component_parts - circuit - beaker))
|
||||
thing.forceMove(loc)
|
||||
if(occupant)
|
||||
occupant.forceMove(loc)
|
||||
occupant = null
|
||||
return
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/proc/eject_beaker()
|
||||
if(beaker)
|
||||
var/obj/item/weapon/reagent_containers/glass/beaker/B = beaker
|
||||
B.loc = loc
|
||||
beaker = null
|
||||
return
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/proc/inject_reagents()
|
||||
if(!occupant)
|
||||
return
|
||||
if(isxeno(occupant))
|
||||
var/mob/living/simple_animal/xeno/X = occupant
|
||||
beaker.reagents.trans_to_holder(X.reagents, computer.transfer_amount, 1, 0)
|
||||
else
|
||||
beaker.reagents.trans_to_mob(occupant, computer.transfer_amount)
|
||||
|
||||
/obj/machinery/xenobio2/manualinjector/attackby(var/obj/item/W, var/mob/user)
|
||||
|
||||
//Let's try to deconstruct first.
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
default_deconstruction_screwdriver(user, W)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/crowbar) && !occupant)
|
||||
default_deconstruction_crowbar(user, W)
|
||||
return
|
||||
|
||||
//are you smashing a beaker in me? Well then insert that shit!
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/glass/beaker))
|
||||
beaker = W
|
||||
user.drop_from_inventory(W)
|
||||
W.loc = src
|
||||
return
|
||||
|
||||
//Did you want to link it?
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
var/obj/item/device/multitool/P = W
|
||||
if(P.connectable)
|
||||
if(istype(P.connectable, /obj/machinery/computer/xenobio2))
|
||||
var/obj/machinery/computer/xenobio2/C = P.connectable
|
||||
computer = C
|
||||
C.injector = src
|
||||
user << "<span class='warning'> You link the [src] to the [P.connectable]!</span>"
|
||||
else
|
||||
user << "<span class='warning'> You store the [src] in the [P]'s buffer!</span>"
|
||||
P.connectable = src
|
||||
return
|
||||
|
||||
if(panel_open)
|
||||
user << "<span class='warning'>Close the panel first!</span>"
|
||||
|
||||
var/obj/item/weapon/grab/G = W
|
||||
|
||||
if(!istype(G))
|
||||
return ..()
|
||||
|
||||
if(G.state < 2)
|
||||
user << "<span class='danger'>You need a better grip to do that!</span>"
|
||||
return
|
||||
|
||||
move_into_injector(user,G.affecting)
|
||||
|
||||
|
||||
/obj/item/weapon/circuitboard/xenobioinjectormachine
|
||||
name = T_BOARD("biological injector")
|
||||
build_path = "/obj/machinery/xenobio2/manualinjector"
|
||||
board_type = "machine"
|
||||
origin_tech = list() //To be filled,
|
||||
req_components = list() //To be filled,
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
This file contains:
|
||||
|
||||
Manual Injector:
|
||||
Manually injects chemicals into a xenobiological creature from a linked machine.
|
||||
|
||||
*/
|
||||
/obj/machinery/computer/xenobio2
|
||||
name = "injector control console"
|
||||
desc = "Used to control mechanized biological injectors."
|
||||
icon_keyboard = "med_key"
|
||||
icon_screen = "dna"
|
||||
light_color = "#315ab4"
|
||||
use_power = 1
|
||||
idle_power_usage = 250
|
||||
active_power_usage = 500
|
||||
circuit = /obj/item/weapon/circuitboard/xenobio2computer
|
||||
var/obj/machinery/xenobio2/manualinjector/injector
|
||||
var/transfer_amount
|
||||
var/active
|
||||
|
||||
/obj/machinery/computer/xenobio2/Destroy()
|
||||
..()
|
||||
injector.computer = null
|
||||
|
||||
/obj/machinery/computer/xenobio2/attack_hand(mob/user)
|
||||
if(..())
|
||||
return 1
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/computer/xenobio2/attackby(var/obj/item/W, var/mob/user)
|
||||
|
||||
//Did you want to link it?
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
var/obj/item/device/multitool/P = W
|
||||
if(P.connectable)
|
||||
if(istype(P.connectable, /obj/machinery/xenobio2/manualinjector))
|
||||
var/obj/machinery/xenobio2/manualinjector/I = P.connectable
|
||||
injector = I
|
||||
I.computer = src
|
||||
user << "<span class='warning'> You link the [src] to the [P.connectable]!</span>"
|
||||
else
|
||||
user << "<span class='warning'> You store the [src] in the [P]'s buffer!</span>"
|
||||
P.connectable = src
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/xenobio2/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!user)
|
||||
return
|
||||
if(!injector)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
data["activity"] = active
|
||||
data["beaker"] = injector.beaker
|
||||
if(injector.occupant)
|
||||
data["occupied"] = 1
|
||||
if(isxeno(injector.occupant))
|
||||
var/mob/living/simple_animal/xeno/X = injector.occupant
|
||||
data["instability"] = (X.mut_level / X.mut_max) * 100
|
||||
else
|
||||
data["instability"] = null
|
||||
|
||||
if(injector.beaker)
|
||||
data["reagentAmount"] = injector.beaker.reagents.total_volume
|
||||
data["reagentMax"] = injector.beaker.reagents.maximum_volume
|
||||
data["reagentMin"] = 0
|
||||
else
|
||||
data["reagentAmount"] = null
|
||||
data["reagentMax"] = 1
|
||||
data["reagentMin"] = 0
|
||||
|
||||
if(injector.occupant)
|
||||
data["occupantHealth"] = injector.occupant.health
|
||||
data["occupantHealthMax"] = injector.occupant.maxHealth
|
||||
else
|
||||
data["occupantHealth"] = null
|
||||
data["occupantHealthMax"] = null
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "xenobio_computer.tmpl", "Injector Control Console UI", 470, 450)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/xenobio2/Topic(href, href_list)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["inject_target"])
|
||||
active = 1
|
||||
spawn(5)
|
||||
injector.inject_reagents()
|
||||
active = 0
|
||||
if(href_list["eject_occupant"])
|
||||
injector.eject_contents()
|
||||
|
||||
if(href_list["eject_beaker"])
|
||||
injector.eject_beaker()
|
||||
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
/obj/item/weapon/circuitboard/xenobio2computer
|
||||
name = T_BOARD("injector control console")
|
||||
build_path = "/obj/item/weapon/circuitboard/xenobio2computer"
|
||||
board_type = "computer"
|
||||
origin_tech = list() //To be filled,
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
Here lives the slime replicator
|
||||
This machine consumes cores to create a slime.
|
||||
To create more of these cores, stick the slime core in the extractor.
|
||||
*/
|
||||
/obj/machinery/slime/replicator
|
||||
name = "slime core growth apparatus"
|
||||
desc = "A machine for creating slimes from cores. Amazing!"
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "restruct_0"
|
||||
density = 1
|
||||
anchored = 1
|
||||
circuit = /obj/item/weapon/circuitboard/slimereplicator
|
||||
var/obj/item/xenoproduct/slime/core/core = null
|
||||
var/inuse
|
||||
var/occupiedcolor = "#22FF22"
|
||||
var/emptycolor = "#FF2222"
|
||||
var/operatingcolor = "#FFFF22"
|
||||
|
||||
/obj/machinery/slime/replicator/New()
|
||||
..()
|
||||
circuit = new circuit(src)
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||
component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
|
||||
RefreshParts()
|
||||
update_light_color()
|
||||
|
||||
|
||||
/obj/machinery/slime/replicator/attackby(var/obj/item/W, var/mob/user)
|
||||
//Let's try to deconstruct first.
|
||||
if(istype(W, /obj/item/weapon/screwdriver) && !inuse)
|
||||
default_deconstruction_screwdriver(user, W)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/crowbar))
|
||||
default_deconstruction_crowbar(user, W)
|
||||
return
|
||||
|
||||
var/obj/item/xenoproduct/slime/core/G = W
|
||||
|
||||
if(!istype(G))
|
||||
return ..()
|
||||
|
||||
if(core)
|
||||
user << "<span class='warning'>[src] is already filled!</span>"
|
||||
return
|
||||
if(panel_open)
|
||||
user << "<span class='warning'>Close the panel first!</span>"
|
||||
core = G
|
||||
user.drop_from_inventory(G)
|
||||
G.forceMove(src)
|
||||
update_light_color()
|
||||
|
||||
/obj/machinery/slime/replicator/proc/update_light_color()
|
||||
if(src.core && !(inuse))
|
||||
set_light(2, 2, occupiedcolor)
|
||||
else if(src.core)
|
||||
set_light(2, 2, operatingcolor)
|
||||
else
|
||||
set_light(2, 2, emptycolor)
|
||||
|
||||
/obj/machinery/slime/replicator/proc/replicate_slime()
|
||||
if(!src.core)
|
||||
src.visible_message("\icon[src] [src] pings unhappily.")
|
||||
else if(inuse)
|
||||
return
|
||||
|
||||
inuse = 1
|
||||
update_light_color()
|
||||
icon_state = "restruct_1"
|
||||
spawn(30)
|
||||
var/mob/living/simple_animal/xeno/slime/S = new(src)
|
||||
S.traitdat = core.traits
|
||||
S.ProcessTraits()
|
||||
qdel(core)
|
||||
spawn(30)
|
||||
inuse = 0
|
||||
eject_slime()
|
||||
icon_state = "restruct_0"
|
||||
update_light_color()
|
||||
src.updateUsrDialog()
|
||||
|
||||
/obj/machinery/slime/replicator/proc/eject_slime()
|
||||
for(var/mob/thing in contents)
|
||||
thing.forceMove(loc)
|
||||
|
||||
/obj/machinery/slime/replicator/proc/eject_core()
|
||||
if(core)
|
||||
core.forceMove(loc)
|
||||
core = null
|
||||
|
||||
/obj/machinery/slime/replicator/proc/eject_contents()
|
||||
eject_slime()
|
||||
eject_core()
|
||||
|
||||
//Here lies the UI
|
||||
/obj/machinery/slime/replicator/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/slime/replicator/interact(mob/user as mob)
|
||||
var/dat = ""
|
||||
if(!inuse)
|
||||
dat = {"
|
||||
<b>Slime core container holds:</b><br>
|
||||
[core]<br>
|
||||
"}
|
||||
if (core && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=\ref[src];action=replicate'>Start the replication process</a><BR>"
|
||||
if(core)
|
||||
dat += "<A href='?src=\ref[src];action=eject'>Eject the core</a><BR>"
|
||||
else
|
||||
dat += "Please wait..."
|
||||
var/datum/browser/popup = new(user, "Slime Replicator", "Slime Replicator", src)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/slime/replicator/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
switch(href_list["action"])
|
||||
if ("replicate")
|
||||
replicate_slime()
|
||||
if("eject")
|
||||
eject_core()
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
//Circuit board below,
|
||||
/obj/item/weapon/circuitboard/slimereplicator
|
||||
name = T_BOARD("Slime replicator")
|
||||
build_path = "/obj/machinery/slime/replicator"
|
||||
board_type = "machine"
|
||||
origin_tech = list(TECH_DATA = 3, TECH_BIO = 3)
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/manipulator = 2,
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/stock_parts/micro_laser = 1
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Slime specific life events go here.
|
||||
*/
|
||||
#define HAPPYLEVEL 200
|
||||
#define ANGRYLEVEL 10
|
||||
/mob/living/simple_animal/xeno/slime/Life()
|
||||
. = ..()
|
||||
if(..())
|
||||
if(health)
|
||||
if(is_child)
|
||||
if(nutrition >= 275)
|
||||
growthcounter++
|
||||
nutrition -= hunger_factor
|
||||
if(nutrition <= 75)
|
||||
growthcounter--
|
||||
if(growthcounter >= growthpoint)
|
||||
src.GrowUp()
|
||||
|
||||
else
|
||||
if(nutrition < 0)
|
||||
nutrition = 0
|
||||
if((prob(10) && !emote_on)) //Slimes might display their food-based emotions over time.
|
||||
var/image/I = new(src.icon)
|
||||
I.color = "#FFFFFF"
|
||||
I.layer = src.layer + 0.2
|
||||
if((nutrition >= HAPPYLEVEL))
|
||||
if((nutrition >= 1.5 * HAPPYLEVEL))
|
||||
I.icon_state = "aslime-:33"
|
||||
else
|
||||
I.icon_state = "aslime-:3"
|
||||
|
||||
else if((nutrition > ANGRYLEVEL))
|
||||
if((nutrition >= 10 * ANGRYLEVEL))
|
||||
I.icon_state = "aslime-pout"
|
||||
else if((nutrition >= 5 * ANGRYLEVEL))
|
||||
I.icon_state = "aslime-sad"
|
||||
else
|
||||
I.icon_state = "aslime-angry"
|
||||
overlays += I
|
||||
emote_on = 1
|
||||
spawn(30)
|
||||
GenerateAdultIcon()
|
||||
emote_on = null
|
||||
|
||||
else
|
||||
if(is_child)
|
||||
icon_state = "slime baby dead"
|
||||
else
|
||||
overlays.Cut()
|
||||
icon_state = "slime adult dead"
|
||||
color = traitdat.traits[TRAIT_XENO_COLOR]
|
||||
|
||||
return 0 //Everything worked okay
|
||||
|
||||
return //xeno/Life() returned 0.
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Slime specific procs go here.
|
||||
*/
|
||||
#define SHINYOVERLAY 0
|
||||
#define LIGHTOVERLAY 1
|
||||
#define MAXOVERLAY 2 //Should be 1 + last overlay, to give the chance for matte slimes
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/RandomizeTraits()
|
||||
traitdat.traits[TRAIT_XENO_COLDRES] = rand(30,270)
|
||||
traitdat.traits[TRAIT_XENO_HEATRES] = rand(30,270)
|
||||
traitdat.traits[TRAIT_XENO_CHEMVOL] = round(rand(20,40)) //Wow, a slime core with the capacity to hold 2/3rd's a beaker's worth of chemicals.
|
||||
traitdat.traits[TRAIT_XENO_HEALTH] = round(rand(50, 75))
|
||||
traitdat.traits[TRAIT_XENO_HUNGER] = rand(1, 20)
|
||||
traitdat.traits[TRAIT_XENO_STARVEDAMAGE] = rand(1, 4)
|
||||
traitdat.traits[TRAIT_XENO_EATS] = prob(95) //Odds are, that thing'll need to eat.
|
||||
traitdat.traits[TRAIT_XENO_CHROMATIC] = prob(5)
|
||||
if(traitdat.traits[TRAIT_XENO_CHROMATIC])
|
||||
traitdat.traits[TRAIT_XENO_HOSTILE] = 0
|
||||
else
|
||||
traitdat.traits[TRAIT_XENO_HOSTILE] = prob(30)
|
||||
traitdat.traits[TRAIT_XENO_GLOW_STRENGTH] = round(rand(1,3))
|
||||
traitdat.traits[TRAIT_XENO_GLOW_RANGE] = round(rand(1,3))
|
||||
traitdat.traits[TRAIT_XENO_STRENGTH] = round(rand(4,9))
|
||||
traitdat.traits[TRAIT_XENO_STR_RANGE] =round(rand(0,2))
|
||||
traitdat.traits[TRAIT_XENO_CANLEARN] = prob(68)
|
||||
traitdat.traits[TRAIT_XENO_SPEED] = round(rand(-10,10))
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/proc/GrowUp()
|
||||
GenerateAdult()
|
||||
|
||||
maxHealth = traitdat.get_trait(TRAIT_XENO_HEALTH)
|
||||
health = maxHealth
|
||||
is_child = 0
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/Mutate()
|
||||
..()
|
||||
cores = round(rand(1,9))
|
||||
if(is_child)
|
||||
RandomizeTraits()
|
||||
GenerateChild()
|
||||
else
|
||||
GenerateAdult()
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/proc/GenerateChild()
|
||||
overlays.Cut()
|
||||
name = "[nameVar] baby slime"
|
||||
real_name = "[nameVar] baby slime"
|
||||
desc = "A shifting blob of [nameVar] goo."
|
||||
icon_state = "slime baby"
|
||||
icon_living = "slime baby"
|
||||
icon_dead = "slime baby dead"
|
||||
color = traitdat.traits[TRAIT_XENO_COLOR]
|
||||
maxHealth = traitdat.traits[TRAIT_XENO_HEALTH]/2
|
||||
health = maxHealth
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/proc/GenerateAdult()
|
||||
overlays.Cut()
|
||||
name = "[nameVar] slime"
|
||||
real_name = "[nameVar] slime"
|
||||
desc = "A shifting mass of [nameVar] goo."
|
||||
color = ""
|
||||
icon_state = ""
|
||||
overlay = round(rand(0, MAXOVERLAY))
|
||||
GenerateAdultIcon()
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/proc/GenerateAdultIcon() //Hack and slash adventure game to make slimes have no color on light effects later
|
||||
overlays.Cut()
|
||||
var/image/Img = new(src.icon)
|
||||
Img.icon_state = "slime adult"
|
||||
Img.color = traitdat.traits[TRAIT_XENO_COLOR]
|
||||
Img.layer = src.layer
|
||||
overlays += Img
|
||||
|
||||
switch(overlay)
|
||||
if(SHINYOVERLAY)
|
||||
var/image/I = new(src.icon)
|
||||
I.icon = src.icon
|
||||
I.icon_state = "slime shiny"
|
||||
I.layer = src.layer + 0.1
|
||||
I.color = "#FFFFFF"
|
||||
overlays += I
|
||||
if(LIGHTOVERLAY)
|
||||
var/image/I = new(src.icon)
|
||||
I.icon = src.icon
|
||||
I.icon_state = ""
|
||||
I.icon_state = "slime light"
|
||||
I.layer = src.layer + 0.1
|
||||
I.color = "#FFFFFF"
|
||||
overlays += I
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/handle_reagents()
|
||||
if(!stasis)
|
||||
if(!reagents)
|
||||
return
|
||||
if(reagents.total_volume <= 0)
|
||||
return
|
||||
if(reagents.has_reagent("docilitytoxin")) //Toxin that makes them docile? Good for quelling angry mobs.
|
||||
hostile = 0
|
||||
traitdat.traits[TRAIT_XENO_HOSTILE] = 0
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/ProcessTraits()
|
||||
..()
|
||||
if(is_child)
|
||||
GenerateChild()
|
||||
else
|
||||
GenerateAdult()
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Slime definitions, Life and New live here.
|
||||
*/
|
||||
/mob/living/simple_animal/xeno/slime //Adult values are found here
|
||||
nameVar = "grey" //When mutated, nameVar might change.
|
||||
desc = "A shifting, mass of goo."
|
||||
speak_emote = list("garbles", "chirps", "blurbles")
|
||||
colored = 1
|
||||
color = "#CACACA"
|
||||
icon = 'icons/mob/slime2.dmi'
|
||||
icon_state = "slime adult"
|
||||
icon_living = "slime adult"
|
||||
icon_dead = "slime adult dead"
|
||||
internal_vol = 200
|
||||
mut_max = 200
|
||||
mutable = COLORMUT
|
||||
var/is_child = 1
|
||||
var/cores = 3
|
||||
var/growthcounter = 0
|
||||
var/growthpoint = 150 //At what point they grow up.
|
||||
var/shiny = 0
|
||||
move_to_delay = 17 //Slimes shouldn't be able to go faster than humans.
|
||||
default_chems = list("slimejelly" = 5)
|
||||
attacktext = "absorbed some of"
|
||||
response_help = "pats"
|
||||
response_disarm = "tries to stop"
|
||||
response_harm = "hits"
|
||||
|
||||
var/emote_on = null
|
||||
|
||||
maleable = MAX_MALEABLE
|
||||
|
||||
//Slimes can speak all of the languages, oh no!
|
||||
universal_speak = 1
|
||||
speak_chance = 1
|
||||
speak = list("Hello?",
|
||||
"Where is this going?",
|
||||
"What is that?",
|
||||
"What is in the box?",
|
||||
"Cargo.",
|
||||
"Transport?",
|
||||
"Special?",
|
||||
"Slime?")
|
||||
|
||||
//Overlay information
|
||||
var/overlay = 1 // 1 = normal lighting, 0 = shiny, 2 = too shiny, -1 = no overlay
|
||||
|
||||
chemreact = list( "nutriment" = list("nutr" = 0.5),
|
||||
"radium" = list("toxic" = 0.3, "mut" = 1),
|
||||
"mutagen" = list("nutr" = 0.4, "mut" = 2),
|
||||
"water" = list("nutr" = -0.1),
|
||||
"milk" = list("nutr" = 0.3),
|
||||
"sacid" = list("toxic" = 1),
|
||||
"pacid" = list("toxic" = 2),
|
||||
"chlorine" = list("toxic" = 0.5),
|
||||
"ammonia" = list("toxic" = 0.5),
|
||||
"sodawater" = list("toxic" = 0.1, "nutr" = -0.1),
|
||||
"beer" = list("nutr" = 0.6),
|
||||
"diethylamine" = list("nutr" = 0.9),
|
||||
"sugar" = list("toxic" = 0.4, "nutr" = 0.2),
|
||||
"eznutrient" = list("nutr" = 0.8),
|
||||
"cryoxadone" = list("toxic" = 0.4),
|
||||
"flourine" = list("toxic" = 0.1),
|
||||
"robustharvest" = list("nutr" = 1.5),
|
||||
"glucose" = list("nutr" = 0.5),
|
||||
"blood" = list("nutr" = 0.75, "toxic" = 0.05, "mut" = 0.45),
|
||||
"fuel" = list("toxic" = 0.4),
|
||||
"toxin" = list("toxic" = 0.5),
|
||||
"carpotoxin" = list("toxic" = 1, "mut" = 1.5),
|
||||
"phoron" = list("toxic" = 1.5, "mut" = 0.03),
|
||||
"cyanide" = list("toxic" = 3.5),
|
||||
"slimejelly" = list("nutr" = 0.5),
|
||||
"amutationtoxin" = list("toxic" = 0.1, "heal" = 1.5, "mut" = 3),
|
||||
"mutationtoxin" = list("toxic" = 0.1, "heal" = 1, "mut" = 1.5),
|
||||
"gold" = list("heal" = 0.3, "nutr" = 0.7, "mut" = 0.3),
|
||||
"uranium" = list("heal" = 0.3, "toxic" = 0.7, "mut" = 1.2),
|
||||
"glycerol" = list("nutr" = 0.6),
|
||||
"woodpulp" = list("heal" = 0.1, "nutr" = 0.7),
|
||||
"docilitytoxin" = list("nutr" = 0.3) )
|
||||
|
||||
/mob/living/simple_animal/xeno/slime/New()
|
||||
..()
|
||||
for(var/datum/language/L in (typesof(/datum/language) - /datum/language))
|
||||
languages += L
|
||||
speak += "[station_name()]?"
|
||||
traitdat.source = "Slime"
|
||||
resistances[BURN] = 4
|
||||
resistances[BRUTE] = 0.2
|
||||
resistances[TOX] = 1.5
|
||||
GenerateChild()
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Slime core lives here.
|
||||
*/
|
||||
/obj/item/xenoproduct/slime/core
|
||||
name = "slime core"
|
||||
desc = "Gooey."
|
||||
icon = 'icons/mob/slime2.dmi'
|
||||
icon_state = "slime extract"
|
||||
source = "Slime"
|
||||
product = "core"
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Slime cube lives here.
|
||||
*/
|
||||
/obj/item/slime_cube
|
||||
name = "slimy monkey cube"
|
||||
desc = "Wonder what might come out of this."
|
||||
icon = 'icons/mob/slime2.dmi'
|
||||
icon_state = "slime cube"
|
||||
var/searching = 0
|
||||
|
||||
/obj/item/slime_cube/attack_self(mob/user as mob)
|
||||
if(!searching)
|
||||
user << "<span class='warning'>You stare at the slimy cube, watching as some activity occurs.</span>"
|
||||
icon_state = "slime cube active"
|
||||
searching = 1
|
||||
request_player()
|
||||
spawn(600) reset_search()
|
||||
|
||||
/obj/item/slime_cube/proc/request_player()
|
||||
for(var/mob/observer/dead/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(O.client)
|
||||
if(O.client.prefs.be_special & BE_ALIEN)
|
||||
question(O.client)
|
||||
|
||||
/obj/item/slime_cube/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C) return
|
||||
var/response = alert(C, "Someone is requesting a soul for a promethean. Would you like to play as one?", "Promethean request", "Yes", "No", "Never for this round")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as a promethean?", "Promethean request", "Yes", "No")
|
||||
if(!C || 2 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
|
||||
if(response == "Yes")
|
||||
transfer_personality(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special ^= BE_ALIEN
|
||||
|
||||
/obj/item/slime_cube/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
|
||||
icon_state = "slime cube"
|
||||
if(searching == 1)
|
||||
searching = 0
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
M.show_message("<span class='warning'>The activity in the cube dies down. Maybe it will spark another time.</span>")
|
||||
|
||||
/obj/item/slime_cube/proc/transfer_personality(var/mob/candidate)
|
||||
announce_ghost_joinleave(candidate, 0, "They are a promethean now.")
|
||||
src.searching = 2
|
||||
var/mob/living/carbon/human/S = new(get_turf(src))
|
||||
S.client = candidate.client
|
||||
S. << "<b>You are a promethean, brought into existence on [station_name()].</b>"
|
||||
S.mind.assigned_role = "Promethean"
|
||||
S.set_species("Promethean")
|
||||
S.shapeshifter_set_colour("#05FF9B")
|
||||
for(var/mob/M in viewers(get_turf_or_move(loc)))
|
||||
M.show_message("<span class='warning'>The monkey cube suddenly takes the shape of a humanoid!</span>")
|
||||
var/newname = sanitize(input(S, "You are a Promethean. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN)
|
||||
if (newname)
|
||||
S.real_name = newname
|
||||
S.name = S.real_name
|
||||
S.dna.real_name = newname
|
||||
if(S.mind) S.mind.name = S.name
|
||||
qdel(src)
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Basic definition of creatures for Xenobiology
|
||||
|
||||
Includes:
|
||||
Proc for metabolism
|
||||
Proc for mutating
|
||||
Procs for copying speech, if applicable
|
||||
Procs for targeting
|
||||
*/
|
||||
/mob/living/simple_animal/xeno/proc/ProcessTraits()
|
||||
if(maleable >= MAX_MALEABLE)
|
||||
maxHealth = traitdat.get_trait(TRAIT_XENO_HEALTH)
|
||||
health = maxHealth
|
||||
if(traitdat.chemlist.len) //Let's make sure that this has a length.
|
||||
chemreact = traitdat.chemlist
|
||||
else
|
||||
traitdat.chemlist = chemreact
|
||||
chromatic = traitdat.traits[TRAIT_XENO_CHROMATIC]
|
||||
if(maleable >= MINOR_MALEABLE)
|
||||
if(colored)
|
||||
color = traitdat.traits[TRAIT_XENO_COLOR]
|
||||
speed = traitdat.traits[TRAIT_XENO_SPEED]
|
||||
hunger_factor = traitdat.traits[TRAIT_XENO_HUNGER]
|
||||
starve_damage = traitdat.traits[TRAIT_XENO_STARVEDAMAGE]
|
||||
minbodytemp = T20C - traitdat.traits[TRAIT_XENO_COLDRES]
|
||||
maxbodytemp = T20C + traitdat.traits[TRAIT_XENO_HEATRES]
|
||||
|
||||
if(traitdat.traits[TRAIT_XENO_BIOLUMESCENT])
|
||||
set_light(traitdat.traits[TRAIT_XENO_GLOW_RANGE], traitdat.traits[TRAIT_XENO_GLOW_STRENGTH], traitdat.traits[TRAIT_XENO_BIO_COLOR])
|
||||
else
|
||||
set_light(0, 0, "#000000") //Should kill any light that shouldn't be there.
|
||||
if(!(chromatic))
|
||||
hostile = 0 //No. No laser-reflecting hostile creatures. Bad.
|
||||
else
|
||||
hostile = traitdat.traits[TRAIT_XENO_HOSTILE]
|
||||
|
||||
speed = traitdat.traits[TRAIT_XENO_SPEED]
|
||||
|
||||
if(traitdat.traits[TRAIT_XENO_CANSPEAK])
|
||||
speak_chance = traitdat.traits[TRAIT_XENO_SPEAKCHANCE]
|
||||
else
|
||||
speak_chance = 0
|
||||
|
||||
melee_damage_lower = traitdat.get_trait(TRAIT_XENO_STRENGTH) - traitdat.get_trait(TRAIT_XENO_STR_RANGE)
|
||||
melee_damage_upper = traitdat.traits[TRAIT_XENO_STRENGTH] + traitdat.get_trait(TRAIT_XENO_STR_RANGE)
|
||||
|
||||
|
||||
|
||||
//Metabolism proc, simplified for xenos. Heavily based on botanical metabolism.
|
||||
/mob/living/simple_animal/xeno/proc/handle_reagents()
|
||||
if(!stasis)
|
||||
if(!reagents)
|
||||
return
|
||||
if(reagents.total_volume <= 0)
|
||||
return
|
||||
|
||||
//Let's handle some chemical smoke, for scientific smoke bomb purposes.
|
||||
for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
|
||||
if(smoke.reagents.total_volume)
|
||||
smoke.reagents.trans_to_mob(src, 10, CHEM_BLOOD, copy = 1)
|
||||
|
||||
reagents.trans_to_obj(temp_chem_holder, min(reagents.total_volume,rand(1,4)))
|
||||
var/reagent_total
|
||||
var/list/reagent_response = list()
|
||||
for(var/datum/reagent/R in temp_chem_holder.reagents.reagent_list)
|
||||
|
||||
reagent_total = temp_chem_holder.reagents.get_reagent_amount(R.id)
|
||||
|
||||
reagent_response = chemreact[R.id]
|
||||
|
||||
if(reagent_response["toxic"])
|
||||
adjustToxLoss(reagent_response["toxic"] * reagent_total)
|
||||
|
||||
if(reagent_response["heal"])
|
||||
heal_overall_damage(reagent_response["heal"] * reagent_total)
|
||||
|
||||
if(reagent_response["nutr"])
|
||||
nutrition += reagent_response["nutr"] * reagent_total
|
||||
|
||||
if(reagent_response["mut"])
|
||||
mut_level += reagent_response["mut"] * reagent_total
|
||||
|
||||
temp_chem_holder.reagents.clear_reagents()
|
||||
|
||||
return 1 //Everything worked out okay.
|
||||
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/xeno/proc/Mutate()
|
||||
nameVar = "mutated"
|
||||
if((COLORMUT & mutable))
|
||||
traitdat.traits[TRAIT_XENO_COLOR] = "#"
|
||||
for(var/i=0, i<6, i++)
|
||||
traitdat.traits[TRAIT_XENO_COLOR] += pick(hexNums)
|
||||
traitdat.traits[TRAIT_XENO_BIO_COLOR] = "#"
|
||||
for(var/i=0, i<6, i++)
|
||||
traitdat.traits[TRAIT_XENO_BIO_COLOR] += pick(hexNums)
|
||||
|
||||
RandomChemicals()
|
||||
//if(SPECIESMUT & mutable)
|
||||
//Placeholder, currently no xenos that have species mutations.
|
||||
RandomizeTraits()
|
||||
ProcessTraits()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/xeno/proc/RandomizeTraits()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/xeno/hear_say(var/message, var/verb = "says", var/datum/language/language, var/alt_name = "",var/italics = 0, var/mob/speaker = null)
|
||||
if(traitdat.traits[TRAIT_XENO_CANLEARN])
|
||||
/*
|
||||
Until this gets sorted out to a functioning point, or waiting on Psi's saycode update.
|
||||
var/learned_message = say_understands(speaker, language)
|
||||
if(!message || isxeno(speaker))
|
||||
return
|
||||
if(learned_message) //Is it understood?
|
||||
var/complete_message = ",[language.key] [message]"
|
||||
if(!(complete_message in speak))
|
||||
speech_buffer.Add(complete_message)
|
||||
log_debug("Added '[complete_message]'.")
|
||||
else
|
||||
*/
|
||||
if(!(message in speak))
|
||||
speech_buffer.Add(message)
|
||||
..(message,verb,language,alt_name,italics,speaker)
|
||||
|
||||
/mob/living/simple_animal/xeno/proc/ProcessSpeechBuffer()
|
||||
if(speech_buffer.len)
|
||||
if(prob(traitdat.get_trait(TRAIT_XENO_LEARNCHANCE)) && traitdat.get_trait(TRAIT_XENO_CANLEARN))
|
||||
var/chosen = pick(speech_buffer)
|
||||
speak.Add(chosen)
|
||||
/* Uncoment for logging of speech list.
|
||||
log_debug("Added [chosen] to speak list.")
|
||||
log_debug("Speechlist cut.") */
|
||||
speech_buffer.Cut()
|
||||
//
|
||||
/mob/living/simple_animal/xeno/proc/BuildReagentLists()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/xeno/proc/bulet_act(var/obj/item/projectile/P)
|
||||
//Shamelessly stolen from ablative armor.
|
||||
if((traitdat.traits[TRAIT_XENO_CHROMATIC]) && istype(P, /obj/item/projectile/beam))
|
||||
visible_message("<span class='danger')\The beam reflects off of the [src]!</span>")
|
||||
// Find a turf near or on the original location to bounce to
|
||||
var/new_x = P.starting.x + pick(0, -1, 1, -2, 2)
|
||||
var/new_y = P.starting.y + pick(0, -1, 1, -2, 2)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
P.redirect(new_x, new_y, curloc, src)
|
||||
|
||||
return
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/xeno/proc/RandomChemicals()
|
||||
traitdat.chems.Cut() //Clear the amount first.
|
||||
|
||||
var/num_chems = round(rand(1,4))
|
||||
var/list/chemchoices = xenoChemList
|
||||
|
||||
for(var/i = 1 to num_chems)
|
||||
var/chemtype = pick(chemchoices)
|
||||
chemchoices -= chemtype
|
||||
var/chemamount = rand(1,5)
|
||||
traitdat.chems[chemtype] = chemamount
|
||||
|
||||
traitdat.chems += default_chems
|
||||
@@ -0,0 +1,97 @@
|
||||
//First we define certain flags, can be expanded upon later.
|
||||
|
||||
/*
|
||||
Basic definition of creatures for Xenobiology
|
||||
Also includes Life and New
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/xeno
|
||||
name = "Xeno"
|
||||
real_name = "Xeno"
|
||||
desc = "Something's broken, yell at someone."
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
attacktext = "hit"
|
||||
attack_sound = null
|
||||
friendly = "touches"
|
||||
environment_smash = 0
|
||||
|
||||
var/datum/xeno/traits/traitdat //Trait datum.
|
||||
|
||||
var/internal_vol = 1000 //Internal volume for ingesting/injected reagents
|
||||
|
||||
var/obj/temp_chem_holder //Used in handle_reagents()
|
||||
|
||||
var/mutable = NOMUT //Flag for mutation.
|
||||
var/nameVar = "Blah"
|
||||
var/instability = 0
|
||||
var/stasis = 0
|
||||
var/mut_level = 0 //How mutated a specimen is. Irrelevant while mutable = NOMUT.
|
||||
var/mut_max = 100000
|
||||
var/colored = 1
|
||||
var/maleable = MIN_MALEABLE //How easy is it to manipulate traitdat.traits after it's alive.
|
||||
var/stability = 0 //Used in gene manipulation
|
||||
|
||||
//Traits that might not be maleable.
|
||||
var/list/chemreact = list()
|
||||
var/hunger_factor = 10
|
||||
var/chromatic = 0
|
||||
var/starve_damage = 0
|
||||
|
||||
//Used for speech learning
|
||||
var/list/speech_buffer = list()
|
||||
|
||||
var/list/default_chems = list()
|
||||
|
||||
|
||||
//Life additions
|
||||
/mob/living/simple_animal/xeno/Life()
|
||||
if(src.stat == DEAD)
|
||||
return 0
|
||||
|
||||
if(stasis)
|
||||
stasis--
|
||||
if(stasis < 0)
|
||||
stasis = 0
|
||||
return 0
|
||||
..()
|
||||
handle_reagents()
|
||||
if((mut_level >= mut_max) && !(mutable & NOMUT))
|
||||
Mutate()
|
||||
mut_level -= mut_max
|
||||
|
||||
ProcessSpeechBuffer()
|
||||
|
||||
//Have to feed the xenos somehow.
|
||||
if(nutrition < 0)
|
||||
nutrition = 0
|
||||
if((nutrition > 0 ) && traitdat.traits[TRAIT_XENO_EATS])
|
||||
if(nutrition >= 300)
|
||||
nutrition -= hunger_factor
|
||||
else
|
||||
if(traitdat.traits[TRAIT_XENO_EATS])
|
||||
health = starve_damage
|
||||
|
||||
return 1 //Everything worked okay.
|
||||
|
||||
/mob/living/simple_animal/xeno/New()
|
||||
|
||||
traitdat = new()
|
||||
|
||||
ProcessTraits()
|
||||
|
||||
..()
|
||||
if(colored)
|
||||
color = traitdat.get_trait(TRAIT_XENO_COLOR)
|
||||
create_reagents(internal_vol)
|
||||
temp_chem_holder = new()
|
||||
temp_chem_holder.create_reagents(20)
|
||||
nutrition = 350
|
||||
for(var/R in default_chems)
|
||||
traitdat.chems[R] = default_chems[R]
|
||||
|
||||
traitdat.source = name
|
||||
|
||||
if(!health)
|
||||
stat = DEAD
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Xenobiological product lives here as a basic type.
|
||||
*/
|
||||
/obj/item/xenoproduct
|
||||
name = "Xenobiological product"
|
||||
desc = "How did this get here?."
|
||||
icon = 'icons/mob/slime2.dmi'
|
||||
icon_state = "slime extract"
|
||||
var/datum/xeno/traits/traits
|
||||
var/source = "Unknown"
|
||||
var/product = "mess"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/* What this file contains:
|
||||
|
||||
* A specialized stun prod, for handling fiesty slimes
|
||||
|
||||
* A specialized stun gun, for handling many fiesty slimes
|
||||
|
||||
* A stun projectile for handling xenomorphs.
|
||||
|
||||
*/
|
||||
/obj/item/weapon/melee/baton/slime
|
||||
name = "slimebaton"
|
||||
desc = "A modified stun baton designed to stun slimes for handling."
|
||||
icon_state = "slimebaton"
|
||||
item_state = "slimebaton"
|
||||
slot_flags = SLOT_BELT
|
||||
force = 9
|
||||
lightcolor = "#33CCFF"
|
||||
origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 4)
|
||||
agonyforce = 10 //It's not supposed to be great at stunning human beings.
|
||||
var/stasisforce = 60 //How much stasis it does to slimes, and 1/3rd to non-slimes.
|
||||
|
||||
/obj/item/weapon/melee/baton/slime/attack(mob/M, mob/user)
|
||||
if(istype(M, /mob/living/simple_animal/xeno))
|
||||
var/mob/living/simple_animal/xeno/X = M
|
||||
if(istype(M, /mob/living/simple_animal/xeno/slime))
|
||||
X.stasis += stasisforce
|
||||
else
|
||||
X.stasis += (stasisforce / 6)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/melee/baton/slime/loaded/New()
|
||||
..()
|
||||
bcell = new/obj/item/weapon/cell/high(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
// Xeno stun gun + projectile
|
||||
/obj/item/weapon/gun/energy/taser/xeno
|
||||
name = "xeno taser gun"
|
||||
desc = "Straight out of NT's testing laboratories, this small gun is used to subdue non-humanoid xeno life forms. While marketed towards handling slimes, it may be useful for other creatures."
|
||||
icon_state = "taserold"
|
||||
fire_sound = 'sound/weapons/taser2.ogg'
|
||||
max_shots = 10
|
||||
projectile_type = /obj/item/projectile/beam/stun/xeno
|
||||
|
||||
/obj/item/projectile/beam/stun/xeno
|
||||
icon_state = "omni"
|
||||
agony = 4
|
||||
var/stasisforce = 40
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
||||
|
||||
/obj/item/projectile/beam/stun/xeno/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/simple_animal/xeno))
|
||||
var/mob/living/simple_animal/xeno/X = target
|
||||
if(istype(target, /mob/living/simple_animal/xeno/slime))
|
||||
X.stasis += stasisforce
|
||||
else
|
||||
X.stasis += (stasisforce / 8)
|
||||
else
|
||||
..()
|
||||
Reference in New Issue
Block a user