mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-17 01:53:35 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into BookClub
This commit is contained in:
@@ -41,7 +41,8 @@ var/global/nologevent = 0
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
|
||||
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_living() + "</a>\]"
|
||||
|
||||
if(istype(M, /mob/new_player))
|
||||
body += " <B>Hasn't Entered Game</B> "
|
||||
|
||||
@@ -74,6 +74,7 @@ var/list/admin_verbs_admin = list(
|
||||
/client/proc/debug_variables,
|
||||
/client/proc/show_snpc_verbs,
|
||||
/client/proc/reset_all_tcs, /*resets all telecomms scripts*/
|
||||
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
|
||||
/client/proc/toggle_mentor_chat
|
||||
)
|
||||
var/list/admin_verbs_ban = list(
|
||||
|
||||
@@ -1996,6 +1996,15 @@
|
||||
|
||||
fax_panel(usr)
|
||||
|
||||
else if(href_list["getplaytimewindow"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/mob/M = locateUID(href_list["getplaytimewindow"])
|
||||
if(!M)
|
||||
to_chat(usr, "ERROR: Mob not found.")
|
||||
return
|
||||
cmd_show_exp_panel(M.client)
|
||||
|
||||
else if(href_list["jumpto"])
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal
|
||||
name = "Nano-Mob Hunter GO! Battle Terminal"
|
||||
desc = "Insert a mob card to partake in life-like Nano-Mob Battle Action!"
|
||||
icon_state = "mob_battle_empty"
|
||||
icon_screen = null
|
||||
icon_keyboard = null
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/obj/item/weapon/nanomob_card/card
|
||||
var/datum/mob_hunt/mob_info
|
||||
var/obj/effect/nanomob/battle/avatar
|
||||
var/ready = 0
|
||||
var/team = "Grey"
|
||||
var/avatar_x_offset = 4
|
||||
var/avatar_y_offset = 0
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/red
|
||||
pixel_y = 24
|
||||
dir = SOUTH
|
||||
team = "Red"
|
||||
avatar_y_offset = -1
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/blue
|
||||
pixel_y = -24
|
||||
dir = NORTH
|
||||
team = "Blue"
|
||||
avatar_y_offset = 1
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/red/initialize()
|
||||
..()
|
||||
check_connection()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/blue/initialize()
|
||||
..()
|
||||
check_connection()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/update_icon()
|
||||
if(card)
|
||||
icon_state = "mob_battle_loaded"
|
||||
else
|
||||
icon_state = "mob_battle_empty"
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/Destroy()
|
||||
eject_card(1)
|
||||
if(mob_hunt_server)
|
||||
if(mob_hunt_server.battle_turn)
|
||||
mob_hunt_server.battle_turn = null
|
||||
if(mob_hunt_server.red_terminal == src)
|
||||
mob_hunt_server.red_terminal = null
|
||||
if(mob_hunt_server.blue_terminal == src)
|
||||
mob_hunt_server.blue_terminal = null
|
||||
if(avatar)
|
||||
qdel(avatar)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/weapon/nanomob_card))
|
||||
insert_card(O, user)
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/insert_card(obj/item/weapon/nanomob_card/new_card, mob/user)
|
||||
if(!new_card)
|
||||
return
|
||||
if(card)
|
||||
to_chat(user, "<span class='warning'>The card slot is currently filled.</span>")
|
||||
return
|
||||
if(!new_card.mob_data)
|
||||
to_chat(user, "<span class='danger'>This is a blank mob card.</span>")
|
||||
return
|
||||
if(new_card.mob_data && !new_card.mob_data.cur_health)
|
||||
to_chat(user, "<span class='warning'>This mob is incapacitated! Heal it before attempting to use it in battle!</span>")
|
||||
return
|
||||
user.unEquip(new_card)
|
||||
new_card.forceMove(src)
|
||||
card = new_card
|
||||
mob_info = card.mob_data
|
||||
update_icon()
|
||||
update_avatar()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0)
|
||||
if(!override)
|
||||
if(ready && mob_hunt_server.battle_turn != team)
|
||||
audible_message("You can't recall on your rival's turn!", null, 2)
|
||||
return
|
||||
card.mob_data = mob_info
|
||||
mob_info = null
|
||||
card.forceMove(get_turf(src))
|
||||
card = null
|
||||
update_avatar()
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/update_avatar()
|
||||
//if we don't have avatars yet, spawn them
|
||||
if(!avatar)
|
||||
avatar = new(locate((x + avatar_x_offset), (y + avatar_y_offset), z))
|
||||
//update avatar info from card
|
||||
if(mob_info)
|
||||
avatar.mob_info = mob_info
|
||||
else
|
||||
avatar.mob_info = null
|
||||
//tell the avatar to update themself with the new info
|
||||
avatar.update_self()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attack_hand(mob/user)
|
||||
add_fingerprint(user)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attack_ai(mob/user)
|
||||
to_chat(user, "<span class='warning'>You cannot interface with this portion of the simulation.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/interact(mob/user)
|
||||
check_connection()
|
||||
var/dat = ""
|
||||
dat += "<table border='1' style='width:75%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "[team] PLAYER"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
if(!card)
|
||||
dat += "<h1>No Nano-Mob card loaded.</h1>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(ready && mob_hunt_server.battle_turn) //offer the surrender option if they are in a battle (ready), but don't have a card loaded
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];surrender=1'>Surrender!</a></td>"
|
||||
dat += "</tr>"
|
||||
else
|
||||
dat += "<table>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "<h1>[mob_info.mob_name]</h1>"
|
||||
dat += "</td>"
|
||||
if(mob_info.nickname)
|
||||
dat += "<td rowspan='2'>"
|
||||
else
|
||||
dat += "<td>"
|
||||
var/img_src = "[mob_info.icon_state_normal].png"
|
||||
if(mob_info.is_shiny)
|
||||
dat += "[mob_info.icon_state_shiny].png"
|
||||
dat += "<img src='[img_src]'>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(mob_info.nickname)
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "<h2>[mob_info.nickname]</h2>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<hr>"
|
||||
dat += "Health: [mob_info.cur_health] / [mob_info.max_health]<br>"
|
||||
dat += "<table border='1'>"
|
||||
dat += "<tr>"
|
||||
if(mob_info.cur_health)
|
||||
dat += "<td><a href='?src=[UID()];attack=1'>Attack!</a></td>"
|
||||
else
|
||||
dat += "<td>Incapacitated!</td>"
|
||||
dat += "<td><a href='?src=[UID()];eject=1'>Recall!</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(!ready)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];ready=1'>Battle!</a></td>"
|
||||
dat += "</tr>"
|
||||
if(ready && !mob_hunt_server.battle_turn)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];ready=2'>Cancel Battle!</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
var/datum/browser/popup = new(user, "mob_battle_terminal", "Nano-Mob Hunter GO! Battle Terminal", 575, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["attack"])
|
||||
do_attack()
|
||||
|
||||
if(href_list["eject"])
|
||||
eject_card()
|
||||
|
||||
if(href_list["surrender"])
|
||||
surrender()
|
||||
|
||||
if(href_list["ready"])
|
||||
var/option = text2num(href_list["ready"])
|
||||
if(option == 1)
|
||||
start_battle()
|
||||
else if(option == 2)
|
||||
ready = 0
|
||||
audible_message("[team] Player cancels their battle challenge.", null, 5)
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/check_connection()
|
||||
if(team == "Red")
|
||||
if(mob_hunt_server && !mob_hunt_server.red_terminal)
|
||||
mob_hunt_server.red_terminal = src
|
||||
else if(team == "Blue")
|
||||
if(mob_hunt_server && !mob_hunt_server.blue_terminal)
|
||||
mob_hunt_server.blue_terminal = src
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/do_attack()
|
||||
if(!ready) //no attacking if you arent ready to fight (duh)
|
||||
return
|
||||
if(!mob_hunt_server || team != mob_hunt_server.battle_turn) //don't attack unless it is actually our turn
|
||||
return
|
||||
else
|
||||
var/message = "[mob_info.mob_name] attacks!"
|
||||
if(mob_info.nickname)
|
||||
message = "[mob_info.nickname] attacks!"
|
||||
audible_message(message, null, 5)
|
||||
mob_hunt_server.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type())
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/start_battle()
|
||||
if(ready) //don't do anything if we are still ready
|
||||
return
|
||||
if(!card) //don't do anything if there isn't a card inserted
|
||||
return
|
||||
ready = 1
|
||||
audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5)
|
||||
mob_hunt_server.start_check()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type)
|
||||
var/message = mob_info.take_damage(raw_damage, attack_type)
|
||||
avatar.audible_message(message, null, 5)
|
||||
if(!mob_info.cur_health)
|
||||
mob_hunt_server.end_battle(team)
|
||||
eject_card(1) //force the card out, they were defeated
|
||||
else
|
||||
mob_hunt_server.end_turn()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/surrender()
|
||||
audible_message("[team] Player surrenders the battle!", null, 5)
|
||||
mob_hunt_server.end_battle(team, 1)
|
||||
|
||||
//////////////////////////////
|
||||
// Mob Healing Terminal //
|
||||
// (Pokemon Center) //
|
||||
//////////////////////////////
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal
|
||||
name = "Nano-Mob Hunter GO! Restoration Terminal"
|
||||
desc = "Swipe a mob card to instantly restore it to full health!"
|
||||
icon_state = "mob_battle_loaded"
|
||||
icon_screen = null
|
||||
icon_keyboard = null
|
||||
density = 0
|
||||
anchored = 1
|
||||
dir = EAST
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/weapon/nanomob_card))
|
||||
heal_card(O, user)
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal/proc/heal_card(obj/item/weapon/nanomob_card/patient, mob/user)
|
||||
if(!patient)
|
||||
return
|
||||
if(!patient.mob_data)
|
||||
to_chat(user, "<span class='danger'>This is a blank mob card.</span>")
|
||||
return
|
||||
if(patient.mob_data && patient.mob_data.cur_health == patient.mob_data.max_health)
|
||||
to_chat(user, "<span class='warning'>This mob is already at maximum health!</span>")
|
||||
return
|
||||
patient.mob_data.cur_health = patient.mob_data.max_health
|
||||
to_chat(user, "<span class='notify'>[patient.mob_data.nickname ? patient.mob_data.nickname : patient.mob_data.mob_name] has been restored to full health!</span>")
|
||||
@@ -0,0 +1,162 @@
|
||||
|
||||
/obj/effect/nanomob
|
||||
name = "Nano-Mob Avatar" //will be overridden by the mob datum name value when created
|
||||
desc = "A wild Nano-Mob appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
invisibility = 101
|
||||
alpha = 128
|
||||
anchored = 1 //just in case
|
||||
density = 0
|
||||
icon = 'icons/effects/mob_hunt.dmi'
|
||||
var/state_name
|
||||
var/datum/mob_hunt/mob_info = null
|
||||
var/list/clients_encountered = list() //tracks who has already interacted with us, so they can't attempt a second capture
|
||||
var/image/avatar
|
||||
|
||||
/obj/effect/nanomob/New(loc, datum/mob_hunt/new_info)
|
||||
..()
|
||||
if(!new_info)
|
||||
qdel(src)
|
||||
return
|
||||
mob_info = new_info
|
||||
update_self()
|
||||
forceMove(mob_info.spawn_point)
|
||||
if(!mob_info.is_trap)
|
||||
addtimer(src, "despawn", mob_info.lifetime)
|
||||
|
||||
/obj/effect/nanomob/proc/update_self()
|
||||
if(!mob_info)
|
||||
return
|
||||
name = mob_info.mob_name
|
||||
desc = "A wild [name] (level [mob_info.level]) appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
if(mob_info.is_shiny)
|
||||
state_name = mob_info.icon_state_shiny
|
||||
else
|
||||
state_name = mob_info.icon_state_normal
|
||||
avatar = image(icon, src, state_name)
|
||||
avatar.override = 1
|
||||
add_alt_appearance("nanomob_avatar", avatar)
|
||||
|
||||
/obj/effect/nanomob/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P, -20) //attempting a melee capture reduces the mob's effective run_chance by 20% to balance the risk of triggering a trap mob
|
||||
return 1
|
||||
|
||||
/obj/effect/nanomob/hitby(obj/item/O)
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P) //attempting a ranged capture does not affect the mob's effective run_chance but does prevent you from being shocked by a trap mob
|
||||
return 1
|
||||
|
||||
/obj/effect/nanomob/proc/attempt_capture(obj/item/device/pda/P, catch_mod = 0) //negative catch_mods lower effective run chance,
|
||||
if(!P || !P.current_app || !istype(P.current_app, /datum/data/pda/app/mob_hunter_game) || !P.cartridge)
|
||||
return
|
||||
|
||||
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
|
||||
var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
|
||||
if(!client.connected) //must be connected to attempt captures
|
||||
P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
|
||||
return
|
||||
|
||||
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
|
||||
if(client.hacked) //hacked copies of the game (copies capable of setting traps) are protected from traps
|
||||
return
|
||||
if(iscarbon(P.loc))
|
||||
var/mob/living/carbon/C = P.loc
|
||||
//Strike them down with a lightning bolt to complete the illusion (copied from the surge reagent overdose, probably could make this a general-use proc in the future)
|
||||
playsound(get_turf(C), 'sound/effects/eleczap.ogg', 75, 1)
|
||||
var/icon/I=new('icons/obj/zap.dmi',"lightningend")
|
||||
I.Turn(-135)
|
||||
var/obj/effect/overlay/beam/B = new(get_turf(C))
|
||||
B.pixel_x = rand(-20, 0)
|
||||
B.pixel_y = rand(-20, 0)
|
||||
B.icon = I
|
||||
//then actually do the damage/stun
|
||||
C.electrocute_act(20, P, 1) //same damage as a revenant's overload ability, except subject to gloves/species shock resistance (for human mobs at least)
|
||||
return
|
||||
|
||||
if(client in clients_encountered) //we've already dealt with you, go away!
|
||||
return
|
||||
else //deal with the new hunter by either running away or getting caught
|
||||
clients_encountered += client
|
||||
var/message = "[bicon(P)] "
|
||||
var/effective_run_chance = mob_info.run_chance + total_catch_mod
|
||||
if((effective_run_chance > 0) && prob(effective_run_chance))
|
||||
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
|
||||
conceal(client)
|
||||
else
|
||||
if(client.register_capture(mob_info, 1))
|
||||
message += "Capture success! [P.owner ? P.owner : "This hunter"] captured [name]!"
|
||||
conceal(client)
|
||||
else
|
||||
message += "Capture error! Try again."
|
||||
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
|
||||
P.audible_message(message, null, 4)
|
||||
|
||||
/obj/effect/nanomob/proc/despawn()
|
||||
if(mob_hunt_server)
|
||||
if(mob_info.is_trap)
|
||||
mob_hunt_server.trap_spawns -= src
|
||||
else
|
||||
mob_hunt_server.normal_spawns -= src
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/nanomob/proc/reveal()
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/show_to = list()
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) || !mob_hunt_server.connected_clients[A])
|
||||
continue
|
||||
show_to |= mob_hunt_server.connected_clients[A]
|
||||
display_alt_appearance("nanomob_avatar", show_to)
|
||||
|
||||
/obj/effect/nanomob/proc/conceal(list/hide_from)
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/hiding_from = list()
|
||||
if(hide_from)
|
||||
hiding_from = hide_from
|
||||
else
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) && mob_hunt_server.connected_clients[A])
|
||||
hiding_from |= mob_hunt_server.connected_clients[A]
|
||||
hide_alt_appearance("nanomob_avatar", hiding_from)
|
||||
|
||||
// BATTLE MOB AVATARS
|
||||
|
||||
/obj/effect/nanomob/battle
|
||||
name = "Nano-Mob Battle Avatar"
|
||||
desc = "A new challenger approaches!"
|
||||
invisibility = 0
|
||||
icon_state = "placeholder"
|
||||
var/obj/machinery/computer/mob_battle_terminal/my_terminal
|
||||
|
||||
/obj/effect/nanomob/battle/New(loc, datum/mob_hunt/new_info)
|
||||
if(new_info)
|
||||
mob_info = new_info
|
||||
update_self()
|
||||
|
||||
/obj/effect/nanomob/battle/update_self()
|
||||
if(!mob_info)
|
||||
name = "Nano-Mob Battle Avatar"
|
||||
desc = "A new challenger approaches"
|
||||
icon_state = "placeholder"
|
||||
else
|
||||
name = mob_info.mob_name
|
||||
desc = "A tamed [name] (level [mob_info.level]) ready for battle!"
|
||||
if(mob_info.is_shiny)
|
||||
icon_state = mob_info.icon_state_shiny
|
||||
else
|
||||
icon_state = mob_info.icon_state_normal
|
||||
|
||||
/obj/effect/nanomob/battle/attempt_capture(obj/item/device/pda/P, catch_mod = 0)
|
||||
//you can't capture battle avatars, since they belong to someone already
|
||||
return
|
||||
|
||||
//battle avatars are always visible, so we can ignore reveal and conceal calls for them
|
||||
/obj/effect/nanomob/battle/reveal()
|
||||
return
|
||||
|
||||
/obj/effect/nanomob/battle/conceal()
|
||||
return
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
//Standard Cards
|
||||
/obj/item/weapon/nanomob_card
|
||||
name = "Nano-Mob Hunter Trading Card"
|
||||
desc = "A blank Nano-Mob Hunter Trading Card. Worthless!"
|
||||
icon = 'icons/obj/card.dmi'
|
||||
icon_state = "trade_card"
|
||||
force = 0
|
||||
throwforce = 1
|
||||
w_class = 1
|
||||
var/datum/mob_hunt/mob_data
|
||||
|
||||
/obj/item/weapon/nanomob_card/proc/update_info()
|
||||
if(!mob_data)
|
||||
return
|
||||
if(mob_data.is_shiny)
|
||||
name = "Holographic [mob_data.mob_name] Nano-Mob Hunter Card"
|
||||
desc = "WOW! A holographic trading card containing a level [mob_data.level] [mob_data.mob_name]!"
|
||||
icon_state = "trade_card_holo"
|
||||
else
|
||||
name = "[mob_data.mob_name] Nano-Mob Hunter Card"
|
||||
desc = "A trading card containing a level [mob_data.level] [mob_data.mob_name]!"
|
||||
|
||||
//Booster Pack Cards (random mob data)
|
||||
/obj/item/weapon/nanomob_card/booster
|
||||
name = "Nano-Mob Hunter Booster Pack Card"
|
||||
desc = "A random Nano-Mob Trading Card from a Booster Pack. Wonder what it is?"
|
||||
|
||||
/obj/item/weapon/nanomob_card/booster/New()
|
||||
var/datum/mob_hunt/mob_info = pick(subtypesof(/datum/mob_hunt))
|
||||
mob_data = new mob_info(0,null,1)
|
||||
update_info()
|
||||
|
||||
//Booster Packs (Box of booster pack cards)
|
||||
/obj/item/weapon/storage/box/nanomob_booster_pack
|
||||
name = "Nano-Mob Hunter Trading Card Booster Pack"
|
||||
desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!"
|
||||
can_hold = list("/obj/item/weapon/nanomob_card")
|
||||
|
||||
/obj/item/weapon/storage/box/nanomob_booster_pack/New()
|
||||
..()
|
||||
for(var/i in 1 to 6)
|
||||
new /obj/item/weapon/nanomob_card/booster(src)
|
||||
@@ -0,0 +1,501 @@
|
||||
|
||||
#define TYPE_FIRE /datum/mob_type/fire
|
||||
#define TYPE_WATER /datum/mob_type/water
|
||||
#define TYPE_GRASS /datum/mob_type/grass
|
||||
#define TYPE_ELECTRIC /datum/mob_type/electric
|
||||
#define TYPE_GROUND /datum/mob_type/ground
|
||||
#define TYPE_ROCK /datum/mob_type/rock
|
||||
#define TYPE_BUG /datum/mob_type/bug
|
||||
#define TYPE_POISON /datum/mob_type/poison
|
||||
#define TYPE_NORMAL /datum/mob_type/normal
|
||||
#define TYPE_FIGHTING /datum/mob_type/fighting
|
||||
#define TYPE_PSYCHIC /datum/mob_type/psychic
|
||||
#define TYPE_GHOST /datum/mob_type/ghost
|
||||
#define TYPE_ICE /datum/mob_type/ice
|
||||
#define TYPE_FLYING /datum/mob_type/flying
|
||||
#define TYPE_BLUESPACE /datum/mob_type/bluespace
|
||||
#define TYPE_DARK /datum/mob_type/dark
|
||||
#define TYPE_STEEL /datum/mob_type/steel
|
||||
|
||||
/datum/mob_hunt
|
||||
//GENERAL STATS AND VARIABLES
|
||||
var/mob_name = "Generic Mob" //the mob's original name (its species/type/whatever)
|
||||
var/nickname = "" //the mob's nickname (if given by the owner)
|
||||
var/run_chance = 0 //percent chance the mob will escape capture attempts (higher is obviously more likely to get away)
|
||||
|
||||
//COMBAT STATS AND VARIABLES
|
||||
var/level = 0 //actual level of this mob (don't set this, it gets overwritten in New())
|
||||
var/min_level = 1 //minimum level of this mob (used for randomizing the actual level)
|
||||
var/max_level = 1 //maximum level of this mob (used for randomizing the actual level)
|
||||
var/exp = 0 //number of battles the mob has won towards the next level (resets to 0 on level-up)
|
||||
var/exp_to_level = 3 //number of battles the mob must win to level up (in case we want to make some mobs harder or easier to level)
|
||||
//the types of the mob will be used for battles to determine damage resistance or weakness (mob_type_datums.dm)
|
||||
var/datum/mob_type/primary_type //Make sure you set this or the mob will be unable to deal damage and will take absurd damage in battles
|
||||
var/datum/mob_type/secondary_type //Don't set if not a dual-type mob so the mob will only calculate damage based on primary type
|
||||
var/base_attack = 5 //base damage dealt by the mob's attacks for battling (effectively damage dealt at level 0)
|
||||
var/base_health = 5 //base health of the mob for battling (effectively max health at level 0)
|
||||
var/attack_multiplier = 1 //how much additional damage per level the mob deals (level * attack_multiplier)
|
||||
var/health_multiplier = 1 //how much additional health per level the mob gets (level * health_multiplier) for calculating max health
|
||||
var/cur_health = 0
|
||||
var/max_health = 0
|
||||
|
||||
//SPAWN PREFERENCES AND VARIABLES
|
||||
//A note on mob spawn preferences: The mob types also have preferences, which are handled prior to per-mob preferences, so ultimately you use a combined set of preferences
|
||||
var/list/area_blacklist = list() //list of areas this mob can NOT spawn in (such as the bridge)
|
||||
var/list/turf_blacklist = list() //list of turfs this mob can NOT spawn on (such as wood floors)
|
||||
var/list/area_whitelist = list() //list of areas this mob is more likely to spawn in (can be used to reinclude subtypes of blacklisted areas)
|
||||
var/list/turf_whitelist = list() //list of turfs this mob is more likely to spawn on (can be used to reinclude subtypes of blacklisted turfs)
|
||||
var/turf/spawn_point //gets set and sent to the game server to spawn its avatar (generated in select_spawn or assigned via set_trap)
|
||||
var/lifetime = 6000 //number of deciseconds the mob will remain before despawning (REMEMBER: DECISECONDS! So 6000 is 600 seconds which is 10 minutes)
|
||||
var/is_shiny = 0 //if this gets set at spawn (super rare), the mob is considered "shiny" and will use the shiny icon_state and holographic cards
|
||||
|
||||
//the icon file for mob_hunt stuff is 'icons/effects/mob_hunt.dmi' so reference that for the following vars
|
||||
var/icon_state_normal = "placeholder" //the icon_state for this mob's normal version
|
||||
var/icon_state_shiny = "placeholder" //the icon_state for this mob's rare shiney version
|
||||
|
||||
var/is_trap = 0 //if this gets set, the mob is a booby-trap and will electrocute any players that dare attempt to catch it
|
||||
|
||||
/datum/mob_hunt/New(set_trap = 0, turf/trap_turf = null, no_register = 0)
|
||||
if(set_trap)
|
||||
level = max_level
|
||||
is_trap = 1
|
||||
spawn_point = trap_turf
|
||||
else
|
||||
level = rand(min_level, max_level)
|
||||
if(prob(1) && prob(1))
|
||||
is_shiny = 1
|
||||
max_health = base_health + (level * health_multiplier)
|
||||
cur_health = max_health
|
||||
if(primary_type)
|
||||
primary_type = new primary_type()
|
||||
if(secondary_type)
|
||||
secondary_type = new secondary_type()
|
||||
if(no_register) //for booster pack cards
|
||||
return
|
||||
if(mob_hunt_server)
|
||||
if(set_trap)
|
||||
if(mob_hunt_server.register_trap(src))
|
||||
return
|
||||
else if(select_spawn())
|
||||
if(mob_hunt_server.register_spawn(src))
|
||||
return
|
||||
qdel(src) //if you reach this, the datum is just pure clutter, so delete it
|
||||
|
||||
/datum/mob_hunt/proc/select_spawn()
|
||||
var/list/possible_areas = get_possible_areas()
|
||||
if(!possible_areas.len)
|
||||
log_admin("No possible areas to spawn [type] found. Possible code/mapping error?")
|
||||
return 0
|
||||
while(possible_areas.len)
|
||||
//randomly select an area from our possible_areas list to try spawning in, then remove it from possible_areas so it won't get picked over and over forever.
|
||||
var/area/spawn_area = locate(pickweight(possible_areas))
|
||||
possible_areas -= spawn_area
|
||||
if(!spawn_area)
|
||||
break
|
||||
//clear and generate a fresh list of turfs in the selected area, weighted based on white/black lists
|
||||
var/list/possible_turfs = get_possible_turfs(spawn_area)
|
||||
if(!possible_turfs.len) //If we don't have any possible turfs, this attempt was a failure. Try again.
|
||||
continue
|
||||
//if we got this far, we're spawning on this attempt, hooray!
|
||||
spawn_point = pickweight(possible_turfs)
|
||||
break
|
||||
if(!spawn_point)
|
||||
//if we get to this, we failed every attempt to find a suitable turf for EVERY area in our list of possible areas. DAMN.
|
||||
log_admin("No acceptable turfs to spawn [type] on could be located. Possible code/mapping error, or someone replaced/destroyed all the acceptable turf types?")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/mob_hunt/proc/get_possible_areas()
|
||||
var/list/possible_areas = list()
|
||||
//setup, sets all station areas (and subtypes) to weight 1
|
||||
for(var/A in the_station_areas)
|
||||
if(A == /area/holodeck) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well
|
||||
continue
|
||||
if(A in possible_areas)
|
||||
continue
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] = 1
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
for(var/A in primary_type.area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in primary_type.area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
for(var/A in secondary_type.area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in secondary_type.area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//mob preferences
|
||||
for(var/A in area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
|
||||
var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
|
||||
for(var/A in bad_areas)
|
||||
possible_areas -= A
|
||||
//weight check, remove negative or zero weight areas from the list, then return the list.
|
||||
for(var/areapath in possible_areas)
|
||||
//remove any areas that shouldn't be on the station-level
|
||||
if(possible_areas[areapath] < 1)
|
||||
possible_areas -= areapath
|
||||
continue
|
||||
return possible_areas
|
||||
|
||||
/datum/mob_hunt/proc/get_possible_turfs(area/spawn_area)
|
||||
if(!spawn_area)
|
||||
return list()
|
||||
var/list/possible_turfs = list()
|
||||
//setup, sets all turfs in spawn_area to weight 1
|
||||
for(var/turf/T in spawn_area)
|
||||
if(!is_station_level(T.z)) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars
|
||||
continue
|
||||
possible_turfs[T] = 1
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
if(is_type_in_list(T, primary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, primary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
if(is_type_in_list(T, secondary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, secondary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//mob preferences
|
||||
if(is_type_in_list(T, turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//weight check, remove negative or zero weight turfs from the list, then return the list
|
||||
if(possible_turfs[T] < 1)
|
||||
possible_turfs -= T
|
||||
return possible_turfs
|
||||
|
||||
/datum/mob_hunt/proc/calc_def_multiplier(datum/mob_type/attack_type)
|
||||
if(!primary_type)
|
||||
return 99 //typeless mobs are weak to everything since they shouldn't exist
|
||||
if(!attack_type) //typeless attacks will return a multiplier of 1 in case we want to use this for calculating unmodified damage for some reason (UI maybe?)
|
||||
return 1
|
||||
|
||||
var/multiplier = 1
|
||||
if(attack_type in primary_type.immunity)
|
||||
return 0 //a single immunity negates all damage
|
||||
else if(attack_type in primary_type.resistance)
|
||||
multiplier *= 0.5
|
||||
else if(attack_type in primary_type.weakness)
|
||||
multiplier *= 2
|
||||
else
|
||||
multiplier *= 1
|
||||
|
||||
if(!secondary_type) //if we don't have a second type, we're done here
|
||||
return multiplier
|
||||
if(attack_type in secondary_type.immunity)
|
||||
return 0 //a single immunity negates all damage
|
||||
else if(attack_type in secondary_type.resistance)
|
||||
multiplier *= 0.5
|
||||
else if(attack_type in secondary_type.weakness)
|
||||
multiplier *= 2
|
||||
else
|
||||
multiplier *= 1
|
||||
return multiplier
|
||||
|
||||
/datum/mob_hunt/proc/take_damage(raw_damage, datum/mob_type/attack_type)
|
||||
var/message = ""
|
||||
var/multiplier = calc_def_multiplier(attack_type)
|
||||
var/total_damage = raw_damage * multiplier
|
||||
if(!cur_health) //it's already downed, quit hitting it
|
||||
return null
|
||||
if(!total_damage)
|
||||
message += "The attack is completely ineffective! "
|
||||
else
|
||||
cur_health = max(cur_health - total_damage, 0)
|
||||
switch(multiplier)
|
||||
if(0)
|
||||
message += "The attack is completely ineffective! "
|
||||
if(0.25)
|
||||
message += "It's barely effective... "
|
||||
if(0.5)
|
||||
message += "It's not very effective... "
|
||||
if(2)
|
||||
message += "It's super effective! "
|
||||
if(4)
|
||||
message += "It's ultra effective! "
|
||||
if(99)
|
||||
message += pick("REKT! ", "DUNKED! ", "DEFENSE BREAK! ", "WOMBO-COMBO'D!")
|
||||
if(!cur_health)
|
||||
message += "[nickname ? nickname : mob_name] is downed!"
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/get_raw_damage()
|
||||
return (level * attack_multiplier)
|
||||
|
||||
/datum/mob_hunt/proc/get_attack_type()
|
||||
var/datum/mob_type/attack_type = primary_type
|
||||
if(secondary_type && prob(40))
|
||||
attack_type = secondary_type
|
||||
return attack_type
|
||||
|
||||
/datum/mob_hunt/proc/gain_exp()
|
||||
exp++
|
||||
var/message = "[nickname ? nickname : mob_name] gained EXP! ([exp] / [exp_to_level] EXP)"
|
||||
if(exp >= exp_to_level)
|
||||
message = levelup()
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/levelup()
|
||||
var/message = ""
|
||||
level++
|
||||
exp = 0
|
||||
if(level > max_level) //This is where we would trigger an evolution, when those are added (need to add evolved forms first)
|
||||
level = max_level //for now though, we'll just cap them back at their max_level
|
||||
message += "[nickname ? nickname : mob_name] can't get any stronger right now!"
|
||||
else
|
||||
max_health = base_health + (level * health_multiplier)
|
||||
cur_health = max_health //full heal on level-up
|
||||
message += "[nickname ? nickname : mob_name] has reached level [level]!"
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/get_type1()
|
||||
if(!primary_type)
|
||||
return "Typeless"
|
||||
else
|
||||
return primary_type.name
|
||||
|
||||
/datum/mob_hunt/proc/get_type2()
|
||||
if(!secondary_type)
|
||||
return null
|
||||
else
|
||||
return secondary_type.name
|
||||
|
||||
|
||||
/datum/mob_hunt/nemabug
|
||||
mob_name = "Nemabug"
|
||||
run_chance = 50
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_BUG
|
||||
icon_state_normal = "nemabug"
|
||||
icon_state_shiny = "nemabug_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/stoutquill
|
||||
mob_name = "Stoutquill"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_ICE
|
||||
icon_state_normal = "stoutquill"
|
||||
icon_state_shiny = "stoutquill_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/spectra
|
||||
mob_name = "Spectra"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_POISON
|
||||
icon_state_normal = "spectra"
|
||||
icon_state_shiny = "spectra_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/dunny
|
||||
mob_name = "Dunny"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_FIRE
|
||||
icon_state_normal = "dunny"
|
||||
icon_state_shiny = "dunny_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/buffsel
|
||||
mob_name = "Buffsel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_ROCK
|
||||
icon_state_normal = "buffsel"
|
||||
icon_state_shiny = "buffsel_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/quarrel
|
||||
mob_name = "Quarrel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_NORMAL
|
||||
icon_state_normal = "quarrel"
|
||||
icon_state_shiny = "quarrel_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/vulerrt
|
||||
mob_name = "Vulerrt"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_DARK
|
||||
icon_state_normal = "vulerrt"
|
||||
icon_state_shiny = "vulerrt_shiny"
|
||||
turf_whitelist = list()
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/strudel
|
||||
mob_name = "Strudel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_ELECTRIC
|
||||
icon_state_normal = "strudel"
|
||||
icon_state_shiny = "strudel_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/folstick
|
||||
mob_name = "Folstick"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_WATER
|
||||
icon_state_normal = "folstick"
|
||||
icon_state_shiny = "folstick_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/glimmerflare
|
||||
mob_name = "Glimmerflare"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_PSYCHIC
|
||||
icon_state_normal = "glimmerflare"
|
||||
icon_state_shiny = "glimmerflare_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/leecoon
|
||||
mob_name = "Leecoon"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_GRASS
|
||||
icon_state_normal = "leecoon"
|
||||
icon_state_shiny = "leecoon_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/halk
|
||||
mob_name = "Halk"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_FLYING
|
||||
icon_state_normal = "halk"
|
||||
icon_state_shiny = "halk_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/gooby
|
||||
mob_name = "Gooby"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_ELECTRIC
|
||||
secondary_type = TYPE_BUG
|
||||
icon_state_normal = "gooby"
|
||||
icon_state_shiny = "gooby_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/pandoom
|
||||
mob_name = "Pandoom"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_GHOST
|
||||
icon_state_normal = "pandoom"
|
||||
icon_state_shiny = "pandoom_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/relish
|
||||
mob_name = "Relish"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_GROUND
|
||||
icon_state_normal = "relish"
|
||||
icon_state_shiny = "relish_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/xofine
|
||||
mob_name = "Xofine"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 10
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_NORMAL
|
||||
icon_state_normal = "xofine"
|
||||
icon_state_shiny = "xofine_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/gitten
|
||||
mob_name = "Gitten"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_WATER
|
||||
secondary_type = TYPE_POISON
|
||||
icon_state_normal = "gitten"
|
||||
icon_state_shiny = "gitten_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/nai
|
||||
mob_name = "Nai"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_GRASS
|
||||
secondary_type = TYPE_NORMAL
|
||||
icon_state_normal = "nai"
|
||||
icon_state_shiny = "nai_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/pyroghast
|
||||
mob_name = "Pyroghast"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_GHOST
|
||||
icon_state_normal = "pyroghast"
|
||||
icon_state_shiny = "pyroghast"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/starslam
|
||||
mob_name = "Starslam"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIGHTING
|
||||
secondary_type = TYPE_ICE
|
||||
icon_state_normal = "starslam"
|
||||
icon_state_shiny = "starslam_shiny"
|
||||
lifetime = 2500
|
||||
|
||||
/datum/mob_hunt/pheron
|
||||
mob_name = "Pheron"
|
||||
run_chance = 85
|
||||
min_level = 10
|
||||
max_level = 20
|
||||
primary_type = TYPE_BLUESPACE
|
||||
icon_state_normal = "pheron"
|
||||
icon_state_shiny = "pheron_shiny"
|
||||
area_blacklist = list()
|
||||
turf_blacklist = list()
|
||||
area_whitelist = list()
|
||||
turf_whitelist = list()
|
||||
lifetime = 2000
|
||||
@@ -0,0 +1,256 @@
|
||||
|
||||
/datum/mob_type
|
||||
var/name = "Typeless"
|
||||
var/list/weakness = list()
|
||||
var/list/resistance = list()
|
||||
var/list/immunity = list()
|
||||
|
||||
//Type-based spawn preferences (to eliminate copy-pasting the same area and turf lists on each mob type)
|
||||
var/list/area_blacklist = list() //areas to be avoided
|
||||
var/list/area_whitelist = list() //areas to be more preferred
|
||||
var/list/turf_blacklist = list() //turf types to be avoided
|
||||
var/list/turf_whitelist = list() //turf types to be more preferred
|
||||
|
||||
//Type defines, to avoid spelling mistakes
|
||||
/datum/mob_type/fire
|
||||
name = "Fire"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_ROCK,
|
||||
TYPE_GROUND)
|
||||
resistance = list(TYPE_BUG,
|
||||
TYPE_FIRE,
|
||||
TYPE_GRASS,
|
||||
TYPE_ICE,
|
||||
TYPE_STEEL)
|
||||
area_blacklist = list(/area/crew_quarters/toilet,
|
||||
/area/crew_quarters/sleep_male/toilet_male,
|
||||
/area/crew_quarters/sleep_female/toilet_female,
|
||||
/area/crew_quarters/locker/locker_toilet,
|
||||
/area/toxins/server_coldroom)
|
||||
area_whitelist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
turf_blacklist = list(/turf/simulated/floor/beach/water)
|
||||
|
||||
/datum/mob_type/water
|
||||
name = "Water"
|
||||
weakness = list(TYPE_ELECTRIC,
|
||||
TYPE_GRASS)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_ICE,
|
||||
TYPE_STEEL,
|
||||
TYPE_WATER)
|
||||
area_blacklist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
area_whitelist = list(/area/crew_quarters/toilet,
|
||||
/area/crew_quarters/sleep_male/toilet_male,
|
||||
/area/crew_quarters/sleep_female/toilet_female,
|
||||
/area/crew_quarters/locker/locker_toilet)
|
||||
turf_whitelist = list(/turf/simulated/floor/beach/water)
|
||||
|
||||
/datum/mob_type/grass
|
||||
name = "Grass"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_BUG,
|
||||
TYPE_POISON,
|
||||
TYPE_ICE,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ELECTRIC,
|
||||
TYPE_GROUND)
|
||||
area_blacklist = list(/area/toxins)
|
||||
area_whitelist = list(/area/hydroponics,
|
||||
/area/hallway/secondary/construction)
|
||||
turf_whitelist = list(/turf/simulated/floor/grass)
|
||||
|
||||
/datum/mob_type/electric
|
||||
name = "Electric"
|
||||
weakness = list(TYPE_GROUND)
|
||||
resistance = list(TYPE_ELECTRIC,
|
||||
TYPE_FLYING,
|
||||
TYPE_STEEL)
|
||||
area_whitelist = list(/area/engine,
|
||||
/area/toxins/server,
|
||||
/area/maintenance,
|
||||
/area/turret_protected/ai,
|
||||
/area/turret_protected/ai_upload,
|
||||
/area/turret_protected/aisat_interior,
|
||||
/area/aisat,
|
||||
/area/assembly)
|
||||
turf_whitelist = list(/turf/simulated/floor/bluegrid)
|
||||
|
||||
/datum/mob_type/ground
|
||||
name = "Ground"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ICE)
|
||||
resistance = list(TYPE_ROCK,
|
||||
TYPE_POISON)
|
||||
immunity = list(TYPE_ELECTRIC)
|
||||
|
||||
/datum/mob_type/rock
|
||||
name = "Rock"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING,
|
||||
TYPE_STEEL)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_FLYING,
|
||||
TYPE_POISON,
|
||||
TYPE_NORMAL)
|
||||
area_whitelist = list(/area/quartermaster,
|
||||
/area/maintenance/disposal)
|
||||
turf_whitelist = list(/turf/simulated/wall,
|
||||
/turf/simulated/floor/mineral)
|
||||
|
||||
/datum/mob_type/bug
|
||||
name = "Bug"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_ROCK,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING)
|
||||
area_blacklist = list(/area/toxins)
|
||||
area_whitelist = list(/area/hydroponics,
|
||||
/area/hallway/secondary/construction)
|
||||
turf_whitelist = list(/turf/simulated/floor/grass)
|
||||
|
||||
/datum/mob_type/poison
|
||||
name = "Poison"
|
||||
weakness = list(TYPE_GROUND,
|
||||
TYPE_PSYCHIC)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_BUG,
|
||||
TYPE_POISON,
|
||||
TYPE_FIGHTING)
|
||||
area_blacklist = list(/area/medical,
|
||||
/area/security/medbay,
|
||||
/area/janitor)
|
||||
area_whitelist = list(/area/medical/virology,
|
||||
/area/toxins,
|
||||
/area/medical/research,
|
||||
/area/medical/research_shuttle_dock,
|
||||
/area/crew_quarters/hor,
|
||||
/area/maintenance/asmaint2)
|
||||
|
||||
/datum/mob_type/normal
|
||||
name = "Normal"
|
||||
weakness = list(TYPE_FIGHTING)
|
||||
immunity = list(TYPE_GHOST)
|
||||
|
||||
/datum/mob_type/fighting
|
||||
name = "Fighting"
|
||||
weakness = list(TYPE_PSYCHIC,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_ROCK,
|
||||
TYPE_BUG,
|
||||
TYPE_DARK)
|
||||
area_blacklist = list(/area/medical)
|
||||
area_whitelist = list(/area/crew_quarters/bar,
|
||||
/area/crew_quarters/fitness,
|
||||
/area/security)
|
||||
turf_whitelist = list(/turf/simulated/floor/wood)
|
||||
|
||||
/datum/mob_type/psychic
|
||||
name = "Psychic"
|
||||
weakness = list(TYPE_BUG,
|
||||
TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
resistance = list(TYPE_FIGHTING,
|
||||
TYPE_PSYCHIC)
|
||||
area_blacklist = list(/area/toxins,
|
||||
/area/medical/research,
|
||||
/area/medical/research_shuttle_dock,
|
||||
/area/crew_quarters/hor,
|
||||
/area/maintenance/asmaint2,
|
||||
/area/teleporter,
|
||||
/area/gateway)
|
||||
area_whitelist = list(/area/library,
|
||||
/area/chapel,
|
||||
/area/medical/psych)
|
||||
|
||||
/datum/mob_type/ghost
|
||||
name = "Ghost"
|
||||
weakness = list(TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
resistance = list(TYPE_BUG,
|
||||
TYPE_POISON)
|
||||
immunity = list(TYPE_NORMAL,
|
||||
TYPE_FIGHTING)
|
||||
area_whitelist = list(/area/medical/morgue,
|
||||
/area/chapel,
|
||||
/area/medical/genetics_cloning)
|
||||
|
||||
/datum/mob_type/ice
|
||||
name = "Ice"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_ROCK,
|
||||
TYPE_FIGHTING,
|
||||
TYPE_STEEL)
|
||||
resistance = list(TYPE_ICE)
|
||||
area_blacklist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
area_whitelist = list(/area/toxins/server_coldroom)
|
||||
|
||||
/datum/mob_type/flying
|
||||
name = "Flying"
|
||||
weakness = list(TYPE_ELECTRIC,
|
||||
TYPE_ROCK,
|
||||
TYPE_ICE)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_BUG,
|
||||
TYPE_FIGHTING)
|
||||
immunity = list(TYPE_GROUND)
|
||||
area_blacklist = list(/area/maintenance)
|
||||
area_whitelist = list(/area/hallway,
|
||||
/area/escapepodbay,
|
||||
/area/engine/mechanic_workshop,
|
||||
/area/security/podbay)
|
||||
|
||||
/datum/mob_type/bluespace
|
||||
name = "Bluespace"
|
||||
weakness = list(TYPE_ICE,
|
||||
TYPE_BLUESPACE)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ELECTRIC)
|
||||
|
||||
/datum/mob_type/dark
|
||||
name = "Dark"
|
||||
weakness = list(TYPE_BUG,
|
||||
TYPE_FIGHTING)
|
||||
resistance = list(TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
immunity = list(TYPE_PSYCHIC)
|
||||
area_blacklist = list(/area/solar,
|
||||
/area/maintenance/auxsolarport,
|
||||
/area/maintenance/starboardsolar,
|
||||
/area/maintenance/portsolar,
|
||||
/area/maintenance/auxsolarstarboard,
|
||||
/area/clownoffice)
|
||||
area_whitelist = list(/area/maintenance,
|
||||
/area/assembly/assembly_line,
|
||||
/area/mimeoffice)
|
||||
turf_blacklist = list(/turf/simulated/floor/light)
|
||||
|
||||
/datum/mob_type/steel
|
||||
name = "Steel"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_ROCK,
|
||||
TYPE_BUG,
|
||||
TYPE_NORMAL,
|
||||
TYPE_PSYCHIC,
|
||||
TYPE_ICE,
|
||||
TYPE_FLYING,
|
||||
TYPE_BLUESPACE,
|
||||
TYPE_STEEL)
|
||||
immunity = list(TYPE_POISON)
|
||||
@@ -190,6 +190,12 @@ var/global/datum/prizes/global_prizes = new
|
||||
typepath = /obj/item/weapon/spellbook/oneuse/fake_gib
|
||||
cost = 100
|
||||
|
||||
/datum/prize_item/nanomob_booster
|
||||
name = "Nano-Mob Hunter Trading Card Booster Pack"
|
||||
desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!"
|
||||
typepath = /obj/item/weapon/storage/box/nanomob_booster_pack
|
||||
cost = 100
|
||||
|
||||
/datum/prize_item/capgun
|
||||
name = "Capgun Revolver"
|
||||
desc = "Do you feel lucky... punk?"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/artillerycontrol/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/artillerycontrol/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/time_to_wait = round(reload_cooldown - ((world.time / 10) - last_fire), 1)
|
||||
|
||||
@@ -9,14 +9,14 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
unacidable = 1
|
||||
var/active = 0
|
||||
|
||||
/obj/machinery/gateway/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
update_density_from_dir()
|
||||
|
||||
/obj/machinery/gateway/New()
|
||||
if(!the_gateway)
|
||||
the_gateway = src
|
||||
spawn(25)
|
||||
update_icon()
|
||||
if(dir == 2)
|
||||
density = 0
|
||||
/obj/machinery/gateway/proc/update_density_from_dir()
|
||||
if(dir == 2)
|
||||
density = 0
|
||||
|
||||
|
||||
/obj/machinery/gateway/update_icon()
|
||||
@@ -40,13 +40,18 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
var/obj/machinery/gateway/centeraway/awaygate = null
|
||||
|
||||
/obj/machinery/gateway/centerstation/New()
|
||||
..()
|
||||
if(!the_gateway)
|
||||
the_gateway = src
|
||||
spawn(25)
|
||||
update_icon()
|
||||
wait = world.time + config.gateway_delay //+ thirty minutes default
|
||||
awaygate = locate(/obj/machinery/gateway/centeraway) in world
|
||||
|
||||
/obj/machinery/gateway/centerstation/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
wait = world.time + config.gateway_delay //+ thirty minutes default
|
||||
awaygate = locate(/obj/machinery/gateway/centeraway) in world
|
||||
|
||||
/obj/machinery/gateway/centerstation/update_density_from_dir()
|
||||
return
|
||||
|
||||
/obj/machinery/gateway/centerstation/Destroy()
|
||||
if(the_gateway == src)
|
||||
@@ -61,7 +66,7 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
|
||||
|
||||
|
||||
obj/machinery/gateway/centerstation/process()
|
||||
/obj/machinery/gateway/centerstation/process()
|
||||
if(stat & (NOPOWER))
|
||||
if(active) toggleoff()
|
||||
return
|
||||
@@ -165,12 +170,15 @@ obj/machinery/gateway/centerstation/process()
|
||||
var/obj/machinery/gateway/centeraway/stationgate = null
|
||||
|
||||
|
||||
/obj/machinery/gateway/centeraway/New()
|
||||
spawn(25)
|
||||
update_icon()
|
||||
stationgate = locate(/obj/machinery/gateway/centerstation) in world
|
||||
/obj/machinery/gateway/centeraway/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
stationgate = locate(/obj/machinery/gateway/centerstation) in world
|
||||
|
||||
|
||||
/obj/machinery/gateway/centeraway/update_density_from_dir()
|
||||
return
|
||||
|
||||
/obj/machinery/gateway/centeraway/update_icon()
|
||||
if(active)
|
||||
icon_state = "oncenter"
|
||||
|
||||
@@ -261,6 +261,8 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
send_asset_list(client, uncommon)
|
||||
send_asset_list(client, common)
|
||||
|
||||
|
||||
//Pill sprites for UIs
|
||||
/datum/asset/chem_master
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
@@ -274,4 +276,21 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
|
||||
//Mob Hunt sprites for UIs
|
||||
/datum/asset/mob_hunt
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/mob_hunt/register()
|
||||
for(var/state in icon_states('icons/effects/mob_hunt.dmi'))
|
||||
if(state == "Placeholder")
|
||||
continue
|
||||
assets["[state].png"] = icon('icons/effects/mob_hunt.dmi', state)
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/mob_hunt/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
@@ -111,49 +111,49 @@
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Barber",5)
|
||||
DB_job_unlock("Barber",5)
|
||||
return
|
||||
if("2")
|
||||
if(karma <5)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Brig Physician",5)
|
||||
DB_job_unlock("Brig Physician",5)
|
||||
return
|
||||
if("3")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Nanotrasen Representative",30)
|
||||
DB_job_unlock("Nanotrasen Representative",30)
|
||||
return
|
||||
if("5")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Blueshield",30)
|
||||
DB_job_unlock("Blueshield",30)
|
||||
return
|
||||
if("6")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Mechanic",30)
|
||||
DB_job_unlock("Mechanic",30)
|
||||
return
|
||||
if("7")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Magistrate",45)
|
||||
DB_job_unlock("Magistrate",45)
|
||||
return
|
||||
if("9")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Security Pod Pilot",30)
|
||||
DB_job_unlock("Security Pod Pilot",30)
|
||||
return
|
||||
if(href_list["KarmaBuy2"])
|
||||
var/karma=verify_karma()
|
||||
@@ -163,55 +163,55 @@
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Machine",15)
|
||||
DB_species_unlock("Machine",15)
|
||||
return
|
||||
if("2")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Kidan",30)
|
||||
DB_species_unlock("Kidan",30)
|
||||
return
|
||||
if("3")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Grey",30)
|
||||
DB_species_unlock("Grey",30)
|
||||
return
|
||||
if("4")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Vox",45)
|
||||
DB_species_unlock("Vox",45)
|
||||
return
|
||||
if("5")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Slime People",45)
|
||||
DB_species_unlock("Slime People",45)
|
||||
return
|
||||
if("6")
|
||||
if(karma <100)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Plasmaman",100)
|
||||
DB_species_unlock("Plasmaman",100)
|
||||
return
|
||||
if("7")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Drask",30)
|
||||
DB_species_unlock("Drask",30)
|
||||
return
|
||||
if(href_list["KarmaRefund"])
|
||||
var/type = href_list["KarmaRefundType"]
|
||||
var/job = href_list["KarmaRefund"]
|
||||
var/cost = href_list["KarmaRefundCost"]
|
||||
src.karmarefund(type,job,cost)
|
||||
karmarefund(type,job,cost)
|
||||
return
|
||||
|
||||
switch(href_list["_src_"])
|
||||
@@ -273,6 +273,7 @@
|
||||
//CONNECT//
|
||||
///////////
|
||||
/client/New(TopicData)
|
||||
var/tdata = TopicData //save this for later use
|
||||
chatOutput = new /datum/chatOutput(src) // Right off the bat.
|
||||
TopicData = null //Prevent calls to client.Topic from connect
|
||||
|
||||
@@ -290,8 +291,8 @@
|
||||
|
||||
// Change the way they should download resources.
|
||||
if(config.resource_urls)
|
||||
src.preload_rsc = pick(config.resource_urls)
|
||||
else src.preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
|
||||
preload_rsc = pick(config.resource_urls)
|
||||
else preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
|
||||
|
||||
to_chat(src, "\red If the title screen is black, resources are still downloading. Please be patient until the title screen appears.")
|
||||
|
||||
@@ -340,7 +341,7 @@
|
||||
winset(src, null, "command=\".configure graphics-hwmode off\"")
|
||||
winset(src, null, "command=\".configure graphics-hwmode on\"")
|
||||
|
||||
log_client_to_db()
|
||||
log_client_to_db(tdata)
|
||||
|
||||
if(ckey in clientmessages)
|
||||
for(var/message in clientmessages[ckey])
|
||||
@@ -399,7 +400,7 @@
|
||||
donator_level = text2num(query_donor_select.item[2])
|
||||
break
|
||||
|
||||
/client/proc/log_client_to_db()
|
||||
/client/proc/log_client_to_db(connectiontopic)
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
@@ -430,6 +431,14 @@
|
||||
if(ckey != query_cid.item[1])
|
||||
related_accounts_cid.Add("[query_cid.item[1]]")
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(holder)
|
||||
admin_rank = holder.rank
|
||||
// Admins don't get slammed by this, I guess
|
||||
else
|
||||
if(check_randomizer(connectiontopic))
|
||||
return
|
||||
|
||||
//Log all the alts
|
||||
if(related_accounts_cid.len)
|
||||
log_access("Alts: [key_name(src)]:[jointext(related_accounts_cid, " - ")]")
|
||||
@@ -446,10 +455,6 @@
|
||||
if(!isnum(sql_id))
|
||||
return
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(src.holder)
|
||||
admin_rank = src.holder.rank
|
||||
|
||||
var/sql_ip = sanitizeSQL(address)
|
||||
var/sql_computerid = sanitizeSQL(computer_id)
|
||||
var/sql_admin_rank = sanitizeSQL(admin_rank)
|
||||
@@ -469,11 +474,128 @@
|
||||
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');")
|
||||
query_accesslog.Execute()
|
||||
|
||||
|
||||
#undef TOPIC_SPAM_DELAY
|
||||
#undef UPLOAD_LIMIT
|
||||
#undef MIN_CLIENT_VERSION
|
||||
|
||||
// Returns true if a randomizer is being used
|
||||
/client/proc/check_randomizer(topic)
|
||||
. = FALSE
|
||||
if(connection != "seeker") //Invalid connection type.
|
||||
return null
|
||||
topic = params2list(topic)
|
||||
if(!config.check_randomizer)
|
||||
return
|
||||
// Stash o' ckeys
|
||||
var/static/cidcheck = list()
|
||||
var/static/tokens = list()
|
||||
// Ckeys that failed the test, stored to send acceptance messages only for atoners
|
||||
var/static/cidcheck_failedckeys = list()
|
||||
var/static/cidcheck_spoofckeys = list()
|
||||
|
||||
var/oldcid = cidcheck[ckey]
|
||||
|
||||
if(!oldcid)
|
||||
var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
query_cidcheck.Execute()
|
||||
|
||||
var/lastcid = computer_id
|
||||
if(query_cidcheck.NextRow())
|
||||
lastcid = query_cidcheck.item[1]
|
||||
|
||||
if(computer_id != lastcid)
|
||||
// Their current CID does not match what the DB says - OFF WITH THEIR HEAD
|
||||
cidcheck[ckey] = computer_id
|
||||
|
||||
// Disable the reconnect button to force a CID change
|
||||
winset(src, "reconnectbutton", "is-disable=true")
|
||||
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
sleep(10) // Since browse is non-instant, and kinda async
|
||||
|
||||
to_chat(src, "<pre class=\"system system\">you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point</pre>")
|
||||
del(src)
|
||||
return TRUE
|
||||
else
|
||||
if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
|
||||
if (!cidcheck_spoofckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] appears to have attempted to spoof a cid randomizer check.</span>")
|
||||
cidcheck_spoofckeys[ckey] = TRUE
|
||||
cidcheck[ckey] = computer_id
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
|
||||
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.
|
||||
del(src)
|
||||
return TRUE
|
||||
// We DO have their cached CID handy - compare it, now
|
||||
if(oldcid != computer_id)
|
||||
// Change detected, they are randomizing
|
||||
cidcheck -= ckey // To allow them to try again after removing CID randomization
|
||||
|
||||
to_chat(src, "<span class='userdanger'>Connection Error:</span>")
|
||||
to_chat(src, "<span class='danger'>Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your BYOND installation and try again.</span>")
|
||||
|
||||
if(!cidcheck_failedckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] has been detected as using a CID randomizer. Connection rejected.</span>")
|
||||
send2irc(config.cidrandomizer_irc, "[key_name(src)] has been detected as using a CID randomizer. Connection rejected.")
|
||||
cidcheck_failedckeys[ckey] = TRUE
|
||||
note_randomizer_user()
|
||||
|
||||
log_access("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])")
|
||||
|
||||
del(src)
|
||||
return TRUE
|
||||
else
|
||||
// don't shoot, I'm innocent
|
||||
if(cidcheck_failedckeys[ckey])
|
||||
// Atonement
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer</span>")
|
||||
send2irc(config.cidrandomizer_irc, "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
|
||||
cidcheck_failedckeys -= ckey
|
||||
if (cidcheck_spoofckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it <i>appears</i> they aren't spoofing one this time</span>")
|
||||
cidcheck_spoofckeys -= ckey
|
||||
cidcheck -= ckey
|
||||
|
||||
/client/proc/note_randomizer_user()
|
||||
var/const/adminckey = "CID-Error"
|
||||
|
||||
// Check for notes in the last day - only 1 note per 24 hours
|
||||
var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n")
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
return
|
||||
|
||||
// Only add a note if their most recent note isn't from the randomizer blocker, either
|
||||
query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n")
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
if(query_get_notes.item[1] == adminckey)
|
||||
return
|
||||
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0)
|
||||
|
||||
/client/proc/cid_check_reconnect()
|
||||
var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
|
||||
. = token
|
||||
log_access("Failed Login: [key] [computer_id] [address] - CID randomizer check")
|
||||
var/url = winget(src, null, "url")
|
||||
//special javascript to make them reconnect under a new window.
|
||||
src << browse("<a id='link' href='byond://[url]?token=[token]'>\
|
||||
byond://[url]?token=[token]\
|
||||
</a>\
|
||||
<script type='text/javascript'>\
|
||||
document.getElementById(\"link\").click();\
|
||||
window.location=\"byond://winset?command=.quit\"\
|
||||
</script>",
|
||||
"border=0;titlebar=0;size=1x1")
|
||||
to_chat(src, "<a href='byond://[url]?token=[token]'>You will be automatically taken to the game, if not, click here to be taken manually</a>. Except you can't, since the chat window doesn't exist yet.")
|
||||
|
||||
//checks if a client is afk
|
||||
//3000 frames = 5 minutes
|
||||
/client/proc/is_afk(duration=3000)
|
||||
|
||||
@@ -74,3 +74,8 @@
|
||||
/datum/gear/skullbandana
|
||||
display_name = "bandana, skull"
|
||||
path = /obj/item/clothing/mask/bandana/skull
|
||||
|
||||
/datum/gear/mob_hunt_game
|
||||
display_name = "Nano-Mob Hunter GO! Cartridge"
|
||||
path = /obj/item/weapon/cartridge/mob_hunt_game
|
||||
cost = 2
|
||||
|
||||
@@ -82,6 +82,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
|
||||
//game-preferences
|
||||
var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
|
||||
var/exp
|
||||
var/ooccolor = "#b82e00"
|
||||
var/be_special = list() //Special role selection
|
||||
var/UI_style = "Midnight"
|
||||
@@ -593,6 +594,10 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
if(jobban_isbanned(user, rank))
|
||||
HTML += "<del>[rank]</del></td><td><b> \[BANNED]</b></td></tr>"
|
||||
continue
|
||||
var/available_in_playtime = job.available_in_playtime(user.client)
|
||||
if(available_in_playtime)
|
||||
HTML += "<del>[rank]</del></td><td> \[ " + get_exp_format(available_in_playtime) + " as " + job.get_exp_req_type() + "</td></tr>"
|
||||
continue
|
||||
if(!job.player_old_enough(user.client))
|
||||
var/available_in_days = job.available_in_days(user.client)
|
||||
HTML += "<del>[rank]</del></td><td> \[IN [(available_in_days)] DAYS]</td></tr>"
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
volume,
|
||||
nanoui_fancy,
|
||||
show_ghostitem_attack,
|
||||
lastchangelog
|
||||
lastchangelog,
|
||||
exp
|
||||
FROM [format_table_name("player")]
|
||||
WHERE ckey='[C.ckey]'"}
|
||||
)
|
||||
@@ -40,6 +41,7 @@
|
||||
nanoui_fancy = text2num(query.item[11])
|
||||
show_ghostitem_attack = text2num(query.item[12])
|
||||
lastchangelog = query.item[13]
|
||||
exp = query.item[14]
|
||||
|
||||
//Sanitize
|
||||
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
|
||||
@@ -54,6 +56,7 @@
|
||||
nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy))
|
||||
show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack))
|
||||
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
|
||||
exp = sanitize_text(exp, initial(exp))
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/save_preferences(client/C)
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
var/invis_override = 0
|
||||
|
||||
var/emagged = 0
|
||||
var/color_view = null//overrides client.color while worn
|
||||
var/list/color_view = null//overrides client.color while worn
|
||||
var/prescription = 0
|
||||
var/prescription_upgradable = 0
|
||||
strip_delay = 20 // but seperated to allow items to protect but not impair vision, like space helmets
|
||||
|
||||
@@ -243,26 +243,35 @@
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/proc/toggle_noir()
|
||||
var/list/difference = difflist(usr.client.color, color_view)
|
||||
|
||||
if(!noir_mode)
|
||||
if(color_view && usr.client && !usr.client.color)
|
||||
if(color_view && usr.client && (!usr.client.color || difference))
|
||||
animate(usr.client, color = color_view, time = 10)
|
||||
noir_mode = 1
|
||||
else
|
||||
if(usr.client && usr.client.color)
|
||||
animate(usr.client, color = null, time = 10)
|
||||
if(usr.client && usr.client.color && !difference)
|
||||
animate(usr.client, color = initial(usr.client.color), time = 10)
|
||||
noir_mode = 0
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/equipped(mob/user, slot)
|
||||
var/list/difference = difflist(user.client.color, color_view)
|
||||
|
||||
if(slot == slot_glasses)
|
||||
if(noir_mode)
|
||||
if(color_view && user.client && !user.client.color)
|
||||
if(color_view && user.client && (!user.client.color || difference.len))
|
||||
animate(user.client, color = color_view, time = 10)
|
||||
else
|
||||
if(user.client && user.client.color && !difference.len)
|
||||
animate(user.client, color = initial(user.client.color), time = 10)
|
||||
..(user, slot)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/dropped(mob/living/carbon/human/user)
|
||||
var/list/difference = difflist(user.client.color, color_view)
|
||||
|
||||
if(istype(user) && user.glasses == src)
|
||||
if(user.client && user.client.color)
|
||||
animate(user.client, color = null, time = 10)
|
||||
if(user.client && user.client.color && !difference.len)
|
||||
animate(user.client, color = initial(user.client.color), time = 10)
|
||||
..(user)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/yeah
|
||||
|
||||
@@ -514,7 +514,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/weapon/rig/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/weapon/rig/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
|
||||
data["primarysystem"] = null
|
||||
|
||||
@@ -313,6 +313,11 @@
|
||||
icon_state = "eyepro"
|
||||
item_state = "eyepro"
|
||||
|
||||
/obj/item/clothing/glasses/hud/security/sunglasses/fluff/voxxyhud //LP Spartan: Kaskreyarawkta
|
||||
name = "VoxxyHUD"
|
||||
desc = "A worn down visor from a vox raider's gear, crudely ripped from its helmet and linked into the security systems of the station. The word 'Kask' is scratched into the side."
|
||||
icon_state = "hud-spartan"
|
||||
|
||||
//////////// Hats ////////////
|
||||
/obj/item/clothing/head/fluff/heather_winceworth // Regens: Heather Winceworth
|
||||
name= "Heather's rose"
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/account_database/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/account_database/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["src"] = UID()
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
ui = new(user, src, ui_key, "smartfridge.tmpl", name, 400, 500)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/smartfridge/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/smartfridge/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["contents"] = null
|
||||
|
||||
@@ -634,14 +634,20 @@
|
||||
chems[rid] = gene_chem.Copy()
|
||||
continue
|
||||
|
||||
// Normally a length 2 list - but sometimes, it's length 1 - poisonberries, etc.
|
||||
// This means the reagent does not scale with potency.
|
||||
// Index 1 is the base value, index 2 is the potency per u of reagent
|
||||
var/list/rgnt_list = chems[rid]
|
||||
rgnt_list.len = max(gene_chem.len, rgnt_list.len)
|
||||
|
||||
for(var/i=1;i<=gene_chem.len;i++)
|
||||
|
||||
if(isnull(gene_chem[i])) gene_chem[i] = 0
|
||||
|
||||
if(chems[rid][i])
|
||||
chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2))
|
||||
if(rgnt_list[i])
|
||||
rgnt_list[i] = max(1,round((gene_chem[i] + rgnt_list[i])/2))
|
||||
else
|
||||
chems[rid][i] = gene_chem[i]
|
||||
rgnt_list[i] = gene_chem[i]
|
||||
|
||||
var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"]
|
||||
if(islist(new_gasses))
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/botany/extractor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/botany/extractor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/list/geneMasks[0]
|
||||
@@ -318,7 +318,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/botany/editor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/botany/editor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["activity"] = active
|
||||
|
||||
@@ -428,6 +428,19 @@
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/terrorspider
|
||||
name = "Spider Hivemind"
|
||||
desc = "Terror spiders have a limited ability to commune over a psychic hivemind, similar to xenomorphs."
|
||||
speech_verb = "chitters"
|
||||
ask_verb = "chitters"
|
||||
exclaim_verb = "chitters"
|
||||
colour = "terrorspider"
|
||||
key = "ts"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/ling
|
||||
name = "Changeling"
|
||||
desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance."
|
||||
@@ -559,7 +572,7 @@
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
drone_only = 1
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/drone
|
||||
name = "Drone"
|
||||
desc = "An encrypted stream of data converted to speech patterns."
|
||||
|
||||
@@ -454,8 +454,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
|
||||
totalMembers |= pipeline.other_atmosmch
|
||||
for(var/obj/machinery/atmospherics/A in totalMembers)
|
||||
if(!A.pipe_image)
|
||||
A.pipe_image = image(A, A.loc, layer = 20, dir = A.dir) //the 20 puts it above Byond's darkness (not its opacity view)
|
||||
A.pipe_image.plane = HUD_PLANE
|
||||
A.update_pipe_image()
|
||||
pipes_shown += A.pipe_image
|
||||
client.images += A.pipe_image
|
||||
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
clear_fullscreen("blind")
|
||||
update_sight()
|
||||
else if(aiRestorePowerRoutine == 3)
|
||||
to_chat(src, "Alert cancelled. Power has been restored.")
|
||||
aiRestorePowerRoutine = 0
|
||||
clear_fullscreen("blind")
|
||||
update_sight()
|
||||
|
||||
|
||||
else
|
||||
|
||||
@@ -114,8 +114,6 @@
|
||||
C.toff = 1
|
||||
..()
|
||||
|
||||
/mob/living/silicon/pai/Login()
|
||||
..()
|
||||
|
||||
// this function shows the information about being silenced as a pAI in the Status panel
|
||||
/mob/living/silicon/pai/proc/show_silenced()
|
||||
|
||||
@@ -41,7 +41,12 @@ var/global/list/default_pai_software = list()
|
||||
if(ui_key != "main")
|
||||
var/datum/pai_software/S = software[ui_key]
|
||||
if(S && !S.toggle)
|
||||
S.on_ui_interact(src, ui, force_open)
|
||||
ui = nanomanager.try_update_ui(user, src, S.id, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, S.id, S.template_file, S.ui_title, S.ui_width, S.ui_height, state = state)
|
||||
ui.open()
|
||||
if(S.autoupdate)
|
||||
ui.set_auto_update(1)
|
||||
else
|
||||
if(ui)
|
||||
ui.set_status(STATUS_CLOSE, 0)
|
||||
@@ -53,9 +58,15 @@ var/global/list/default_pai_software = list()
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/mob/living/silicon/pai/ui_data(mob/user, datum/topic_state/state = self_state)
|
||||
/mob/living/silicon/pai/ui_data(mob/user, ui_key = "main", datum/topic_state/state = self_state)
|
||||
var/data[0]
|
||||
|
||||
if(ui_key != "main")
|
||||
var/datum/pai_software/S = software[ui_key]
|
||||
if(S && !S.toggle)
|
||||
return S.on_ui_data(user, state)
|
||||
log_runtime(EXCEPTION("Unrecognized/invalid pAI UI state '[ui_key]'"), src)
|
||||
return
|
||||
// Software we have bought
|
||||
var/bought_software[0]
|
||||
// Software we have not bought
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -285,6 +285,7 @@
|
||||
|
||||
if(player.mob && player.mob.mind)
|
||||
player.mob.mind.transfer_to(src)
|
||||
player.mob.mind.assigned_role = "Drone"
|
||||
|
||||
lawupdate = 0
|
||||
to_chat(src, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>.")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
#define SPINNING_WEB 1
|
||||
#define LAYING_EGGS 2
|
||||
#define MOVING_TO_TARGET 3
|
||||
#define SPINNING_COCOON 4
|
||||
|
||||
#define TS_TIER_1 1
|
||||
#define TS_TIER_2 2
|
||||
#define TS_TIER_3 3
|
||||
#define TS_TIER_4 4
|
||||
#define TS_TIER_5 5
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
|
||||
/datum/action/innate/terrorspider/web
|
||||
name = "Web"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "stickyweb1"
|
||||
|
||||
/datum/action/innate/terrorspider/web/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.Web()
|
||||
|
||||
/datum/action/innate/terrorspider/wrap
|
||||
name = "Wrap"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "cocoon_large1"
|
||||
|
||||
/datum/action/innate/terrorspider/wrap/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.FindWrapTarget()
|
||||
user.DoWrap()
|
||||
|
||||
|
||||
// ---------- WEB
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web()
|
||||
visible_message("<span class='notice'>[src] begins to secrete a sticky substance.</span>")
|
||||
if(do_after(src, 40, target = loc))
|
||||
var/obj/effect/spider/terrorweb/T = locate() in get_turf(src)
|
||||
if(T)
|
||||
to_chat(src, "<span class='danger'>There is already a web here.</span>")
|
||||
else
|
||||
new /obj/effect/spider/terrorweb(loc)
|
||||
|
||||
/obj/effect/spider/terrorweb
|
||||
name = "terror web"
|
||||
desc = "it's stringy and sticky"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
anchored = 1 // prevents people dragging it
|
||||
density = 0 // prevents it blocking all movement
|
||||
health = 20 // two welders, or one laser shot (15 for the normal spider webs)
|
||||
icon_state = "stickyweb1"
|
||||
|
||||
|
||||
/obj/effect/spider/terrorweb/New()
|
||||
..()
|
||||
if(prob(50))
|
||||
icon_state = "stickyweb2"
|
||||
|
||||
|
||||
/obj/effect/spider/terrorweb/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
return 1
|
||||
if(isliving(mover))
|
||||
if(prob(80))
|
||||
to_chat(mover, "<span class='danger'>You get stuck in [src] for a moment.</span>")
|
||||
var/mob/living/M = mover
|
||||
M.Stun(4) // 8 seconds.
|
||||
M.Weaken(4) // 8 seconds.
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
return prob(20)
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------- WRAP
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget()
|
||||
if(!cocoon_target)
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/L in oview(1,src))
|
||||
if(Adjacent(L))
|
||||
if(L.stat == DEAD)
|
||||
choices += L
|
||||
for(var/obj/O in oview(1,src))
|
||||
if(Adjacent(O) && !O.anchored)
|
||||
if(!istype(O, /obj/effect/spider/terrorweb) && !istype(O, /obj/effect/spider/cocoon))
|
||||
choices += O
|
||||
if(choices.len)
|
||||
cocoon_target = input(src,"What do you wish to cocoon?") in null|choices
|
||||
else
|
||||
to_chat(src, "<span class='danger'>There is nothing nearby you can wrap.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoWrap()
|
||||
if(cocoon_target && busy != SPINNING_COCOON)
|
||||
busy = SPINNING_COCOON
|
||||
visible_message("<span class='notice'>[src] begins to secrete a sticky substance around [cocoon_target].</span>")
|
||||
stop_automated_movement = 1
|
||||
walk(src,0)
|
||||
if(do_after(src, 40, target = cocoon_target.loc))
|
||||
if(busy == SPINNING_COCOON)
|
||||
if(cocoon_target && isturf(cocoon_target.loc) && get_dist(src,cocoon_target) <= 1)
|
||||
var/obj/effect/spider/cocoon/C = new(cocoon_target.loc)
|
||||
var/large_cocoon = 0
|
||||
C.pixel_x = cocoon_target.pixel_x
|
||||
C.pixel_y = cocoon_target.pixel_y
|
||||
for(var/obj/O in C.loc)
|
||||
if(istype(O, /obj/item))
|
||||
O.loc = C
|
||||
else if(istype(O, /obj/machinery) || istype(O, /obj/structure))
|
||||
O.loc = C
|
||||
large_cocoon = 1
|
||||
for(var/mob/living/L in C.loc)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
continue
|
||||
if(iscarbon(L))
|
||||
regen_points += regen_points_per_kill
|
||||
fed++
|
||||
large_cocoon = 1
|
||||
last_cocoon_object = 0
|
||||
L.loc = C
|
||||
C.pixel_x = L.pixel_x
|
||||
C.pixel_y = L.pixel_y
|
||||
visible_message("<span class='danger'>[src] sticks a proboscis into [L] and sucks a viscous substance out.</span>")
|
||||
break
|
||||
if(large_cocoon)
|
||||
C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
|
||||
cocoon_target = null
|
||||
busy = 0
|
||||
stop_automated_movement = 0
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T2 BLACK TERROR ------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: assassin, poisoner, DoT expert
|
||||
// -------------: AI: attacks to inject its venom, then retreats. Will inject its enemies multiple times then hang back to ensure they die.
|
||||
// -------------: SPECIAL: venom that does more damage the more of it is in you
|
||||
// -------------: TO FIGHT IT: if bitten once, retreat, get charcoal/etc treatment, and come back with a gun.
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/black
|
||||
name = "Black Terror spider"
|
||||
desc = "An ominous-looking spider, black as the darkest night, and with merciless eyes and a blood-red hourglass pattern on its back."
|
||||
spider_role_summary = "Hit-and-run attacker with extremely venomous bite."
|
||||
|
||||
icon_state = "terror_widow"
|
||||
icon_living = "terror_widow"
|
||||
icon_dead = "terror_widow_dead"
|
||||
maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but its bite will kill you!
|
||||
health = 120
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 10
|
||||
move_to_delay = 5
|
||||
stat_attack = 1 // ensures they will target people in crit, too!
|
||||
spider_tier = TS_TIER_2
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/black/spider_specialattack(mob/living/carbon/human/L, poisonable)
|
||||
if(!poisonable)
|
||||
return ..()
|
||||
if(L.reagents.has_reagent("terror_black_toxin", 50))
|
||||
return ..()
|
||||
var/inject_target = pick("chest", "head")
|
||||
if(L.stunned || L.can_inject(null, 0, inject_target, 0))
|
||||
L.reagents.add_reagent("terror_black_toxin", 15) // inject our special poison
|
||||
visible_message("<span class='danger'>[src] buries its long fangs deep into the [inject_target] of [target]!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] bites [target], but cannot inject venom into their [inject_target]!</span>")
|
||||
L.attack_animal(src)
|
||||
@@ -0,0 +1,33 @@
|
||||
// Terror Spider, Black, Deadly Venom
|
||||
|
||||
/datum/reagent/terror_black_toxin
|
||||
name = "Black Widow venom"
|
||||
id = "terror_black_toxin"
|
||||
description = "An incredibly toxic venom injected by the Black Widow spider."
|
||||
color = "#CF3600"
|
||||
metabolization_rate = 0.1
|
||||
|
||||
/datum/reagent/terror_black_toxin/on_mob_life(mob/living/M)
|
||||
if(volume < 15)
|
||||
// bitten once, die slowly. Easy to survive a single bite - just go to medbay.
|
||||
// total damage: 2/tick, human health 150 until crit, = 75 ticks, = 150 seconds = 2.5 minutes to get to medbay.
|
||||
M.adjustToxLoss(2) // same damage/tick as tabun cycle 0 to 60
|
||||
else if(volume < 30)
|
||||
// bitten twice, die more quickly, muscle cramps make movement difficult. Call medics immediately.
|
||||
// total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death
|
||||
M.adjustToxLoss(4)
|
||||
M.Confused(3)
|
||||
M.EyeBlurry(3)
|
||||
else if(volume < 45)
|
||||
// bitten thrice, die very quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you.
|
||||
// total damage: 8, human health 150 until crit, = 18.75 ticks, = 37s until death
|
||||
M.adjustToxLoss(8) // a bit worse than coiine
|
||||
M.Confused(6)
|
||||
M.EyeBlurry(6)
|
||||
else
|
||||
// bitten 4 or more times, whole body goes into shock/death
|
||||
// total damage: 12, human health 150 until crit, = 12.5 ticks, = 25s until death
|
||||
M.adjustToxLoss(12)
|
||||
M.EyeBlurry(6)
|
||||
M.Paralyse(5)
|
||||
..()
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Topic(href, href_list)
|
||||
if(href_list["activate"])
|
||||
var/mob/dead/observer/ghost = usr
|
||||
if(istype(ghost))
|
||||
humanize_spider(ghost)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/attack_ghost(mob/user)
|
||||
humanize_spider(user)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/humanize_spider(mob/user)
|
||||
if(key)//Someone is in it
|
||||
return
|
||||
var/error_on_humanize = ""
|
||||
var/humanize_prompt = "Take direct control of [src]?"
|
||||
humanize_prompt += "Role: [spider_role_summary]"
|
||||
if(user.ckey in ts_ckey_blacklist)
|
||||
error_on_humanize = "You are not able to control any terror spider this round."
|
||||
else if(!ai_playercontrol_allowingeneral)
|
||||
error_on_humanize = "Terror spiders cannot currently be player-controlled."
|
||||
else if(spider_awaymission)
|
||||
error_on_humanize = "Terror spiders that are part of an away mission cannot be controlled by ghosts."
|
||||
else if(!ai_playercontrol_allowtype)
|
||||
error_on_humanize = "This specific type of terror spider is not player-controllable."
|
||||
else if(stat == DEAD)
|
||||
error_on_humanize = "Dead spiders are not player-controllable."
|
||||
if(jobban_isbanned(user, "Syndicate") || jobban_isbanned(user, "alien"))
|
||||
to_chat(user,"You are jobbanned from role of syndicate and/or alien lifeform.")
|
||||
return
|
||||
if(error_on_humanize == "")
|
||||
var/spider_ask = alert(humanize_prompt, "Join as Terror Spider?", "Yes", "No")
|
||||
if(spider_ask == "No" || !src || qdeleted(src))
|
||||
return
|
||||
else
|
||||
to_chat(user, "Cannot inhabit spider: [error_on_humanize]")
|
||||
return
|
||||
if(key)
|
||||
to_chat(user, "<span class='notice'>Someone else already took this spider.</span>")
|
||||
return
|
||||
key = user.key
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
G.show_message("<i>A ghost has taken control of <b>[src]</b>. ([ghost_follow_link(src, ghost=G)]).</i>")
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T1 GRAY TERROR -------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: fast, weak terror spider
|
||||
// -------------: SPECIAL: silences targets
|
||||
// -------------: TO FIGHT IT: shoot it!
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/gray
|
||||
name = "Gray Terror spider"
|
||||
desc = "An ominous-looking gray spider, it seems jittery."
|
||||
spider_role_summary = "Fast-moving but weak spider."
|
||||
icon_state = "terror_gray"
|
||||
icon_living = "terror_gray"
|
||||
icon_dead = "terror_gray_dead"
|
||||
maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but silences its targets
|
||||
health = 120
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 20
|
||||
ventcrawler = 1
|
||||
move_to_delay = 5 // normal speed
|
||||
stat_attack = 1 // ensures they will target people in crit, too!
|
||||
environment_smash = 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_specialattack(mob/living/carbon/human/L, poisonable)
|
||||
if(!poisonable)
|
||||
..()
|
||||
return
|
||||
if(L.silent >= 10)
|
||||
L.attack_animal(src)
|
||||
else
|
||||
var/inject_target = pick("chest","head")
|
||||
if(L.stunned || L.can_inject(null,0,inject_target,0))
|
||||
L.Silence(20) // instead of having a venom that only lasts seconds, we just add the silence directly.
|
||||
visible_message("<span class='danger'>[src] buries grey fangs deep into the [inject_target] of [target]!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] bites [target], but cannot inject venom into their [inject_target]!</span>")
|
||||
L.attack_animal(src)
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T3 PRINCE OF TERROR --------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: boss
|
||||
// -------------: AI: no special ai
|
||||
// -------------: SPECIAL: massive health
|
||||
// -------------: TO FIGHT IT: a squad of at least 4 people with laser rifles.
|
||||
// -------------: SPRITES FROM: Travelling Merchant, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=2766
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince
|
||||
name = "Prince of Terror spider"
|
||||
desc = "An enormous, terrifying spider. It looks like it is judging everything it sees. Its hide seems armored, and it bears the scars of many battles."
|
||||
spider_role_summary = "Boss-level terror spider. Lightning bruiser. Capable of taking on a squad by itself."
|
||||
icon_state = "terror_allblack"
|
||||
icon_living = "terror_allblack"
|
||||
icon_dead = "terror_allblack_dead"
|
||||
maxHealth = 400 // 20 laser shots.
|
||||
health = 400
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 25
|
||||
move_to_delay = 5
|
||||
ventcrawler = 1
|
||||
loot = list(/obj/item/clothing/accessory/medal)
|
||||
spider_tier = TS_TIER_3
|
||||
spider_opens_doors = 2
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince/spider_specialattack(mob/living/carbon/human/L)
|
||||
if(prob(15))
|
||||
visible_message("<span class='danger'>[src] rams into [L], knocking them to the floor!</span>")
|
||||
L.Weaken(5)
|
||||
L.Stun(5)
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T1 RED TERROR --------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: generic attack spider
|
||||
// -------------: AI: uses very powerful fangs to wreck people in melee
|
||||
// -------------: SPECIAL: the more you hurt it, the harder it bites you
|
||||
// -------------: TO FIGHT IT: shoot it from range. Kite it.
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/red
|
||||
name = "Red Terror spider"
|
||||
desc = "An ominous-looking red spider, it has eight beady red eyes, and nasty, big, pointy fangs! It looks like it has a vicious streak a mile wide."
|
||||
|
||||
spider_role_summary = "High health, high damage, very slow, melee juggernaut"
|
||||
|
||||
icon_state = "terror_red"
|
||||
icon_living = "terror_red"
|
||||
icon_dead = "terror_red_dead"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
move_to_delay = 20
|
||||
spider_opens_doors = 2
|
||||
var/enrage = 0
|
||||
var/melee_damage_lower_rage0 = 15
|
||||
var/melee_damage_upper_rage0 = 20
|
||||
var/melee_damage_lower_rage1 = 15
|
||||
var/melee_damage_upper_rage1 = 35
|
||||
var/melee_damage_lower_rage2 = 35
|
||||
var/melee_damage_upper_rage2 = 40
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/red/AttackingTarget()
|
||||
if(enrage == 0)
|
||||
if(health < maxHealth)
|
||||
enrage = 1
|
||||
visible_message("<span class='danger'>[src] growls, flexing its fangs!</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage1
|
||||
melee_damage_upper = melee_damage_upper_rage1
|
||||
else if(enrage == 1)
|
||||
if(health == maxHealth)
|
||||
enrage = 0
|
||||
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage0
|
||||
melee_damage_upper = melee_damage_upper_rage0
|
||||
else if(health < (maxHealth/2))
|
||||
enrage = 2
|
||||
visible_message("<span class='danger'>[src] growls, spreading its fangs wide!</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage2
|
||||
melee_damage_upper = melee_damage_upper_rage2
|
||||
else if(enrage == 2)
|
||||
if(health > (maxHealth/2))
|
||||
enrage = 1
|
||||
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage0
|
||||
melee_damage_upper = melee_damage_upper_rage0
|
||||
..()
|
||||
@@ -0,0 +1,329 @@
|
||||
|
||||
var/global/list/ts_ckey_blacklist = list()
|
||||
var/global/ts_count_dead = 0
|
||||
var/global/ts_count_alive_awaymission = 0
|
||||
var/global/ts_count_alive_station = 0
|
||||
var/global/ts_death_last = 0
|
||||
var/global/ts_death_window = 9000 // 15 minutes
|
||||
var/global/list/ts_spiderlist = list()
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: DEFAULTS ---------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// Because: http://tvtropes.org/pmwiki/pmwiki.php/Main/SpidersAreScary
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider
|
||||
// Name / Description
|
||||
name = "terror spider"
|
||||
desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug."
|
||||
|
||||
// Icons
|
||||
icon = 'icons/mob/terrorspider.dmi'
|
||||
icon_state = "terror_red"
|
||||
icon_living = "terror_red"
|
||||
icon_dead = "terror_red_dead"
|
||||
|
||||
// Health
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
// Melee attacks
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
poison_type = "" // we do not use that silly system.
|
||||
|
||||
// Movement
|
||||
move_to_delay = 6
|
||||
turns_per_move = 5
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
// Ventcrawling
|
||||
ventcrawler = 1 // allows player ventcrawling
|
||||
|
||||
// Speech
|
||||
speak_chance = 0 // quiet but deadly
|
||||
speak_emote = list("hisses")
|
||||
emote_hear = list("hisses")
|
||||
|
||||
// Languages are handled in terror_spider/New()
|
||||
|
||||
// Interaction keywords
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
|
||||
// regeneration settings - overridable by child classes
|
||||
var/regen_points = 0 // number of regen points they have by default
|
||||
var/regen_points_max = 100 // max number of points they can accumulate
|
||||
var/regen_points_per_tick = 1 // gain one regen point per tick
|
||||
var/regen_points_per_kill = 90 // gain extra regen points if you kill something
|
||||
var/regen_points_per_hp = 3 // every X regen points = 1 health point you can regen
|
||||
// desired: 20hp/minute unmolested, 40hp/min on food boost, assuming one tick every 2 seconds
|
||||
// 90/kill means bonus 30hp/kill regenerated over the next 1-2 minutes
|
||||
|
||||
// Vision
|
||||
idle_vision_range = 10
|
||||
aggro_vision_range = 10
|
||||
see_in_dark = 10
|
||||
nightvision = 1
|
||||
vision_type = new /datum/vision_override/nightvision/thermals/ling_augmented_eyesight
|
||||
see_invisible = 5
|
||||
|
||||
// player control by ghosts
|
||||
var/ai_playercontrol_allowingeneral = 1 // if 0, no spiders are player controllable. Default set in code, can be changed by queens.
|
||||
var/ai_playercontrol_allowtype = 1 // if 0, this specific class of spider is not player-controllable. Default set in code for each class, cannot be changed.
|
||||
|
||||
var/spider_opens_doors = 1 // all spiders can open firedoors (they have no security). 1 = can open depowered doors. 2 = can open powered doors
|
||||
faction = list("terrorspiders")
|
||||
var/spider_awaymission = 0 // if 1, limits certain behavior in away missions
|
||||
var/spider_role_summary = "UNDEFINED"
|
||||
var/spider_placed = 0
|
||||
|
||||
// AI variables designed for use in procs
|
||||
var/atom/cocoon_target // for queen and nurse
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/entry_vent // nearby vent they are going to try to get to, and enter
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/exit_vent // remote vent they intend to come out of
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/nest_vent // home vent, usually used by queens
|
||||
var/fed = 0
|
||||
var/travelling_in_vent = 0
|
||||
var/busy = 0 // leave this alone!
|
||||
var/spider_tier = TS_TIER_1 // 1 for red,gray,green. 2 for purple,black,white, 3 for prince, mother. 4 for queen, 5 for empress.
|
||||
var/hasdied = 0
|
||||
var/attackstep = 0
|
||||
var/attackcycles = 0
|
||||
var/mylocation = null
|
||||
var/chasecycles = 0
|
||||
var/last_cocoon_object = 0 // leave this, changed by procs.
|
||||
var/killcount = 0
|
||||
|
||||
// Breathing, Pressure & Fire
|
||||
// - No breathing / cannot be suffocated (spiders can hold their breath, look it up)
|
||||
// - No pressure damage either - they have effectively exoskeletons
|
||||
// - HOWEVER they can be burned to death!
|
||||
// - Normal SPACE spiders should probably be immune to SPACE too, but meh, we try to leave the base spiders alone.
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
heat_damage_per_tick = 5 //amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
|
||||
// DEBUG OPTIONS & COMMANDS
|
||||
var/spider_debug = 0
|
||||
|
||||
var/datum/action/innate/terrorspider/web/web_action
|
||||
var/datum/action/innate/terrorspider/wrap/wrap_action
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: SHARED ATTACK CODE -----------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget()
|
||||
if(istype(target, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = target
|
||||
if(T.spider_tier > spider_tier)
|
||||
visible_message("<span class='notice'>[src] bows in respect for the terrifying presence of [target].</span>")
|
||||
else if(T.spider_tier == spider_tier)
|
||||
visible_message("<span class='notice'>[src] nuzzles [target].</span>")
|
||||
else if(T.spider_tier < spider_tier && spider_tier >= 4)
|
||||
visible_message("<span class='notice'>[src] gives [target] a stern look.</span>")
|
||||
else
|
||||
visible_message("<span class='notice'>[src] harmlessly nuzzles [target].</span>")
|
||||
T.CheckFaction()
|
||||
CheckFaction()
|
||||
else if(istype(target, /obj/effect/spider/cocoon))
|
||||
to_chat(src, "Destroying our own cocoons would not help us.")
|
||||
else if(istype(target, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = target
|
||||
if(F.density)
|
||||
if(F.blocked)
|
||||
to_chat(src, "The fire door is welded shut.")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] pries open the firedoor!</span>")
|
||||
F.open()
|
||||
else
|
||||
to_chat(src, "Closing fire doors does not help.")
|
||||
else if(istype(target, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = target
|
||||
if(A.density)
|
||||
try_open_airlock(A)
|
||||
else if(isliving(target))
|
||||
var/mob/living/G = target
|
||||
if(issilicon(G))
|
||||
G.attack_animal(src)
|
||||
return
|
||||
else if(G.reagents && (iscarbon(G)))
|
||||
var/can_poison = 1
|
||||
if(ishuman(G))
|
||||
var/mob/living/carbon/human/H = G
|
||||
if(!(H.species.reagent_tag & PROCESS_ORG) || (H.species.flags & NO_POISON))
|
||||
can_poison = 0
|
||||
spider_specialattack(G,can_poison)
|
||||
else
|
||||
G.attack_animal(src)
|
||||
else
|
||||
target.attack_animal(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, var/poisonable)
|
||||
L.attack_animal(src)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: PROC OVERRIDES ---------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user)
|
||||
..()
|
||||
var/list/msgs = list()
|
||||
if(stat == DEAD)
|
||||
msgs += "<span class='notice'>It appears to be dead.</span>\n"
|
||||
else
|
||||
if(key)
|
||||
msgs += "<span class='warning'>Its eyes regard you with a curious intelligence.</span>"
|
||||
if(health > (maxHealth*0.95))
|
||||
msgs += "<span class='notice'>It is in excellent health.</span>"
|
||||
else if(health > (maxHealth*0.75))
|
||||
msgs += "<span class='notice'>It has a few injuries.</span>"
|
||||
else if(health > (maxHealth*0.55))
|
||||
msgs += "<span class='warning'>It has many injuries.</span>"
|
||||
else if(health > (maxHealth*0.25))
|
||||
msgs += "<span class='warning'>It is barely clinging on to life!</span>"
|
||||
else if(health < maxHealth && regen_points > regen_points_per_kill)
|
||||
msgs += "<span class='notice'>It appears to be regenerating quickly.</span>"
|
||||
if(killcount >= 1)
|
||||
msgs += "<span class='warning'>It has blood dribbling from its mouth.</span>"
|
||||
to_chat(usr,msgs.Join("<BR>"))
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/New()
|
||||
..()
|
||||
ts_spiderlist += src
|
||||
add_language("Spider Hivemind")
|
||||
add_language("Galactic Common")
|
||||
default_language = all_languages["Spider Hivemind"]
|
||||
|
||||
web_action = new()
|
||||
web_action.Grant(src)
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
|
||||
name += " ([rand(1, 1000)])"
|
||||
msg_terrorspiders("[src] has grown in [get_area(src)].")
|
||||
if(is_away_level(z))
|
||||
spider_awaymission = 1
|
||||
ts_count_alive_awaymission++
|
||||
else
|
||||
ts_count_alive_station++
|
||||
// after 30 seconds, assuming nobody took control of it yet, offer it to ghosts.
|
||||
addtimer(src, "CheckFaction", 150)
|
||||
addtimer(src, "announcetoghosts", 300)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts()
|
||||
if(spider_awaymission)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(ckey)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay)
|
||||
else if(ai_playercontrol_allowingeneral && ai_playercontrol_allowtype)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "<a href=?src=[UID()];activate=1>(Click to control)</a>", source = src, alert_overlay = alert_overlay, attack_not_jump = 1)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Destroy()
|
||||
ts_spiderlist -= src
|
||||
handle_dying()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Life()
|
||||
..()
|
||||
if(stat == DEAD)
|
||||
if(prob(2))
|
||||
// 2% chance every cycle to decompose
|
||||
visible_message("<span class='notice'>\The dead body of the [src] decomposes!</span>")
|
||||
gib()
|
||||
else
|
||||
if(regen_points < regen_points_max)
|
||||
regen_points += regen_points_per_tick
|
||||
if((bruteloss > 0) || (fireloss > 0))
|
||||
if(regen_points > regen_points_per_hp)
|
||||
if(bruteloss > 0)
|
||||
adjustBruteLoss(-1)
|
||||
regen_points -= regen_points_per_hp
|
||||
else if(fireloss > 0)
|
||||
adjustFireLoss(-1)
|
||||
regen_points -= regen_points_per_hp
|
||||
if(prob(5))
|
||||
CheckFaction()
|
||||
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/handle_dying()
|
||||
if(!hasdied)
|
||||
hasdied = 1
|
||||
ts_count_dead++
|
||||
ts_death_last = world.time
|
||||
if(spider_awaymission)
|
||||
ts_count_alive_awaymission--
|
||||
else
|
||||
ts_count_alive_station--
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/death(gibbed)
|
||||
if(!gibbed)
|
||||
msg_terrorspiders("[src] has died in [get_area(src)].")
|
||||
handle_dying()
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_special_action()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Bump(atom/A)
|
||||
if(istype(A, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/L = A
|
||||
if(L.density)
|
||||
try_open_airlock(L)
|
||||
if(istype(A, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = A
|
||||
if(F.density && !F.blocked)
|
||||
F.open()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext)
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in ts_spiderlist)
|
||||
if(T.stat != DEAD)
|
||||
to_chat(T, "<span class='terrorspider'>TerrorSense: [msgtext]</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction()
|
||||
if(faction.len != 1 || (!("terrorspiders" in faction)) || master_commander != null)
|
||||
visible_message("<span class='danger'>[src] writhes in pain!</span>")
|
||||
log_runtime(EXCEPTION("Terror spider created with incorrect faction list at: [atom_loc_line(src)]"))
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D)
|
||||
if(D.operating)
|
||||
return
|
||||
if(!D.density)
|
||||
to_chat(src, "<span class='warning'>Closing doors does not help us.</span>")
|
||||
else if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded shut.</span>")
|
||||
else if(D.locked)
|
||||
to_chat(src, "<span class='warning'>The door is bolted shut.</span>")
|
||||
else if(D.allowed(src))
|
||||
D.open(1)
|
||||
else if(D.arePowerSystemsOn() && (spider_opens_doors != 2))
|
||||
to_chat(src, "<span class='warning'>The door's motors resist your efforts to force it.</span>")
|
||||
else if(!spider_opens_doors)
|
||||
to_chat(src, "<span class='warning'>Your type of spider is not strong enough to force open doors.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] pries open the door!</span>")
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
D.open(1)
|
||||
@@ -244,8 +244,10 @@
|
||||
if(!job.is_position_available()) return 0
|
||||
if(jobban_isbanned(src,rank)) return 0
|
||||
if(!is_job_whitelisted(src, rank)) return 0
|
||||
if(!job.player_old_enough(src.client)) return 0
|
||||
if(!job.player_old_enough(client)) return 0
|
||||
if(job.admin_only && !(check_rights(R_EVENT, 0))) return 0
|
||||
if(job.available_in_playtime(client))
|
||||
return 0
|
||||
|
||||
if(config.assistantlimit)
|
||||
if(job.title == "Civilian")
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/alarm_monitor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/categories[0]
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
ui.set_auto_update(1)
|
||||
ui_ref = ui
|
||||
|
||||
/datum/nano_module/atmos_control/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/atmos_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["alarms"] = air_alarm_repository.air_alarm_data(monitored_alarms)
|
||||
return data
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
// should make the UI auto-update; doesn't seem to?
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/crew_monitor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/crew_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
var/turf/T = get_turf(nano_host())
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/appearance_changer/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/appearance_changer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
generate_data(check_whitelist, whitelist, blacklist)
|
||||
var/data[0]
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/law_manager/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/law_manager/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
owner.lawsync()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/power_monitor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/power_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["powermonitor"] = powermonitor
|
||||
|
||||
@@ -44,11 +44,12 @@
|
||||
* The ui_data proc is used to get data for the interface
|
||||
*
|
||||
* @param user /mob The mob who is viewing this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param state /datum/topic_state Current topic state of the UI
|
||||
*
|
||||
* @return list()
|
||||
*/
|
||||
/datum/proc/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/proc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
return list()
|
||||
|
||||
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
ui = get_open_ui(user, src_object, ui_key)
|
||||
|
||||
if(!isnull(ui))
|
||||
var/data = src_object.ui_data(user, ui.state) // Get data from src_object.
|
||||
var/data = src_object.ui_data(user, ui_key, ui.state) // Get data from src_object.
|
||||
if(!force_open)
|
||||
ui.push_data(data)
|
||||
else
|
||||
|
||||
@@ -415,7 +415,7 @@ nanoui is used to open and update nano browser uis
|
||||
return
|
||||
|
||||
if(!initial_data)
|
||||
set_initial_data(src_object.ui_data(user, state)) // Get the UI data.
|
||||
set_initial_data(src_object.ui_data(user, ui_key, state)) // Get the UI data.
|
||||
|
||||
user << browse(get_html(), "window=[window_id];[window_size][window_options]")
|
||||
winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
|
||||
|
||||
@@ -62,7 +62,7 @@ var/list/alldepartments = list()
|
||||
ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/photocopier/faxmachine/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
if(scan)
|
||||
@@ -109,16 +109,18 @@ var/list/alldepartments = list()
|
||||
|
||||
if(href_list["paper"])
|
||||
if(copyitem)
|
||||
copyitem.loc = usr.loc
|
||||
usr.put_in_hands(copyitem)
|
||||
to_chat(usr, "<span class='notice'>You take \the [copyitem] out of \the [src].</span>")
|
||||
copyitem.forceMove(get_turf(src))
|
||||
if(ishuman(usr))
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(copyitem)
|
||||
to_chat(usr, "<span class='notice'>You eject \the [copyitem] from \the [src].</span>")
|
||||
copyitem = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/photo) || istype(I, /obj/item/weapon/paper_bundle))
|
||||
usr.drop_item()
|
||||
copyitem = I
|
||||
I.loc = src
|
||||
I.forceMove(src)
|
||||
to_chat(usr, "<span class='notice'>You insert \the [I] into \the [src].</span>")
|
||||
flick(insert_anim, src)
|
||||
|
||||
@@ -163,24 +165,24 @@ var/list/alldepartments = list()
|
||||
/obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/weapon/card/id/card = null)
|
||||
if(scan) // Card is in machine
|
||||
if(ishuman(usr))
|
||||
scan.loc = usr.loc
|
||||
scan.forceMove(get_turf(usr))
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
else
|
||||
scan.loc = src.loc
|
||||
scan.forceMove(get_turf(src))
|
||||
scan = null
|
||||
else
|
||||
if(!card)
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/weapon/card/id))
|
||||
usr.drop_item()
|
||||
I.loc = src
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
else
|
||||
if(istype(card))
|
||||
usr.drop_item()
|
||||
card.loc = src
|
||||
card.forceMove(src)
|
||||
scan = card
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
|
||||
@@ -79,8 +79,10 @@
|
||||
updateUsrDialog()
|
||||
else if(href_list["remove"])
|
||||
if(copyitem)
|
||||
copyitem.loc = usr.loc
|
||||
usr.put_in_hands(copyitem)
|
||||
copyitem.forceMove(get_turf(src))
|
||||
if(ishuman(usr))
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(copyitem)
|
||||
to_chat(usr, "<span class='notice'>You take \the [copyitem] out of \the [src].</span>")
|
||||
copyitem = null
|
||||
updateUsrDialog()
|
||||
@@ -125,7 +127,7 @@
|
||||
if(!copyitem)
|
||||
user.drop_item()
|
||||
copyitem = O
|
||||
O.loc = src
|
||||
O.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You insert \the [O] into \the [src].</span>")
|
||||
flick(insert_anim, src)
|
||||
updateUsrDialog()
|
||||
@@ -150,10 +152,10 @@
|
||||
if(ismob(G.affecting) && G.affecting != ass)
|
||||
var/mob/GM = G.affecting
|
||||
visible_message("<span class='warning'>[usr] drags [GM.name] onto the photocopier!</span>")
|
||||
GM.loc = get_turf(src)
|
||||
GM.forceMove(get_turf(src))
|
||||
ass = GM
|
||||
if(copyitem)
|
||||
copyitem.loc = src.loc
|
||||
copyitem.forceMove(get_turf(src))
|
||||
copyitem = null
|
||||
updateUsrDialog()
|
||||
return
|
||||
@@ -290,10 +292,10 @@
|
||||
W = copy(W)
|
||||
else if(istype(W, /obj/item/weapon/photo))
|
||||
W = photocopy(W)
|
||||
W.loc = p
|
||||
W.forceMove(p)
|
||||
p.amount++
|
||||
p.amount--
|
||||
p.loc = src.loc
|
||||
p.forceMove(get_turf(src))
|
||||
p.update_icon()
|
||||
p.icon_state = "paper_words"
|
||||
p.name = bundle.name
|
||||
@@ -313,10 +315,10 @@
|
||||
if(target.anchored) return
|
||||
if(!ishuman(user)) return
|
||||
visible_message("<span class='warning'>[usr] drags [target.name] onto the photocopier!</span>")
|
||||
target.loc = get_turf(src)
|
||||
target.forceMove(get_turf(src))
|
||||
ass = target
|
||||
if(copyitem)
|
||||
copyitem.loc = src.loc
|
||||
copyitem.forceMove(get_turf(src))
|
||||
visible_message("<span class='notice'>[copyitem] is shoved out of the way by [ass]!</span>")
|
||||
copyitem = null
|
||||
updateUsrDialog()
|
||||
|
||||
+13
-1
@@ -129,7 +129,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(auto_update)
|
||||
|
||||
/obj/item/device/pda/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/device/pda/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
|
||||
data["owner"] = owner // Who is your daddy...
|
||||
@@ -427,6 +427,9 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
user.drop_item()
|
||||
C.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You slide \the [C] into \the [src].</span>")
|
||||
else if(istype(C, /obj/item/weapon/nanomob_card))
|
||||
if(cartridge && istype(cartridge, /obj/item/weapon/cartridge/mob_hunt_game))
|
||||
cartridge.attackby(C, user, params)
|
||||
|
||||
/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob)
|
||||
if(istype(C, /mob/living/carbon) && scanmode)
|
||||
@@ -498,3 +501,12 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
else
|
||||
close(usr)
|
||||
return 0
|
||||
|
||||
/obj/item/device/pda/process()
|
||||
if(current_app)
|
||||
current_app.program_process()
|
||||
|
||||
/obj/item/device/pda/hit_check(speed)
|
||||
if(current_app)
|
||||
current_app.program_hit_check()
|
||||
..()
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
// Base class for anything that can show up on home screen
|
||||
/datum/data/pda
|
||||
var/icon = "tasks"
|
||||
var/icon = "tasks" //options comes from http://fontawesome.io/icons/
|
||||
var/notify_icon = "exclamation-circle"
|
||||
var/notify_silent = 0
|
||||
var/hidden = 0 // program not displayed in main menu
|
||||
@@ -12,6 +12,16 @@
|
||||
return ..()
|
||||
|
||||
/datum/data/pda/proc/start()
|
||||
return
|
||||
|
||||
/datum/data/pda/proc/stop()
|
||||
return
|
||||
|
||||
/datum/data/pda/proc/program_process()
|
||||
return
|
||||
|
||||
/datum/data/pda/proc/program_hit_check()
|
||||
return
|
||||
|
||||
/datum/data/pda/proc/notify(message, blink = 1)
|
||||
if(message)
|
||||
@@ -56,6 +66,8 @@
|
||||
title = name
|
||||
|
||||
/datum/data/pda/app/start()
|
||||
if(pda.current_app)
|
||||
pda.current_app.stop()
|
||||
pda.current_app = src
|
||||
return 1
|
||||
|
||||
|
||||
+41
-24
@@ -22,7 +22,7 @@
|
||||
if(radio)
|
||||
radio.initialize()
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/weapon/cartridge/Destroy()
|
||||
if(radio)
|
||||
qdel(radio)
|
||||
@@ -53,8 +53,7 @@
|
||||
/obj/item/weapon/cartridge/atmos
|
||||
name = "BreatheDeep Cartridge"
|
||||
icon_state = "cart-a"
|
||||
programs = list(
|
||||
new/datum/data/pda/utility/scanmode/gas)
|
||||
programs = list(new/datum/data/pda/utility/scanmode/gas)
|
||||
|
||||
/obj/item/weapon/cartridge/medical
|
||||
name = "Med-U Cartridge"
|
||||
@@ -66,8 +65,7 @@
|
||||
/obj/item/weapon/cartridge/chemistry
|
||||
name = "ChemWhiz Cartridge"
|
||||
icon_state = "cart-chem"
|
||||
programs = list(
|
||||
new/datum/data/pda/utility/scanmode/reagent)
|
||||
programs = list(new/datum/data/pda/utility/scanmode/reagent)
|
||||
|
||||
/obj/item/weapon/cartridge/security
|
||||
name = "R.O.B.U.S.T. Cartridge"
|
||||
@@ -94,30 +92,25 @@
|
||||
name = "CustodiPRO Cartridge"
|
||||
desc = "The ultimate in clean-room design."
|
||||
icon_state = "cart-j"
|
||||
programs = list(
|
||||
new/datum/data/pda/app/janitor)
|
||||
programs = list(new/datum/data/pda/app/janitor)
|
||||
|
||||
/obj/item/weapon/cartridge/lawyer
|
||||
name = "P.R.O.V.E. Cartridge"
|
||||
icon_state = "cart-s"
|
||||
programs = list(
|
||||
new/datum/data/pda/app/crew_records/security)
|
||||
programs = list(new/datum/data/pda/app/crew_records/security)
|
||||
|
||||
/obj/item/weapon/cartridge/clown
|
||||
name = "Honkworks 5.0"
|
||||
icon_state = "cart-clown"
|
||||
charges = 5
|
||||
programs = list(
|
||||
new/datum/data/pda/utility/honk)
|
||||
messenger_plugins = list(
|
||||
new/datum/data/pda/messenger_plugin/virus/clown)
|
||||
programs = list(new/datum/data/pda/utility/honk)
|
||||
messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/clown)
|
||||
|
||||
/obj/item/weapon/cartridge/mime
|
||||
name = "Gestur-O 1000"
|
||||
icon_state = "cart-mi"
|
||||
charges = 5
|
||||
messenger_plugins = list(
|
||||
new/datum/data/pda/messenger_plugin/virus/mime)
|
||||
messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/mime)
|
||||
|
||||
/*
|
||||
/obj/item/weapon/cartridge/botanist
|
||||
@@ -129,8 +122,7 @@
|
||||
/obj/item/weapon/cartridge/signal
|
||||
name = "generic signaler cartridge"
|
||||
desc = "A data cartridge with an integrated radio signaler module."
|
||||
programs = list(
|
||||
new/datum/data/pda/app/signaller)
|
||||
programs = list(new/datum/data/pda/app/signaller)
|
||||
|
||||
/obj/item/weapon/cartridge/signal/initialize()
|
||||
radio = new /obj/item/radio/integrated/signal(src)
|
||||
@@ -162,8 +154,7 @@
|
||||
/obj/item/weapon/cartridge/head
|
||||
name = "Easy-Record DELUXE"
|
||||
icon_state = "cart-h"
|
||||
programs = list(
|
||||
new/datum/data/pda/app/status_display)
|
||||
programs = list(new/datum/data/pda/app/status_display)
|
||||
|
||||
/obj/item/weapon/cartridge/hop
|
||||
name = "HumanResources9001"
|
||||
@@ -303,12 +294,38 @@
|
||||
icon_state = "cart"
|
||||
var/initial_remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
|
||||
charges = 4
|
||||
programs = list(
|
||||
new/datum/data/pda/utility/toggle_door)
|
||||
messenger_plugins = list(
|
||||
new/datum/data/pda/messenger_plugin/virus/detonate)
|
||||
programs = list(new/datum/data/pda/utility/toggle_door)
|
||||
messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/detonate)
|
||||
|
||||
/obj/item/weapon/cartridge/syndicate/New()
|
||||
var/datum/data/pda/utility/toggle_door/D = programs[1]
|
||||
if(istype(D))
|
||||
D.remote_door_id = initial_remote_door_id
|
||||
D.remote_door_id = initial_remote_door_id
|
||||
|
||||
/obj/item/weapon/cartridge/mob_hunt_game
|
||||
name = "Nano-Mob Hunter GO! Cartridge"
|
||||
desc = "The hit new PDA game that lets you track down and capture your favorite Nano-Mobs living in your world!"
|
||||
icon_state = "cart-eye"
|
||||
programs = list(new/datum/data/pda/app/mob_hunter_game)
|
||||
var/emagged = 0
|
||||
|
||||
/obj/item/weapon/cartridge/mob_hunt_game/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/weapon/nanomob_card))
|
||||
var/obj/item/weapon/nanomob_card/card = O
|
||||
var/datum/data/pda/app/mob_hunter_game/my_game = programs[1]
|
||||
if(my_game.register_capture(card.mob_data))
|
||||
to_chat(user, "<span class='notice'>Transfer successful!</span>")
|
||||
qdel(card)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Transfer failed. Could not read mob data from card.</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/cartridge/mob_hunt_game/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
emagged = 1
|
||||
var/datum/data/pda/app/mob_hunter_game/my_game = programs[1]
|
||||
my_game.hacked = 1
|
||||
to_chat(user, "<span class='warning'>TR4P_M45T3R.mod successfully initialized. ToS violated. User Agreement nullified. Gotta pwn them all.</span>")
|
||||
to_chat(user, "<span class='warning'>You can now create trapped versions of any mob in your collection that will damage hunters who attempt to capture it.</span>")
|
||||
description_antag = "This copy of Nano-Mob Hunter GO! has been hacked to allow the creation of trap mobs which will cause any PDA that attempts to capture it to shock anyone holding it. Hacked copies of the game will not trigger the trap."
|
||||
@@ -0,0 +1,182 @@
|
||||
|
||||
/*
|
||||
This stuff isn't included with in core_apps.dm because it is so distinct and would end up making the file huge (more than it already is).
|
||||
I put it in it's own file in order to help it stay organized and easier to locate the procs and such.
|
||||
For reference, the other Nano-mob Hunter GO files are in /code/game/modules/arcade/mob_hunt
|
||||
*/
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game
|
||||
name = "Nano-Mob Hunter GO"
|
||||
icon = "gamepad"
|
||||
template = "pda_mob_hunt"
|
||||
category = "Games"
|
||||
|
||||
var/list/my_collection = list()
|
||||
var/current_index = 0
|
||||
var/connected = 0
|
||||
var/hacked = 0 //if set, this cartridge is able to spawn trap mobs from its collection (set via emag_act on the cartridge)
|
||||
var/catch_mod = 0 //used to adjust the likelihood of a mob running from this client, a negative value means it is less likely to run (support for temporary bonuses)
|
||||
var/wild_captures = 0 //used to track the total number of mobs captured from the wild (does not count card mobs) by this client
|
||||
var/scan_range = 3 //maximum distance (in tiles) from which the client can reveal nearby mobs
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/start()
|
||||
..()
|
||||
processing_objects.Add(pda)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/stop()
|
||||
..()
|
||||
disconnect("Program Terminated")
|
||||
processing_objects.Remove(pda)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/scan_nearby()
|
||||
if(!mob_hunt_server || !connected)
|
||||
return
|
||||
for(var/turf/T in range(scan_range, get_turf(pda)))
|
||||
for(var/obj/effect/nanomob/N in T.contents)
|
||||
if(src in N.clients_encountered)
|
||||
//hide the mob
|
||||
N.conceal()
|
||||
else
|
||||
//reveal the mob
|
||||
N.reveal()
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/reconnect()
|
||||
if(!mob_hunt_server || !mob_hunt_server.server_status || connected)
|
||||
//show a message about the server being unavailable (because it doesn't exist / didn't get set to the global var / is offline)
|
||||
return 0
|
||||
mob_hunt_server.connected_clients += src
|
||||
connected = 1
|
||||
if(pda)
|
||||
pda.audible_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!", null, 2)
|
||||
return 1
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/get_player()
|
||||
if(!pda)
|
||||
return null
|
||||
if(ishuman(pda.loc))
|
||||
var/mob/living/carbon/human/H = pda.loc
|
||||
return H
|
||||
return null
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/disconnect(reason = null)
|
||||
if(!mob_hunt_server || !connected)
|
||||
return
|
||||
mob_hunt_server.connected_clients -= src
|
||||
for(var/obj/effect/nanomob/N in (mob_hunt_server.normal_spawns + mob_hunt_server.trap_spawns))
|
||||
N.conceal(list(get_player()))
|
||||
connected = 0
|
||||
//show a disconnect message if we were disconnected involuntarily (reason argument provided)
|
||||
if(pda && reason)
|
||||
pda.audible_message("[bicon(pda)] Disconnected from server. Reason: [reason].", null, 2)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/program_process()
|
||||
if(!mob_hunt_server || !connected)
|
||||
return
|
||||
scan_nearby()
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/program_hit_check()
|
||||
if(!pda)
|
||||
return
|
||||
for(var/obj/effect/nanomob/hit_mob in get_turf(pda))
|
||||
hit_mob.hitby(pda)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/register_capture(datum/mob_hunt/captured, wild = 0)
|
||||
if(!captured)
|
||||
return 0
|
||||
my_collection.Add(captured)
|
||||
if(wild)
|
||||
wild_captures++
|
||||
return 1
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/update_ui(mob/user, list/data)
|
||||
if(!mob_hunt_server || !(src in mob_hunt_server.connected_clients))
|
||||
data["connected"] = 0
|
||||
else
|
||||
data["connected"] = 1
|
||||
data["wild_captures"] = wild_captures
|
||||
data["no_collection"] = 0
|
||||
if(!my_collection.len)
|
||||
data["no_collection"] = 1
|
||||
return
|
||||
var/datum/mob_hunt/mob_info
|
||||
if(!current_index)
|
||||
current_index = 1
|
||||
if(current_index > my_collection.len)
|
||||
current_index = 1
|
||||
if(current_index < 1)
|
||||
current_index = my_collection.len
|
||||
mob_info = my_collection[current_index]
|
||||
var/list/entry = list(
|
||||
"nickname" = mob_info.nickname,
|
||||
"real_name" = mob_info.mob_name,
|
||||
"level" = mob_info.level,
|
||||
"type1" = mob_info.get_type1(),
|
||||
"type2" = mob_info.get_type2(),
|
||||
"sprite" = "[mob_info.icon_state_normal].png",
|
||||
"is_hacked" = hacked
|
||||
)
|
||||
if(mob_info.is_shiny)
|
||||
entry["sprite"] = "[mob_info.icon_state_shiny].png"
|
||||
data["entry"] = entry
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/assign_nickname()
|
||||
if(!my_collection.len)
|
||||
return
|
||||
var/datum/mob_hunt/mob_info = my_collection[current_index]
|
||||
var/old_name = mob_info.mob_name
|
||||
if(mob_info.nickname)
|
||||
old_name = mob_info.nickname
|
||||
mob_info.nickname = input("Give a nickname to [old_name]?", "Nickname", old_name)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/release()
|
||||
if(!my_collection.len)
|
||||
return
|
||||
if(alert("Are you sure you want to release this mob back into the wild?", "Confirm Release", "Yes", "No") == "Yes")
|
||||
remove_mob()
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/print_card()
|
||||
if(!pda || !my_collection.len)
|
||||
return
|
||||
var/obj/item/weapon/nanomob_card/card = new/obj/item/weapon/nanomob_card(null)
|
||||
var/datum/mob_hunt/mob_info = my_collection[current_index]
|
||||
card.mob_data = mob_info
|
||||
card.update_info()
|
||||
card.forceMove(get_turf(pda))
|
||||
remove_mob()
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/remove_mob()
|
||||
if(!my_collection.len)
|
||||
return
|
||||
my_collection.Remove(my_collection[current_index])
|
||||
if(current_index > my_collection.len)
|
||||
current_index = my_collection.len
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/set_trap()
|
||||
if(!my_collection.len || !pda || !hacked)
|
||||
return
|
||||
var/datum/mob_hunt/bait = my_collection[current_index]
|
||||
bait = bait.type
|
||||
new bait(1, get_turf(pda))
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/Topic(href, list/href_list)
|
||||
switch(href_list["choice"])
|
||||
if("Rename")
|
||||
assign_nickname()
|
||||
if("Release")
|
||||
release()
|
||||
if("Next")
|
||||
current_index++
|
||||
if(current_index > my_collection.len)
|
||||
current_index = 1
|
||||
if("Prev")
|
||||
current_index--
|
||||
if(current_index < 1)
|
||||
current_index = my_collection.len
|
||||
if("Reconnect")
|
||||
reconnect()
|
||||
if("Disconnect")
|
||||
disconnect()
|
||||
if("Transfer")
|
||||
print_card()
|
||||
if("Set_Trap")
|
||||
set_trap()
|
||||
@@ -787,7 +787,7 @@
|
||||
// Auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/apc/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/power/apc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["locked"] = is_locked(user)
|
||||
data["isOperating"] = operating
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/power/port_gen/pacman/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["active"] = active
|
||||
|
||||
@@ -95,10 +95,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if(src.anchored)
|
||||
if(anchored)
|
||||
to_chat(usr, "It is fastened to the floor!")
|
||||
return 0
|
||||
src.dir = turn(src.dir, 270)
|
||||
dir = turn(dir, 270)
|
||||
return 1
|
||||
|
||||
/obj/structure/particle_accelerator/AltClick(mob/user)
|
||||
@@ -116,29 +116,29 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if(src.anchored)
|
||||
if(anchored)
|
||||
to_chat(usr, "It is fastened to the floor!")
|
||||
return 0
|
||||
src.dir = turn(src.dir, 90)
|
||||
dir = turn(dir, 90)
|
||||
return 1
|
||||
|
||||
/obj/structure/particle_accelerator/examine(mob/user)
|
||||
switch(src.construction_state)
|
||||
switch(construction_state)
|
||||
if(0)
|
||||
src.desc = text("A [name], looks like it's not attached to the flooring")
|
||||
desc = text("A [name], looks like it's not attached to the flooring")
|
||||
if(1)
|
||||
src.desc = text("A [name], it is missing some cables")
|
||||
desc = text("A [name], it is missing some cables")
|
||||
if(2)
|
||||
src.desc = text("A [name], the panel is open")
|
||||
desc = text("A [name], the panel is open")
|
||||
if(3)
|
||||
src.desc = text("The [name] is assembled")
|
||||
desc = text("The [name] is assembled")
|
||||
if(powered)
|
||||
src.desc = src.desc_holder
|
||||
desc = desc_holder
|
||||
..(user)
|
||||
|
||||
/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user, params)
|
||||
if(istool(W))
|
||||
if(src.process_tool_hit(W,user))
|
||||
if(process_tool_hit(W,user))
|
||||
return
|
||||
..()
|
||||
return
|
||||
@@ -208,7 +208,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
/obj/structure/particle_accelerator/proc/connect_master(var/obj/O)
|
||||
if(O && istype(O,/obj/machinery/particle_accelerator/control_box))
|
||||
if(O.dir == src.dir)
|
||||
if(O.dir == dir)
|
||||
master = O
|
||||
return 1
|
||||
return 0
|
||||
@@ -219,51 +219,51 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
return 0
|
||||
if(!ismob(user) || !isobj(O))
|
||||
return 0
|
||||
var/temp_state = src.construction_state
|
||||
var/temp_state = construction_state
|
||||
|
||||
switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
|
||||
switch(construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
|
||||
if(0)
|
||||
if(iswrench(O) && !isinspace())
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
src.anchored = 1
|
||||
user.visible_message("[user.name] secures the [src.name] to the floor.", \
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
user.visible_message("[user.name] secures the [name] to the floor.", \
|
||||
"You secure the external bolts.")
|
||||
temp_state++
|
||||
if(1)
|
||||
if(iswrench(O))
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
src.anchored = 0
|
||||
user.visible_message("[user.name] detaches the [src.name] from the floor.", \
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
user.visible_message("[user.name] detaches the [name] from the floor.", \
|
||||
"You remove the external bolts.")
|
||||
temp_state--
|
||||
else if(iscoil(O))
|
||||
var/obj/item/stack/cable_coil/C = O
|
||||
if(C.use(1))
|
||||
user.visible_message("[user.name] adds wires to the [src.name].", \
|
||||
user.visible_message("[user.name] adds wires to the [name].", \
|
||||
"You add some wires.")
|
||||
temp_state++
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need one length of cable to wire the [src.name]!</span>")
|
||||
to_chat(user, "<span class='warning'>You need one length of cable to wire the [name]!</span>")
|
||||
return
|
||||
if(2)
|
||||
if(iswirecutter(O))//TODO:Shock user if its on?
|
||||
user.visible_message("[user.name] removes some wires from the [src.name].", \
|
||||
user.visible_message("[user.name] removes some wires from the [name].", \
|
||||
"You remove some wires.")
|
||||
temp_state--
|
||||
else if(isscrewdriver(O))
|
||||
user.visible_message("[user.name] closes the [src.name]'s access panel.", \
|
||||
user.visible_message("[user.name] closes the [name]'s access panel.", \
|
||||
"You close the access panel.")
|
||||
temp_state++
|
||||
if(3)
|
||||
if(isscrewdriver(O))
|
||||
user.visible_message("[user.name] opens the [src.name]'s access panel.", \
|
||||
user.visible_message("[user.name] opens the [name]'s access panel.", \
|
||||
"You open the access panel.")
|
||||
temp_state--
|
||||
if(temp_state == src.construction_state)//Nothing changed
|
||||
if(temp_state == construction_state)//Nothing changed
|
||||
return 0
|
||||
else
|
||||
src.construction_state = temp_state
|
||||
if(src.construction_state < 3)//Was taken apart, update state
|
||||
construction_state = temp_state
|
||||
if(construction_state < 3)//Was taken apart, update state
|
||||
update_state()
|
||||
update_icon()
|
||||
return 1
|
||||
@@ -296,10 +296,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if(src.anchored)
|
||||
if(anchored)
|
||||
to_chat(usr, "It is fastened to the floor!")
|
||||
return 0
|
||||
src.dir = turn(src.dir, 270)
|
||||
dir = turn(dir, 270)
|
||||
return 1
|
||||
|
||||
/obj/machinery/particle_accelerator/verb/rotateccw()
|
||||
@@ -309,10 +309,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if(src.anchored)
|
||||
if(anchored)
|
||||
to_chat(usr, "It is fastened to the floor!")
|
||||
return 0
|
||||
src.dir = turn(src.dir, 90)
|
||||
dir = turn(dir, 90)
|
||||
return 1
|
||||
|
||||
/obj/machinery/particle_accelerator/update_icon()
|
||||
@@ -320,7 +320,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
/obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user, params)
|
||||
if(istool(W))
|
||||
if(src.process_tool_hit(W,user))
|
||||
if(process_tool_hit(W,user))
|
||||
return
|
||||
..()
|
||||
return
|
||||
@@ -357,51 +357,53 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
return 0
|
||||
if(!ismob(user) || !isobj(O))
|
||||
return 0
|
||||
var/temp_state = src.construction_state
|
||||
switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
|
||||
var/temp_state = construction_state
|
||||
switch(construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
|
||||
if(0)
|
||||
if(iswrench(O))
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
src.anchored = 1
|
||||
user.visible_message("[user.name] secures the [src.name] to the floor.", \
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
user.visible_message("[user.name] secures the [name] to the floor.", \
|
||||
"You secure the external bolts.")
|
||||
temp_state++
|
||||
power_change()
|
||||
if(1)
|
||||
if(iswrench(O))
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
src.anchored = 0
|
||||
user.visible_message("[user.name] detaches the [src.name] from the floor.", \
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
user.visible_message("[user.name] detaches the [name] from the floor.", \
|
||||
"You remove the external bolts.")
|
||||
temp_state--
|
||||
power_change()
|
||||
else if(iscoil(O))
|
||||
if(O:use(1))
|
||||
user.visible_message("[user.name] adds wires to the [src.name].", \
|
||||
user.visible_message("[user.name] adds wires to the [name].", \
|
||||
"You add some wires.")
|
||||
temp_state++
|
||||
if(2)
|
||||
if(iswirecutter(O))//TODO:Shock user if its on?
|
||||
user.visible_message("[user.name] removes some wires from the [src.name].", \
|
||||
user.visible_message("[user.name] removes some wires from the [name].", \
|
||||
"You remove some wires.")
|
||||
temp_state--
|
||||
else if(isscrewdriver(O))
|
||||
user.visible_message("[user.name] closes the [src.name]'s access panel.", \
|
||||
user.visible_message("[user.name] closes the [name]'s access panel.", \
|
||||
"You close the access panel.")
|
||||
temp_state++
|
||||
if(3)
|
||||
if(isscrewdriver(O))
|
||||
user.visible_message("[user.name] opens the [src.name]'s access panel.", \
|
||||
user.visible_message("[user.name] opens the [name]'s access panel.", \
|
||||
"You open the access panel.")
|
||||
temp_state--
|
||||
active = 0
|
||||
if(temp_state == src.construction_state)//Nothing changed
|
||||
if(temp_state == construction_state)//Nothing changed
|
||||
return 0
|
||||
else
|
||||
if(src.construction_state < 3)//Was taken apart, update state
|
||||
if(construction_state < 3)//Was taken apart, update state
|
||||
update_state()
|
||||
if(use_power)
|
||||
use_power = 0
|
||||
src.construction_state = temp_state
|
||||
if(src.construction_state >= 3)
|
||||
construction_state = temp_state
|
||||
if(construction_state >= 3)
|
||||
use_power = 1
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
/obj/machinery/particle_accelerator/control_box/New()
|
||||
wires = new(src)
|
||||
connected_parts = list()
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/Destroy()
|
||||
@@ -34,7 +35,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/attack_ghost(user as mob)
|
||||
return src.attack_hand(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/attack_hand(mob/user as mob)
|
||||
if(construction_state >= 3)
|
||||
@@ -62,9 +63,12 @@
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/update_icon()
|
||||
if(active)
|
||||
icon_state = "[reference]p1"
|
||||
icon_state = "[reference]p[strength]"
|
||||
else
|
||||
if(use_power)
|
||||
if(stat & NOPOWER)
|
||||
icon_state = "[reference]w"
|
||||
return
|
||||
else if(use_power)
|
||||
if(assembled)
|
||||
icon_state = "[reference]p"
|
||||
else
|
||||
@@ -89,16 +93,16 @@
|
||||
to_chat(usr, "<span class='error'>ERROR: Request timed out. Check wire contacts.</span>")
|
||||
return
|
||||
|
||||
if( href_list["close"] )
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=pacontrol")
|
||||
usr.unset_machine()
|
||||
return
|
||||
if(href_list["togglep"])
|
||||
if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE))
|
||||
src.toggle_power()
|
||||
toggle_power()
|
||||
|
||||
else if(href_list["scan"])
|
||||
src.part_scan()
|
||||
part_scan()
|
||||
|
||||
else if(href_list["strengthup"])
|
||||
if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
|
||||
@@ -108,8 +112,8 @@
|
||||
if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
|
||||
remove_strength()
|
||||
|
||||
src.updateDialog()
|
||||
src.update_icon()
|
||||
updateDialog()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
@@ -152,32 +156,39 @@
|
||||
use_power = 0
|
||||
else if(!stat && construction_state <= 3)
|
||||
use_power = 1
|
||||
update_icon()
|
||||
|
||||
if((stat & NOPOWER) || (!stat && construction_state <= 3)) //Only update the part icons if something's changed (i.e. any of the above condition sets are met).
|
||||
for(var/obj/structure/particle_accelerator/part in connected_parts)
|
||||
part.strength = null
|
||||
part.powered = 0
|
||||
part.update_icon()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/process()
|
||||
if(src.active)
|
||||
if(active)
|
||||
//a part is missing!
|
||||
if( length(connected_parts) < 6 )
|
||||
if(length(connected_parts) < 6)
|
||||
investigate_log("lost a connected part; It <font color='red'>powered down</font>.","singulo")
|
||||
src.toggle_power()
|
||||
toggle_power()
|
||||
return
|
||||
//emit some particles
|
||||
for(var/obj/structure/particle_accelerator/particle_emitter/PE in connected_parts)
|
||||
if(PE)
|
||||
PE.emit_particle(src.strength)
|
||||
PE.emit_particle(strength)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/part_scan()
|
||||
for(var/obj/structure/particle_accelerator/fuel_chamber/F in orange(1,src))
|
||||
src.dir = F.dir
|
||||
dir = F.dir
|
||||
connected_parts = list()
|
||||
var/tally = 0
|
||||
var/ldir = turn(dir,-90)
|
||||
var/rdir = turn(dir,90)
|
||||
var/odir = turn(dir,180)
|
||||
var/turf/T = src.loc
|
||||
var/turf/T = loc
|
||||
T = get_step(T,rdir)
|
||||
if(check_part(T,/obj/structure/particle_accelerator/fuel_chamber))
|
||||
tally++
|
||||
@@ -213,26 +224,26 @@
|
||||
if(istype(PA, type))
|
||||
if(PA.connect_master(src))
|
||||
if(PA.report_ready(src))
|
||||
src.connected_parts.Add(PA)
|
||||
connected_parts.Add(PA)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/toggle_power()
|
||||
src.active = !src.active
|
||||
active = !active
|
||||
investigate_log("turned [active?"<font color='red'>ON</font>":"<font color='green'>OFF</font>"] by [usr ? usr.key : "outside forces"]","singulo")
|
||||
if(active)
|
||||
msg_admin_attack("PA Control Computer turned ON by [key_name(usr, usr.client)](<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("PA Control Computer turned ON by [usr.ckey]([usr]) in ([x],[y],[z])")
|
||||
use_log += text("\[[time_stamp()]\] <font color='red'>[usr.name] ([usr.ckey]) has turned on the PA Control Computer.</font>")
|
||||
if(src.active)
|
||||
src.use_power = 2
|
||||
if(active)
|
||||
use_power = 2
|
||||
for(var/obj/structure/particle_accelerator/part in connected_parts)
|
||||
part.strength = src.strength
|
||||
part.strength = strength
|
||||
part.powered = 1
|
||||
part.update_icon()
|
||||
else
|
||||
src.use_power = 1
|
||||
use_power = 1
|
||||
for(var/obj/structure/particle_accelerator/part in connected_parts)
|
||||
part.strength = null
|
||||
part.powered = 0
|
||||
@@ -262,13 +273,13 @@
|
||||
else
|
||||
dat += "Off <BR>"
|
||||
dat += "<A href='?src=[UID()];togglep=1'>Toggle Power</A><BR><BR>"
|
||||
dat += "Particle Strength: [src.strength] "
|
||||
dat += "Particle Strength: [strength] "
|
||||
dat += "<A href='?src=[UID()];strengthdown=1'>--</A>|<A href='?src=[UID()];strengthup=1'>++</A><BR><BR>"
|
||||
|
||||
//user << browse(dat, "window=pacontrol;size=420x500")
|
||||
//onclose(user, "pacontrol")
|
||||
var/datum/browser/popup = new(user, "pacontrol", name, 420, 500)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
return
|
||||
@@ -375,7 +375,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/smes/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/power/smes/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["nameTag"] = name_tag
|
||||
|
||||
@@ -395,7 +395,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/solar_control/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/power/solar_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["generated"] = round(lastgen)
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/power/supermatter_shard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["integrity_percentage"] = round(get_integrity())
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_dispenser/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["amount"] = amount
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_heater/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["targetTemp"] = desired_temp
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
ui = new(user, src, ui_key, "chem_master.tmpl", name, 575, 400)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_master/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/chem_master/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["condi"] = condi
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/disposal/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/disposal/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/pressure = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
|
||||
|
||||
@@ -652,7 +652,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
|
||||
ui = new(user, src, ui_key, "r_n_d.tmpl", src.name, 800, 550)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/rdconsole/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/rdconsole/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
files.RefreshResearch()
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/radiocarbon_spectrometer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["scanned_item"] = (scanned_item ? scanned_item.name : "")
|
||||
data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "")
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 540, 320)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/keycard_auth/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/keycard_auth/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["screen"] = screen
|
||||
data["event"] = event
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
/atom/movable/lighting_overlay/onShuttleMove()
|
||||
return 0
|
||||
|
||||
/obj/onShuttleMove()
|
||||
if(invisibility >= 101)
|
||||
return 0
|
||||
. = ..()
|
||||
/obj/effect/landmark/shuttle_import/onShuttleMove()
|
||||
// Used for marking where to preview/load shuttles
|
||||
return 0
|
||||
|
||||
/obj/docking_port/onShuttleMove()
|
||||
// Stationary ports shouldn't move, mobile ones move themselves
|
||||
return 0
|
||||
|
||||
/obj/machinery/door/onShuttleMove()
|
||||
. = ..()
|
||||
|
||||
@@ -59,13 +59,12 @@
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/shuttle_manipulator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "shuttle_manipulator.tmpl", "Shuttle Manipulator", 660, 700)
|
||||
ui = new(user, src, ui_key, "shuttle_manipulator.tmpl", "Shuttle Manipulator", 660, 700, null, null, admin_state)
|
||||
// when the ui is first opened this is the data it will use
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
|
||||
@@ -430,7 +430,7 @@
|
||||
ui = new(user, src, ui_key, "order_console.tmpl", name, ORDER_SCREEN_WIDTH, ORDER_SCREEN_HEIGHT)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/ordercomp/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/ordercomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["last_viewed_group"] = last_viewed_group
|
||||
|
||||
@@ -579,7 +579,7 @@
|
||||
ui = new(user, src, ui_key, "supply_console.tmpl", name, SUPPLY_SCREEN_WIDTH, SUPPLY_SCREEN_HEIGHT)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/supplycomp/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/supplycomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["last_viewed_group"] = last_viewed_group
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
var/turf/T
|
||||
var/obj/item/pod_parts/pod_frame/linked
|
||||
var/obj/item/pod_parts/pod_frame/pointer
|
||||
var/connectedparts = list()
|
||||
var/list/connectedparts = list()
|
||||
neededparts -= src
|
||||
//log_admin("Starting with [src]")
|
||||
linked = src
|
||||
@@ -44,7 +44,8 @@
|
||||
connectedparts += pointer
|
||||
linked = pointer
|
||||
pointer = null
|
||||
//log_admin("Parts left: [neededparts.len]") //len not working
|
||||
if(connectedparts.len < 4)
|
||||
return 0
|
||||
for(var/i = 1; i <=4; i++)
|
||||
var/obj/item/pod_parts/pod_frame/F = connectedparts[i]
|
||||
if(F.type in neededparts) //if one of the items can be founded in neededparts
|
||||
@@ -122,4 +123,4 @@
|
||||
name = "civilian pod armor"
|
||||
icon = 'icons/goonstation/pods/pod_parts.dmi'
|
||||
icon_state = "pod_armor_civ"
|
||||
desc = "Spacepod armor. This is the civilian version. It looks rather flimsy."
|
||||
desc = "Spacepod armor. This is the civilian version. It looks rather flimsy."
|
||||
|
||||
@@ -57,6 +57,12 @@
|
||||
typepath = /obj/item/weapon/storage/box/dice
|
||||
cost = 200
|
||||
|
||||
/datum/storeitem/nanomob_booster
|
||||
name = "Nano-Mob Hunter Trading Card Booster Pack"
|
||||
desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!"
|
||||
typepath = /obj/item/weapon/storage/box/nanomob_booster_pack
|
||||
cost = 250
|
||||
|
||||
/datum/storeitem/crayons
|
||||
name = "Crayons"
|
||||
desc = "Let security know how they're doing by scrawling lovenotes all over their hallways."
|
||||
|
||||
Reference in New Issue
Block a user