////////////////////////////////////////////////////////////// // stupid rassumfrassum no good ////////////////////////////////////////////////////////////// /proc/uppertext_proxy(match) // FUCKIN' BYOND . = uppertext(match) ////////////////////////////////////////////////////////////// // PATHFINDING STUFF ////////////////////////////////////////////////////////////// /turf/proc/AllDirsTurfsCritter(var/obj/critter/C) var/L[] = new() // for(var/turf/simulated/t in oview(src,1)) var/CT = get_turf(C) for(var/d in alldirs) var/turf/simulated/T = get_step(src, d) //if(istype(T) && !T.density) if (T && T.pathable && !T.density) if(!LinkBlockedForCritters(CT, T, C)) L.Add(T) return L /proc/LinkBlockedForCritters(turf/A, turf/B, obj/critter/C) if(A == null || B == null) return 1 var/adir = get_dir(A,B) var/rdir = get_dir(B,A) if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal var/iStep = get_step(A,adir&(NORTH|SOUTH)) if(!LinkBlockedForCritters(A,iStep, C) && !LinkBlockedForCritters(iStep,B,C)) return 0 var/pStep = get_step(A,adir&(EAST|WEST)) if(!LinkBlockedForCritters(A,pStep,C) && !LinkBlockedForCritters(pStep,B,C)) return 0 return 1 if(DirBlockedForCritters(A,adir, C)) return 1 if(DirBlockedForCritters(B,rdir, C)) return 1 for (var/atom/O in B.contents) if (O.density && !(O.flags & ON_BORDER)) if (istype(O, /obj/machinery/door)) var/obj/machinery/door/D = O if (D.isblocked()) return 1 return 0 if (ismob(O)) var/mob/M = O if (M.anchored) return 1 return 0 return 1 return 0 // Returns true if direction is blocked from loc // If critters can open doors the direction is not considered blocked /proc/DirBlockedForCritters(turf/loc,var/dir,var/obj/critter/C) var/blocked = 0 for (var/obj/window/D in loc) if (D.density && D.dir == dir) blocked = 1 if (D.density && !(D.flags & ON_BORDER)) blocked = 1 for (var/obj/machinery/door/D in loc) if (D.isblocked()) blocked = 1 if (istype(D, /obj/machinery/door/window)) if (dir & D.dir) if (D.density && C.opensdoors == 0) blocked = 1 else if (D.density && C.opensdoors == 0) blocked = 1 return blocked ////////////////////////////////////////////////////////////// // Critter data extension (avoiding pollution of critter vars) ////////////////////////////////////////////////////////////// // TODO: name this fucker better var/global/datum/critterDataAccess/intruderCritterDefinitions = new() /datum/critterDataAccess var/list/critterExtraData New() ..() critterExtraData = src.getValues() proc/getValues() . = list() var/types = typesof(/datum/critterData) DEBUG_MESSAGE("[html_encode(list2params(types))]") for(var/T in types) var/datum/critterData/instance = new T() var/subtypes = typesof(instance.assocPath) DEBUG_MESSAGE("[html_encode(list2params(subtypes))]") for(var/ST in subtypes) .[ST] = instance DEBUG_MESSAGE("[ST] - [instance]") proc/getCritterData(critterType) if(critterType in critterExtraData) return critterExtraData[critterType] else return critterExtraData[/obj/critter] /datum/critterData var/portrait = "temp_portrait_generic" var/assocSound = "sound/machines/chime_1.ogg" var/assocPath = /obj/critter // more data to come /datum/critterData/roach portrait = "temp_portrait_roach" assocSound = "sound/intrusion/critter_roach.ogg" assocPath = /obj/critter/roach /datum/critterData/mouse portrait = "temp_portrait_mouse" //assocSound = "sound/intrusion/critter_mouse.ogg" assocPath = /obj/critter/mouse /datum/critterData/bee portrait = "temp_portrait_bee" assocSound = "sound/intrusion/critter_bee.ogg" assocPath = /obj/critter/domestic_bee /datum/critterData/wasp portrait = "temp_portrait_wasp" assocSound = "sound/intrusion/critter_bee.ogg" assocPath = /obj/critter/spacebee /datum/critterData/cat portrait = "temp_portrait_cat" assocSound = "sound/effects/cat.ogg" assocPath = /obj/critter/cat /datum/critterData/dog portrait = "temp_portrait_dog" assocSound = "sound/misc/dogbark.ogg" assocPath = /obj/critter/dog /datum/critterData/parrot portrait = "temp_portrait_bird" assocSound = "sound/intrusion/critter_parrot.ogg" assocPath = /obj/critter/parrot /datum/critterData/plasma_spore portrait = "temp_portrait_spore" assocSound = "sound/intrusion/critter_plasma_spore.ogg" assocPath = /obj/critter/spore /datum/critterData/spider portrait = "temp_portrait_spider" assocSound = "sound/intrusion/critter_spider.ogg" assocPath = /obj/critter/spider /datum/critterData/bumblespider portrait = "temp_portrait_bumblespider" assocSound = "sound/intrusion/critter_spider.ogg" assocPath = /obj/critter/nicespider /datum/critterData/owl portrait = "temp_portrait_owl" assocSound = "sound/misc/hoot.ogg" assocPath = /obj/critter/owl ////////////////////////////////////////////////////////////// // The actual mob itself!! ////////////////////////////////////////////////////////////// /mob/living/intangible/intruder name = "Eldritch Intruder" real_name = "Eldritch Intruder" desc = "Weird!" icon = 'icons/mob/intruder.dmi' icon_state = "intruder" layer = NOLIGHT_EFFECTS_LAYER_BASE density = 0 canmove = 1 blinded = 0 anchored = 1 mob_flags = SPEECH_INTRUDER var/color1 = rgb(100, 90, 165) var/color2 = rgb(100, 220, 175) var/image/baseImage var/image/accentImage var/datum/hud/intruder/hud var/obj/critter/selected var/image/selectedImage var/list/structures = list() var/obj/intrusionStructure/spire/spire = null // TODO: put this in a textfile var/list/nameParts = list("hand", "eye", "tendril", "claw", "extension", "protrusion", "maw", "will") var/list/nameAdjectives = list("clear", "clean", "crystalline", "cloudy", "thundering", "lightning", "born", "aged", "warped", "ethereal", "alien", "wild", "whispered", "fell", "starborne", "known", "coral", "nameless", "voiceless", "shimmering") var/list/nameConcepts = list("song", "stanza", "liturgy", "sonnet", "poem", "contemplation", "idea", "home", "hive", "colony", "pool", "voice", "name") var/list/nameVerb = list("scry", "delay", "wander", "sing", "watch", "dream", "know", "drift", "seek", "abandon") var/list/nameVerbs = list("scries", "delays", "wanders", "sings", "watches", "dreams", "knows", "drifts", "seeks", "abandons") var/list/nameVerbing = list("scrying", "delaying", "wandering", "singing", "watching", "dreaming", "knowing", "drifting", "seeking", "abandoning") var/list/nameTemplates = list("%ADJ%ADJ %CONCEPT of %VERBING", "%ADJ %ADJ%CONCEPT which %VERBS", "%ADJ %VERB to %ADJ%CONCEPT", "%ADJ%VERBING %ADJ%CONCEPT") proc/generateName() . = "" var/template = pick(nameTemplates) for(var/i=1, i<=length(template), i++) var/char = copytext(template,i,i+1) if(char == "%") if(copytext(template, i+1, i+4) == "ADJ") . += pick(nameAdjectives) i = i+3 continue if(copytext(template, i+1, i+8) == "CONCEPT") . += pick(nameConcepts) i = i+7 continue if(copytext(template, i+1, i+8) == "VERBING") . += pick(nameVerbing) i = i+7 continue if(copytext(template, i+1, i+6) == "VERBS") . += pick(nameVerbs) i = i+5 continue if(copytext(template, i+1, i+5) == "VERB") . += pick(nameVerb) i = i+4 continue else . += char //var/list/bag = nameConcepts.Copy() //var/words = rand(3,6) //for(var/i=0, i[src.real_name]" // forgive me for duplicating more code unnecessarily emote(var/act, var/voluntary = 0) var/message = "" var/m_type = 0 if (!message) switch (lowertext(act)) if ("dance") if (src.emote_check(voluntary, 50)) m_type = 1 message = "[src] waves around a bit, not really understanding dance or rhythm." animate_weird(src) if ("scream") if (src.emote_check(voluntary, 50)) m_type = 2 var/descriptor = pick("a weird", "a strange", "an unnatural", "a baffling", "a disconcerting", "a painful", "a twisting", "some weird", "an unsettling", "a distorted") message = "[src] makes [descriptor] noise!" playsound(get_turf(src), "sound/cirr/intruder_scream[rand(1,11)].ogg", 50, 1, 1) if ("flip") if (src.emote_check(voluntary, 50) && !src.shrunk) m_type = 1 message = "[src] does a flip!" if (prob(50)) animate_spin(src, "R", 1, 0) else animate_spin(src, "L", 1, 0) if (message) logTheThing("say", src, null, "EMOTE: [message]") if (m_type & 1) for (var/mob/O in viewers(src, null)) O.show_message(message, m_type) else if (m_type & 2) for (var/mob/O in hearers(src, null)) O.show_message(message, m_type) else if (!isturf(src.loc)) var/atom/A = src.loc for (var/mob/O in A.contents) O.show_message(message, m_type) click(atom/target, params) . = ..() if(params["left"]) if(istype(target, /obj/critter)) var/obj/critter/C = target selectCritter(C) else deselect() if(params["right"]) giveCommand(target, "moveTo") Move(NewLoc, direct) src.dir = get_dir(src, NewLoc) src.baseImage.dir = src.dir src.accentImage.dir = src.dir ..() proc/selectCritter(obj/critter/C, var/play_sound=1) var/datum/critterData/CD = intruderCritterDefinitions.getCritterData(C.type) //if(istype(src.selected)) // clean up existing image? src.selected = C src.selected.selected = 1 src.selectedImage.loc = src.selected.loc src.client.images += src.selectedImage hud.changePortrait(CD.portrait) if(play_sound) playsound_local(src, CD.assocSound, 60, 1, -1) if(src.selected.task == "following path") src.selectedImage.color = color2 proc/deselect() src.client.images -= src.selectedImage if(istype(src.selected)) src.selected.selected = 0 src.selected = null src.selectedImage.color = color1 hud.changePortrait("temp_portrait_entity") proc/giveCommand(var/atom/target, var/command="move") if(!src.selected) return // not sure how we got here, but better safe than sorry if(!src.spire) boutput(src, "Your presence is too weak to command anything, you must place a spire first.") return var/datum/critterData/CD = intruderCritterDefinitions.getCritterData(src.selected.type) switch(command) if ("moveTo") playsound_local(src, CD.assocSound, 60, 1, -1, 0.8) src.selected.followed_path = AStar(get_turf(src.selected), get_turf(target), /turf/proc/AllDirsTurfsCritter, /turf/proc/Distance, adjacent_param = src.selected) src.selected.followed_path_retry_target = target.loc src.selected.task = "following path" src.selectedImage.color = color2 visualisePath(src.client, src.selected.followed_path) proc/addAllAbilities() src.addAbility(/datum/targetable/intruderAbility/setColors) src.addAbility(/datum/targetable/intruderAbility/createStructure/spire) proc/addAbility(var/abilityType) abilityHolder.addAbility(abilityType) proc/removeAbility(var/abilityType) abilityHolder.removeAbility(abilityType) ghostize() deselect() src.client.show_popup_menus = 1 return ..() /mob/living/intangible/intruder/proc/build(var/structure_path, var/turf/T) if(src.can_build(structure_path, T)) var/obj/intrusionStructure/S = new structure_path(T) src.structures |= S S.post_construct(src) /mob/living/intangible/intruder/proc/can_build(var/structure_path, var/turf/T) // if structure isn't freestanding, do orthogonal check // TODO: othogonal check // if we already have too many, don't build var/count = 0 for (var/obj/intrusionStructure/I in structures) if(I.type == structure_path) count++ if(count >= initial(structure_path:max)) // if you can figure out how to typecast a type, let me know ok boutput(src, "You can't bring any more of these into this reality.") return 0 // check tile is clear if (T.density) boutput(src, "The [T] is too solid to forge through.") return 0 for (var/obj/O in T) if (O.density) boutput(src, "The [O] is too solid to forge through.") return 0 return 1 ////////////////////////////////////////////////////////////// // Intruder UI stuff ////////////////////////////////////////////////////////////// /datum/hud/intruder var/mob/living/intangible/intruder/master var/obj/screen/hud/portrait var/image/cloud1 var/image/cloud2 New(M) master = M createPortrait() proc/createPortrait() portrait = create_screen("portrait", "portrait", 'icons/ui/intruder_portrait_ui.dmi', "temp_portrait_entity", "WEST,SOUTH", HUD_LAYER+1, tooltipTheme = "wraith") portrait.underlays += image('icons/ui/intruder_portrait_ui.dmi', icon_state="backdrop", layer=FLOAT_LAYER - 3) cloud1 = image('icons/ui/intruder_portrait_ui.dmi', icon_state="cloud1", layer=FLOAT_LAYER - 2) cloud2 = image('icons/ui/intruder_portrait_ui.dmi', icon_state="cloud2", layer=FLOAT_LAYER - 1) portrait.overlays += image('icons/ui/intruder_portrait_ui.dmi', icon_state="frame", layer=FLOAT_LAYER ) portrait.name = "portrait" portrait.desc = "temp_portrait_entity" proc/updateColors(var/col1, var/col2) portrait.underlays -= cloud1 portrait.underlays -= cloud2 cloud1.color = col1 cloud2.color = col2 cloud1.blend_mode = BLEND_ADD cloud2.blend_mode = BLEND_MULTIPLY portrait.underlays += cloud1 portrait.underlays += cloud2 proc/changePortrait(var/portrait_name) portrait.icon_state = portrait_name portrait.desc = portrait_name clicked(id, mob/user, list/params) boutput("id: [id] - params: [url_decode(list2params(params))]") //if(id == "portrait") //boutput(url_decode(list2params(params))) ////////////////////////////////////////////////////////////// // Intruder abilities! ////////////////////////////////////////////////////////////// /datum/abilityHolder/intruder topBarRendered = 1 /obj/screen/ability/topBar/intruder tens_offset_x = 19 tens_offset_y = 7 secs_offset_x = 23 secs_offset_y = 7 /datum/targetable/intruderAbility icon = 'icons/mob/wraith_ui.dmi' icon_state = "template" cooldown = 0 last_cast = 0 targeted = 1 target_anything = 1 preferred_holder_type = /datum/abilityHolder/intruder New() var/obj/screen/ability/topBar/intruder/B = new /obj/screen/ability/topBar/intruder(null) B.icon = src.icon B.icon_state = src.icon_state B.owner = src B.name = src.name B.desc = src.desc src.object = B cast(atom/target) if (!holder || !holder.owner) return 1 return 0 doCooldown() if (!holder) return last_cast = world.time + cooldown holder.updateButtons() SPAWN_DBG(cooldown + 5) holder.updateButtons() /datum/targetable/intruderAbility/setColors name = "Set Color" desc = "Choose the color your cosmic presence radiates. This will be removed once you place your Spire." targeted = 0 cast(atom/target) if(..()) return 1 //var/color1 = input("Select your Base Color", "Base") as color //var/color2 = input("Select your Accent Color", "Accent") as color var/color = input("Select your Color", "Color") as color var/mob/living/intangible/intruder/I = holder.owner I.updateColors(color, complementarycolor(color)) /datum/targetable/intruderAbility/createStructure name = "Forge Structure" desc = "You shouldn't see this. Please flag a coder." targeted = 1 var/structure = /obj/intrusionStructure cast(atom/target) if(..()) return 1 var/turf/T = get_turf(target) var/mob/living/intangible/intruder/I = holder.owner if(structure) I.build(structure, T) /datum/targetable/intruderAbility/createStructure/spire name = "Emerge Spire" desc = "Manifest the anchor of your presence in this reality." structure = /obj/intrusionStructure/spire ////////////////////////////////////////////////////////////// // Intruder structures ////////////////////////////////////////////////////////////// // Base //////////////////////////////////////////////////// /obj/intrusionStructure name = "fire cirr into the sun" desc = "no seriously fire him into the sun you shouldn't see this" icon = 'icons/obj/intruder_structures.dmi' var/freestanding = 0 // does this structure need to be aligned with a previous one? var/max = -1 // if this is -1, there's no max, otherwise there is a max, and 0 means can't build /obj/intrusionStructure/proc/post_construct(var/mob/living/intangible/intruder/builder) // Spire /////////////////////////////////////////////////// /obj/intrusionStructure/spire name = "Spire" desc = "The anchor of your material presence." icon_state = "spire" freestanding = 1 // we kind of need to be able to place the spire anywhere max = 1 /obj/intrusionStructure/spire/post_construct(var/mob/living/intangible/intruder/builder) // no more colour changes for you, you've begun builder.removeAbility(/datum/targetable/intruderAbility/setColors) builder.spire = src ////////////////////////////////////////////////////////////// // Transform procs ////////////////////////////////////////////////////////////// // GUESS WHO STOLE THIS FROM WRAITH // IT'S ME CIRR /mob/proc/intruderize() if (src.mind || src.client) message_admins("[key_name(usr)] made [key_name(src)] an intruder.") logTheThing("admin", usr, src, "made %target% an intruder.") return make_intruder() return null /mob/proc/make_intruder() if (src.mind || src.client) var/mob/living/intangible/intruder/O = new/mob/living/intangible/intruder(src) var/turf/T = get_turf(src) if (!(T && isturf(T)) || ((isrestrictedz(T.z) || T.z != 1) && !(src.client && src.client.holder))) var/OS = observer_start.len ? pick(observer_start) : locate(1, 1, 1) if (OS) O.set_loc(OS) else O.z = 1 else O.set_loc(T) if (src.mind) src.mind.transfer_to(O) else var/key = src.client.key if (src.client) src.client.mob = O O.mind = new /datum/mind() O.mind.key = key O.mind.current = O ticker.minds += O.mind src.loc = null var/this = src src = null qdel(this) //W.addAllAbilities() boutput(O, "You are an intruder! Click critters to select them and right click to move them!") //boutput(W, "Your astral powers enable you to survive one banishment. Beware of salt.") //boutput(W, "Use the question mark button in the lower right corner to get help on your abilities.") return O return null ////////////////////////////////////////////////////////////// // misc helper procs ////////////////////////////////////////////////////////////// /proc/complementarycolor(var/color) var/r = hex2num(copytext(color, 2, 4)) var/g = hex2num(copytext(color, 4, 6)) var/b = hex2num(copytext(color, 6)) DEBUG_MESSAGE("rgb: [r] [g] [b]") var/list/hsv = rgb2hsv(r, g, b) DEBUG_MESSAGE("hsv: [hsv[1]] [hsv[2]] [hsv[3]]") hsv[1] += 180 // rotate the hue by 180 i think if(hsv[1] > 360) hsv[1] -= 360 DEBUG_MESSAGE("comp hsv: [hsv[1]] [hsv[2]] [hsv[3]]") var/list/rgb = hsv2rgblist(hsv[1], hsv[2], hsv[3]) DEBUG_MESSAGE("comp rgb: [rgb[1]] [rgb[2]] [rgb[3]]") . = rgb(rgb[1], rgb[2], rgb[3]) ////////////////////////////////////////////////////////////// // Path visualisation stuff ////////////////////////////////////////////////////////////// /client/var/list/Visualised_Path /client/var/list/Pathing_Images /proc/visualisePath(var/client/C, var/list/path) if(!path) boutput("No path to show.") C.Visualised_Path = path C.images -= C.Pathing_Images C.Pathing_Images = list() SPAWN_DBG(0) if(path) for(var/i = 2, i < path.len, i++) if(!C.Visualised_Path) break var/turf/prev = path[i-1] var/turf/t = path[i] var/turf/next = path[i+1] var/image/img = image('icons/obj/power_cond.dmi') img.loc = t img.layer = 101 img.color = "#5555ff" var/D1=turn(angle2dir(get_angle(next, t)),180) var/D2=turn(angle2dir(get_angle(prev,t)),180) if(D1>D2) D1=D2 D2=turn(angle2dir(get_angle(next, t)),180) img.icon_state = "[D1]-[D2]" C.images += img C.Pathing_Images[++C.Pathing_Images.len] = img img.alpha=0 var/matrix/xf = matrix() img.transform = xf/2 animate(img,alpha=255,transform=xf,time=2) sleep(1)