This commit is contained in:
LetterJay
2017-12-27 07:08:26 -06:00
parent 2e6b034493
commit 0381491643
9 changed files with 602 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
/datum/action/item_action/zoom_speed_action
name = "Toggle Zooming Speed"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "projectile"
background_icon_state = "bg_tech"
/datum/action/item_action/zoom_lock_action
name = "Switch Zoom Mode"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "zoom_mode"
background_icon_state = "bg_tech"

View File

@@ -0,0 +1,170 @@
#define MONKEYS_ESCAPED 1
#define MONKEYS_LIVED 2
#define MONKEYS_DIED 3
#define DISEASE_LIVED 4
/datum/antagonist/monkey
name = "Monkey"
job_rank = ROLE_MONKEY
roundend_category = "monkeys"
var/datum/objective_team/monkey/monkey_team
/datum/antagonist/monkey/on_gain()
. = ..()
SSticker.mode.ape_infectees += owner
owner.special_role = "Infected Monkey"
var/datum/disease/D = new /datum/disease/transformation/jungle_fever
if(!owner.current.HasDisease(D))
D.affected_mob = owner
owner.current.viruses += D
else
QDEL_NULL(D)
/datum/antagonist/monkey/greet()
to_chat(owner, "<b>You are a monkey now!</b>")
to_chat(owner, "<b>Bite humans to infect them, follow the orders of the monkey leaders, and help fellow monkeys!</b>")
to_chat(owner, "<b>Ensure at least one infected monkey escapes on the Emergency Shuttle!</b>")
to_chat(owner, "<b><i>As an intelligent monkey, you know how to use technology and how to ventcrawl while wearing things.</i></b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/antagonist/monkey/on_removal()
. = ..()
owner.special_role = null
SSticker.mode.ape_infectees -= owner
var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
if(D)
D.cure()
/datum/antagonist/monkey/create_team(datum/objective_team/monkey/new_team)
if(!new_team)
for(var/datum/antagonist/monkey/N in get_antagonists(/datum/antagonist/monkey, TRUE))
if(N.monkey_team)
monkey_team = N.monkey_team
return
monkey_team = new /datum/objective_team/monkey
monkey_team.update_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
monkey_team = new_team
/datum/antagonist/monkey/proc/forge_objectives()
if(monkey_team)
owner.objectives |= monkey_team.objectives
/datum/antagonist/monkey/leader
name = "Monkey Leader"
/datum/antagonist/monkey/leader/on_gain()
. = ..()
var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
if(D)
D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
var/obj/item/organ/heart/freedom/F = new
F.Insert(owner.current, drop_if_replaced = FALSE)
SSticker.mode.ape_leaders += owner
owner.special_role = "Monkey Leader"
/datum/antagonist/monkey/leader/on_removal()
. = ..()
SSticker.mode.ape_leaders -= owner
var/obj/item/organ/heart/H = new
H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart
/datum/antagonist/monkey/leader/greet()
to_chat(owner, "<B><span class='notice'>You are the Jungle Fever patient zero!!</B></span>")
to_chat(owner, "<b>You have been planted onto this station by the Animal Rights Consortium.</b>")
to_chat(owner, "<b>Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.</b>")
to_chat(owner, "<b>While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.</b>")
to_chat(owner, "<b>Your mission will be deemed a success if any of the live infected monkeys reach CentCom.</b>")
to_chat(owner, "<b>As an initial infectee, you will be considered a 'leader' by your fellow monkeys.</b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/objective/monkey
explanation_text = "Ensure that infected monkeys escape on the emergency shuttle!"
martyr_compatible = TRUE
var/monkeys_to_win = 1
var/escaped_monkeys = 0
/datum/objective/monkey/check_completion()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
return TRUE
return FALSE
/datum/objective_team/monkey
name = "Monkeys"
/datum/objective_team/monkey/proc/update_objectives()
objectives = list()
var/datum/objective/monkey/O = new /datum/objective/monkey()
O.team = src
objectives += O
return
/datum/objective_team/monkey/proc/infected_monkeys_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_monkeys_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_humans_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/infected_humans_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/objective_team/monkey/proc/get_result()
if(infected_monkeys_escaped())
return MONKEYS_ESCAPED
if(infected_monkeys_alive())
return MONKEYS_LIVED
if(infected_humans_alive() || infected_humans_escaped())
return DISEASE_LIVED
return MONKEYS_DIED
/datum/objective_team/monkey/roundend_report()
var/list/parts = list()
switch(get_result())
if(MONKEYS_ESCAPED)
parts += "<span class='greentext big'><B>Monkey Major Victory!</B></span>"
parts += "<span class='greentext'><B>Central Command and [station_name()] were taken over by the monkeys! Ook ook!</B></span>"
if(MONKEYS_LIVED)
parts += "<FONT size = 3><B>Monkey Minor Victory!</B></FONT>"
parts += "<span class='greentext'><B>[station_name()] was taken over by the monkeys! Ook ook!</B></span>"
if(DISEASE_LIVED)
parts += "<span class='redtext big'><B>Monkey Minor Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, but the disease lives on! The future is uncertain.</B></span>"
if(MONKEYS_DIED)
parts += "<span class='redtext big'><B>Monkey Major Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, and Jungle Fever was wiped out!</B></span>"
if(LAZYLEN(SSticker.mode.ape_leaders))
parts += "<span class='header'>The monkey leaders were:</span>"
parts += printplayerlist(SSticker.mode.ape_leaders)
if(LAZYLEN(SSticker.mode.ape_infectees))
parts += "<span class='header'>The monkeys were:</span>"
parts += printplayerlist(SSticker.mode.ape_infectees)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"

View File

@@ -0,0 +1,40 @@
/datum/component/cleaning
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/datum/component/cleaning/Initialize()
if(!ismovableatom(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("[type] added to a [parent.type]")
RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
/datum/component/cleaning/proc/Clean()
var/atom/movable/AM = parent
var/turf/tile = AM.loc
if(!isturf(tile))
return
tile.clean_blood()
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.update_inv_head()
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.update_inv_wear_suit()
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.update_inv_w_uniform()
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.update_inv_shoes()
cleaned_human.clean_blood()
cleaned_human.wash_cream()
to_chat(cleaned_human, "<span class='danger'>[AM] cleans your face!</span>")

View File

@@ -0,0 +1,239 @@
//Designed for things that need precision trajectories like projectiles.
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
var/x = 0
var/y = 0
var/z = 0
var/pixel_x = 0
var/pixel_y = 0
/datum/position/proc/valid()
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
if(istype(_x, /datum/point))
var/datum/point/P = _x
var/turf/T = P.return_turf()
_x = T.x
_y = T.y
_z = T.z
_pixel_x = P.return_px()
_pixel_y = P.return_py()
else if(isatom(_x))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
x = _x
y = _y
z = _z
pixel_x = _pixel_x
pixel_y = _pixel_y
/datum/position/proc/return_turf()
return locate(x, y, z)
/datum/position/proc/return_px()
return pixel_x
/datum/position/proc/return_py()
return pixel_y
/datum/position/proc/return_point()
return new /datum/point(src)
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
var/datum/point/P = new
P.x = round(a.x + (b.x - a.x) / 2, 1)
P.y = round(a.y + (b.y - a.y) / 2, 1)
P.z = a.z
return P
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
/proc/angle_between_points(datum/point/a, datum/point/b)
return ATAN2((b.y - a.y), (b.x - a.x))
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
var/x = 0
var/y = 0
var/z = 0
/datum/point/proc/valid()
return x && y && z
/datum/point/proc/copy_to(datum/point/p = new)
p.x = x
p.y = y
p.z = z
return p
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
if(istype(_x, /datum/position))
var/datum/position/P = _x
_x = P.x
_y = P.y
_z = P.z
_pixel_x = P.pixel_x
_pixel_y = P.pixel_y
else if(istype(_x, /atom))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
if(!isnull(tile_x))
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x
if(!isnull(tile_y))
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
if(!isnull(tile_z))
z = tile_z
/datum/point/proc/return_turf()
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_position()
return new /datum/position(src)
/datum/point/proc/return_px()
return MODULUS(x, world.icon_size) - 16
/datum/point/proc/return_py()
return MODULUS(y, world.icon_size) - 16
/datum/point/proc/mapcheck()
. = FALSE
var/maxx = world.icon_size * world.maxx
var/maxy = world.icon_size * world.maxy
var/move_zx = 0
var/move_zy = 0
if(x < 0)
x += maxx
move_zx -= 1
if(y < 0)
y += maxy
move_zy -= 1
if(x > maxx)
x -= maxx
move_zx += 1
if(y > maxy)
y -= maxy
move_zy += 1
var/datum/space_level/S = GLOB.z_levels_list["[z]"]
if(move_zx != 0)
var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
z = L.z_value
. = TRUE
if(move_zy != 0)
var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
z = L.z_value
. = TRUE
/datum/point/vector
var/speed = 32 //pixels per iteration
var/iteration = 0
var/angle = 0
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
var/mpy = 0
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
var/starting_y = 0
var/starting_z = 0
/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
..()
initialize_trajectory(_speed, _angle)
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
. = ..()
starting_x = x
starting_y = y
starting_z = z
/datum/point/vector/copy_to(datum/point/vector/v = new)
..(v)
v.speed = speed
v.iteration = iteration
v.angle = angle
v.mpx = mpx
v.mpy = mpy
v.starting_x = starting_x
v.starting_y = starting_y
v.starting_z = starting_z
return v
/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
if(!isnull(pixel_speed))
speed = pixel_speed
set_angle(new_angle)
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
if(isnull(angle))
return
angle = new_angle
update_offsets()
/datum/point/vector/proc/update_offsets()
mpx = sin(angle) * speed
mpy = cos(angle) * speed
/datum/point/vector/proc/set_speed(new_speed)
if(isnull(new_speed) || speed == new_speed)
return
speed = new_speed
update_offsets()
/datum/point/vector/proc/increment(multiplier = 1)
iteration++
x += mpx * 1
y += mpy * 1
if(mapcheck())
on_z_change()
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to()
if(force_simulate)
for(var/i in 1 to amount)
v.increment(multiplier)
else
v.increment(multiplier * amount)
return v
/datum/point/vector/proc/on_z_change()
return
/datum/point/vector/processed //pixel_speed is per decisecond.
var/last_process = 0
var/last_move = 0
var/paused = FALSE
/datum/point/vector/processed/Destroy()
STOP_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/proc/start()
last_process = world.time
last_move = world.time
START_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/process()
if(paused)
last_move += world.time - last_process
last_process = world.time
return
var/needed_time = world.time - last_move
last_process = world.time
last_move = world.time
increment(needed_time)

View File

@@ -0,0 +1,70 @@
/proc/generate_projectile_beam_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
if(!istype(starting) || !istype(ending) || !ispath(beam_type))
return
var/datum/point/midpoint = point_midpoint_points(starting, ending)
var/obj/effect/projectile_beam/PB = new beam_type
PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
. = PB
if(qdel_in)
QDEL_IN(PB, qdel_in)
/obj/effect/projectile_beam
icon = 'icons/obj/projectiles.dmi'
layer = ABOVE_MOB_LAYER
anchored = TRUE
light_power = 1
light_range = 2
light_color = "#00ffff"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
flags_1 = ABSTRACT_1
appearance_flags = 0
/obj/effect/projectile_beam/singularity_pull()
return
/obj/effect/projectile_beam/singularity_act()
return
/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
var/matrix/M
if(!override)
M = transform
else
M = new
M.Scale(nx,ny)
transform = M
/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
var/matrix/M
if(!override)
M = transform
else
M = new
M.Turn(angle)
transform = M
/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
if(angle_override && p_x && p_y && color_override && scaling)
apply_vars(angle_override, p_x, p_y, color_override, scaling)
return ..()
/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
var/mutable_appearance/look = new(src)
look.pixel_x = p_x
look.pixel_y = p_y
if(color_override)
look.color = color_override
appearance = look
scale_to(1,scaling, FALSE)
turn_to(angle_override, FALSE)
if(!isnull(new_loc)) //If you want to null it just delete it...
forceMove(new_loc)
for(var/i in 1 to increment)
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
/obj/effect/projectile_beam/tracer
icon_state = "tracer_beam"
/obj/effect/projectile_beam/tracer/aiming
icon_state = "gbeam"

View File

@@ -0,0 +1,18 @@
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
// Only way to do that is to tie the behavior into the focus's keyLoop().
/atom/movable/keyLoop(client/user)
if(!user.keys_held["Ctrl"])
var/movement_dir = NONE
for(var/_key in user.keys_held)
movement_dir = movement_dir | GLOB.movement_keys[_key]
if(user.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
movement_dir &= ~user.next_move_dir_sub
// Sanity checks in case you hold left and right and up to make sure you only go up
if((movement_dir & NORTH) && (movement_dir & SOUTH))
movement_dir &= ~(NORTH|SOUTH)
if((movement_dir & EAST) && (movement_dir & WEST))
movement_dir &= ~(EAST|WEST)
user.Move(get_step(src, movement_dir), movement_dir)

48
code/modules/mob/emote.dm Normal file
View File

@@ -0,0 +1,48 @@
//The code execution of the emote datum is located at code/datums/emotes.dm
/mob/emote(act, m_type = null, message = null)
act = lowertext(act)
var/param = message
var/custom_param = findchar(act, " ")
if(custom_param)
param = copytext(act, custom_param + 1, length(act) + 1)
act = copytext(act, 1, custom_param)
var/datum/emote/E
E = E.emote_list[act]
if(!E)
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
return
E.run_emote(src, param, m_type)
/datum/emote/flip
key = "flip"
key_third_person = "flips"
restraint_check = TRUE
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
/datum/emote/flip/run_emote(mob/user, params)
. = ..()
if(.)
user.SpinAnimation(7,1)
/datum/emote/spin
key = "spin"
key_third_person = "spins"
restraint_check = TRUE
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
/datum/emote/spin/run_emote(mob/user)
. = ..()
if(.)
user.spin(20, 1)
if(iscyborg(user) && user.has_buckled_mobs())
var/mob/living/silicon/robot/R = user
GET_COMPONENT_FROM(riding_datum, /datum/component/riding, R)
if(riding_datum)
for(var/mob/M in R.buckled_mobs)
riding_datum.force_dismount(M)
else
R.unbuckle_all_mobs()

BIN
icons/mob/landmarks.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -306,6 +306,7 @@
#include "code\datums\mutable_appearance.dm"
#include "code\datums\mutations.dm"
#include "code\datums\outfit.dm"
#include "code\datums\position_point_vector.dm"
#include "code\datums\profiling.dm"
#include "code\datums\progressbar.dm"
#include "code\datums\radiation_wave.dm"
@@ -318,6 +319,7 @@
#include "code\datums\verbs.dm"
#include "code\datums\weakrefs.dm"
#include "code\datums\world_topic.dm"
#include "code\datums\actions\beam_rifle.dm"
#include "code\datums\actions\flightsuit.dm"
#include "code\datums\actions\ninja.dm"
#include "code\datums\antagonists\abductor.dm"
@@ -329,6 +331,7 @@
#include "code\datums\antagonists\datum_traitor.dm"
#include "code\datums\antagonists\devil.dm"
#include "code\datums\antagonists\internal_affairs.dm"
#include "code\datums\antagonists\monkey.dm"
#include "code\datums\antagonists\ninja.dm"
#include "code\datums\antagonists\nukeop.dm"
#include "code\datums\antagonists\pirate.dm"
@@ -345,6 +348,7 @@
#include "code\datums\components\archaeology.dm"
#include "code\datums\components\caltrop.dm"
#include "code\datums\components\chasm.dm"
#include "code\datums\components\cleaning.dm"
#include "code\datums\components\decal.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm"
@@ -1701,6 +1705,7 @@
#include "code\modules\mob\login.dm"
#include "code\modules\mob\logout.dm"
#include "code\modules\mob\mob.dm"
#include "code\modules\mob\mob_cleanup.dm"
#include "code\modules\mob\mob_defines.dm"
#include "code\modules\mob\mob_helpers.dm"
#include "code\modules\mob\mob_movement.dm"