From d248f32207f6af7526c32cc09c7e714e20497c4e Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Wed, 4 Dec 2024 17:43:02 +1100 Subject: [PATCH 01/90] Adding Doe's crafted backpacks. --- code/datums/outfits/equipment/backpacks.dm | 8 ++++++++ .../objects/items/weapons/storage/backpack.dm | 17 +++++++++++++++++ .../crafting/stack_recipes/recipes_textiles.dm | 11 +++++++++++ .../storage/backpack/backpack_crafted.dmi | Bin 0 -> 901 bytes .../storage/backpack/backpack_haversack.dmi | Bin 0 -> 844 bytes maps/shaded_hills/shaded_hills_define.dm | 12 +++++++----- 6 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 icons/obj/items/storage/backpack/backpack_crafted.dmi create mode 100644 icons/obj/items/storage/backpack/backpack_haversack.dmi diff --git a/code/datums/outfits/equipment/backpacks.dm b/code/datums/outfits/equipment/backpacks.dm index 13b7df63e46c..2a4aed715eab 100644 --- a/code/datums/outfits/equipment/backpacks.dm +++ b/code/datums/outfits/equipment/backpacks.dm @@ -43,6 +43,14 @@ name = "Sack" path = /obj/item/bag/sack +/decl/backpack_outfit/haversack + name = "Haversack" + path = /obj/item/backpack/crafted + +/decl/backpack_outfit/backpack/crafted + name = "Handmade Backpack" + path = /obj/item/backpack/crafted/backpack + /* Code */ /decl/backpack_outfit var/flags diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 6b9c600b9594..1bc1144dc870 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -445,3 +445,20 @@ name = "security messenger bag" desc = "A tactical backpack worn over one shoulder. This one is in Security colors." icon = 'icons/obj/items/storage/backpack/messenger_sec.dmi' + +// Crafted backpacks. +/obj/item/backpack/crafted + name = "haversack" + desc = "A rather rough handmade haversack." + icon = 'icons/obj/items/storage/backpack/backpack_haversack.dmi' + material = /decl/material/solid/organic/leather + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + +/obj/item/backpack/crafted/backpack + name = "backpack" + desc = "A rather rough handmade backpack." + icon = 'icons/obj/items/storage/backpack/backpack_crafted.dmi' + +/obj/item/backpack/crafted/backpack/update_name() + . = ..() + SetName("handmade [name]") diff --git a/code/modules/crafting/stack_recipes/recipes_textiles.dm b/code/modules/crafting/stack_recipes/recipes_textiles.dm index ee608b17555b..7fdbd1b56aff 100644 --- a/code/modules/crafting/stack_recipes/recipes_textiles.dm +++ b/code/modules/crafting/stack_recipes/recipes_textiles.dm @@ -60,6 +60,17 @@ crafting_extra_cost_factor = 1.1 // less material is lost because it's relatively simple difficulty = MAT_VALUE_NORMAL_DIY // Slightly easier than making clothing. +/decl/stack_recipe/textiles/leather/sack + result_type = /obj/item/bag/sack + difficulty = MAT_VALUE_HARD_DIY + +/decl/stack_recipe/textiles/leather/backpack + result_type = /obj/item/backpack/crafted/backpack + difficulty = MAT_VALUE_VERY_HARD_DIY + +/decl/stack_recipe/textiles/leather/backpack/haversack + result_type = /obj/item/backpack/crafted + /decl/stack_recipe/textiles/leather/waterskin result_type = /obj/item/chems/waterskin/crafted required_material = /decl/material/solid/organic/leather diff --git a/icons/obj/items/storage/backpack/backpack_crafted.dmi b/icons/obj/items/storage/backpack/backpack_crafted.dmi new file mode 100644 index 0000000000000000000000000000000000000000..e565e4862a1bceac42c1741494324f05a464eeea GIT binary patch literal 901 zcmV;01A6?4P)D@x2wg|OkOGD>q3^YSxO6q52&Ds_u<@=M~A z5|gtL`b>z{mlL0nn3qD1&LX@zl@(n5T);s90COHt%wU^Zr~m*0e@R3^RA_EMenM@{=`KJlfzlr}-)t)d7xOu=v2gW)4Ckd)o>d@{ z?z{r3SHd*lYUqv-t0H4w0o6W(CbWCmk0*&fQ%+t1)msXn-CJ!@1fZawhXV}SJ(mJS z01BLkgG?rq`N_~&Bl-^P@;l9d*eAbYpW)hlS^}=!CmGz^eOd;t-6t8`+kKjWYxije b|2KaCLi$`=a6(Yk00000NkvXXu0mjfW=){1 literal 0 HcmV?d00001 diff --git a/icons/obj/items/storage/backpack/backpack_haversack.dmi b/icons/obj/items/storage/backpack/backpack_haversack.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ca148f6a4eac4bdaae099b0ea1d8c63e11db1738 GIT binary patch literal 844 zcmV-S1GD^zP)D@x2wg|OkOGD>q3^YSxO6q52&Ds_u<@=M~A z5|gtL`b>z{mlL0nn3qD1&LX@zl@(n5T);s90COHt%wU^Zr~m*0MoC0LRA_ zAP|N5IkS(D?8VZ3fb;_-()-bl@Bb=eCQ%B-c4pXR_*O`j;$yN0y zdIVb(p!IO~_32;^Jj_r-H*`ogUkriPSLX{bcOoRrFhx-aB#H$BA9HYXUZ8a6#UprQ zwf#WzvK#`_MPa<&;y_p!m*Wt=1d_Zcz(HGIUyk$1gZQ`#{T;6Y4euwk=?5QfzLxJC z16Lf|YP$fdySopc+Hx6}m;P=A*#@ljH!;+Hp{%uf)r+7N{?@A1XTwBQeJ5ZaR;1mZ z$z(F`h0!X(qKumt5hlT+JfJWnNg$+iWm*C5Qpb?GxiFck;G<7eaOn~YthfEYgI2+% zF6q;&aY1A(U!7yUUXKKLu8J}yW35o0kFrh{UJxCZeC_pfa&J==bJ;*-1F8jO7Cx8&^Oz-NveK!zZ5p+11{ugEh=@4=?-C(y7?Dk25p#e{K->=m z-Ps&uGMUUf!&8s;)!uLL9<=$HR$z1lX$3|{kf;Enr!0TY=m^pZjE*3&z=k9EPxuAK WLqd%9JxMG80000 Date: Wed, 4 Dec 2024 19:31:43 +1100 Subject: [PATCH 02/90] Added a large square woven basket. --- .../extensions/storage/subtypes_basket.dm | 3 +++ .../objects/items/weapons/storage/basket.dm | 17 ++++++++++++++--- .../obj/items/storage/baskets/basket_large.dmi | Bin 0 -> 1156 bytes .../{basket.dmi => baskets/basket_round.dmi} | Bin 940 -> 940 bytes 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 icons/obj/items/storage/baskets/basket_large.dmi rename icons/obj/items/storage/{basket.dmi => baskets/basket_round.dmi} (93%) diff --git a/code/datums/extensions/storage/subtypes_basket.dm b/code/datums/extensions/storage/subtypes_basket.dm index 26b00fd25da4..e5601ca91158 100644 --- a/code/datums/extensions/storage/subtypes_basket.dm +++ b/code/datums/extensions/storage/subtypes_basket.dm @@ -3,3 +3,6 @@ use_sound = 'sound/effects/storage/box.ogg' max_w_class = ITEM_SIZE_LARGE max_storage_space = DEFAULT_BOX_STORAGE + +/datum/storage/basket/large + max_storage_space = DEFAULT_BACKPACK_STORAGE diff --git a/code/game/objects/items/weapons/storage/basket.dm b/code/game/objects/items/weapons/storage/basket.dm index d7eada187651..65d8c1a3ec69 100644 --- a/code/game/objects/items/weapons/storage/basket.dm +++ b/code/game/objects/items/weapons/storage/basket.dm @@ -1,10 +1,21 @@ /obj/item/basket - name = "woven basket" + name = "basket" desc = "A simple woven basket. Very rustic." - icon = 'icons/obj/items/storage/basket.dmi' + icon = 'icons/obj/items/storage/baskets/basket_round.dmi' icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_HUGE - slot_flags = SLOT_BACK material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC storage = /datum/storage/basket material = /decl/material/solid/organic/plantmatter/grass/dry + var/name_prefix = "woven" + +/obj/item/basket/update_name() + . = ..() + SetName("[name_prefix] [name]") + +/obj/item/basket/large + slot_flags = SLOT_BACK + icon = 'icons/obj/items/storage/baskets/basket_large.dmi' + name_prefix = "large woven" + storage = /datum/storage/basket/large + slowdown_general = 1 // Large and unwieldly diff --git a/icons/obj/items/storage/baskets/basket_large.dmi b/icons/obj/items/storage/baskets/basket_large.dmi new file mode 100644 index 0000000000000000000000000000000000000000..af9d0140ca7e4391ace607f2666842ae4817a899 GIT binary patch literal 1156 zcmV-~1bh35P)005u_0{{R3dEt5<0000LP)t-sz`(#| zVs?s(p2ES&|Ns9K5nZm&E79XC&q!=`zm#6x;WVF~6KlE3 z52f!a){1S{+4Jc+v6clM$`nLeQL0y1hp8yI;Kgmu#aeMvudoh-s5mdJ7167Lbs(au zrj~{2sGxKp1uv#2?zAF$Rj>|Ze?EWj6T`>7uGh@}oNs@o`ACQ1rS&3_NF);ZcWf8s za;kQAkd0T;@nE#n&TgS4AnAB8YMdP;<4`dm>3A?|oE@aDpj8n-((z!_I6JGu0$P;< zNID*j8fOQw-5E4%bUYZPot^E@pjo5i!6@zQYZYkXa(ass>9mMjJtm|OIj9PW${{sAE+E|;?Qo0Go{{{HT z@jIc!l5T?We<6Ny7_1P=nHm2V;wJ+z{x3SgNF)-8{BqXp4<;dQZO#5*65=O;y(^#X z4@z%gf8o#E@BbOFceMYrM)z-)ci6u<;R4t@+W*1PG`GIkmC^~f_6JG-2S)?^>FX`TSKJnwy*_Dla81+!|jAuX> z2~KBy;yXI0xT%++uMS41!%j^JNy~%{#AA47r(T8uK0yV)p?{Vg%9`ANq=}XCV-gPJ zO=~Lj)hXHFf@QMxp1D->sb8)8`e2qQZ*F)aYIG54?K>|hyPtk_!F$u1f*F0fDQ$?| z9p405eJ~4@HzgIcS?JI~c4)flYjXE*+pIVVCp$EE;T0V+c;b_BdJSKE&MOj${D3df W^V(n5M!k6e0000DHg!Mz{0`F|NsArik@X+c1cHEoa$Scu|I7CFn`4gUZD From 48f02aa8ef1d324a0afa9f07eeda6b4519c2af5f Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Wed, 4 Dec 2024 19:42:21 +1100 Subject: [PATCH 03/90] Generalised the name_prefix system. --- code/game/objects/items/__item.dm | 3 ++ code/game/objects/items/_item_materials.dm | 9 +++-- .../objects/items/blades/spear_improvised.dm | 5 +-- .../objects/items/weapons/storage/basket.dm | 34 ++++++++++-------- .../objects/items/weapons/tools/wrench.dm | 5 +-- .../stool_bed_chair_nest_sofa/stools.dm | 13 +++---- .../crafting/stack_recipes/recipes_grass.dm | 3 ++ code/modules/detectivework/tools/rag.dm | 8 ++--- .../reagents/reagent_containers/beaker.dm | 5 +-- .../items/storage/baskets/basket_large.dmi | Bin 1156 -> 943 bytes .../items/storage/baskets/basket_round.dmi | Bin 940 -> 776 bytes 11 files changed, 43 insertions(+), 42 deletions(-) diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm index 69b1449b4193..562b26a9d0cb 100644 --- a/code/game/objects/items/__item.dm +++ b/code/game/objects/items/__item.dm @@ -6,6 +6,9 @@ abstract_type = /obj/item temperature_sensitive = TRUE + /// Set to prefix name with this string ('woven' for 'woven basket' etc) + var/name_prefix + /// Set to false to skip state checking and never draw an icon on the mob (except when held) var/draw_on_mob_when_equipped = TRUE diff --git a/code/game/objects/items/_item_materials.dm b/code/game/objects/items/_item_materials.dm index 95bc6402777c..7aaf5d6bb267 100644 --- a/code/game/objects/items/_item_materials.dm +++ b/code/game/objects/items/_item_materials.dm @@ -104,10 +104,13 @@ queue_icon_update() /obj/item/proc/update_name() + var/list/new_name = list(base_name || initial(name)) if(material_alteration & MAT_FLAG_ALTERATION_NAME) - SetName("[material.adjective_name] [base_name || initial(name)]") - else - SetName(base_name || initial(name)) + new_name.Insert(1, material.adjective_name) + if(name_prefix) + new_name.Insert(1, name_prefix) + if(length(new_name)) + SetName(jointext(new_name, " ")) /obj/item/get_matter_amount_modifier() . = ..() diff --git a/code/game/objects/items/blades/spear_improvised.dm b/code/game/objects/items/blades/spear_improvised.dm index e2dba3cc5987..b6295462833b 100644 --- a/code/game/objects/items/blades/spear_improvised.dm +++ b/code/game/objects/items/blades/spear_improvised.dm @@ -1,4 +1,5 @@ /obj/item/bladed/polearm/spear/improvised + name_prefix = "improvised" material = /decl/material/solid/glass hilt_material = /decl/material/solid/metal/steel guard_material = /decl/material/solid/metal/copper @@ -11,10 +12,6 @@ force_binding_color = pick(global.cable_colors) . = ..(ml, material_key, _hilt_mat, _guard_mat) -/obj/item/bladed/polearm/spear/improvised/update_name() - . = ..() - SetName("improvised [name]") - /obj/item/bladed/polearm/spear/improvised/get_guard_color() return force_binding_color || ..() diff --git a/code/game/objects/items/weapons/storage/basket.dm b/code/game/objects/items/weapons/storage/basket.dm index 65d8c1a3ec69..8c7661451a91 100644 --- a/code/game/objects/items/weapons/storage/basket.dm +++ b/code/game/objects/items/weapons/storage/basket.dm @@ -1,21 +1,25 @@ /obj/item/basket - name = "basket" - desc = "A simple woven basket. Very rustic." - icon = 'icons/obj/items/storage/baskets/basket_round.dmi' - icon_state = ICON_STATE_WORLD - w_class = ITEM_SIZE_HUGE + name_prefix = "woven" + name = "handbasket" + desc = "A simple woven basket. Very rustic." + icon = 'icons/obj/items/storage/baskets/basket_round.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_HUGE material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC - storage = /datum/storage/basket - material = /decl/material/solid/organic/plantmatter/grass/dry - var/name_prefix = "woven" + storage = /datum/storage/basket + material = /decl/material/solid/organic/plantmatter/grass/dry -/obj/item/basket/update_name() +/obj/item/basket/on_update_icon() . = ..() - SetName("[name_prefix] [name]") + icon_state = get_world_inventory_state() + if(storage?.opened) + icon_state = "[icon_state]-open" /obj/item/basket/large - slot_flags = SLOT_BACK - icon = 'icons/obj/items/storage/baskets/basket_large.dmi' - name_prefix = "large woven" - storage = /datum/storage/basket/large - slowdown_general = 1 // Large and unwieldly + name_prefix = "large woven" + name = "basket" + slot_flags = SLOT_BACK + icon = 'icons/obj/items/storage/baskets/basket_large.dmi' + w_class = ITEM_SIZE_GARGANTUAN + storage = /datum/storage/basket/large + slowdown_general = 1 // Large and unwieldly diff --git a/code/game/objects/items/weapons/tools/wrench.dm b/code/game/objects/items/weapons/tools/wrench.dm index e3f8e9e9d7a0..c117895cea1b 100644 --- a/code/game/objects/items/weapons/tools/wrench.dm +++ b/code/game/objects/items/weapons/tools/wrench.dm @@ -30,6 +30,7 @@ // Twohanded wrench. /obj/item/wrench/pipe + name_prefix = "enormous" name = "pipe wrench" desc = "You are no longer asking nicely." icon = 'icons/obj/items/tool/pipewrench.dmi' @@ -47,10 +48,6 @@ /obj/item/wrench/pipe/get_handle_color() return null -/obj/item/wrench/pipe/update_name() - . = ..() - SetName("enormous [name]") - /obj/item/wrench/pipe/Initialize() . = ..() set_extension(src, /datum/extension/tool, list(TOOL_WRENCH = TOOL_QUALITY_DEFAULT)) diff --git a/code/game/objects/structures/stool_bed_chair_nest_sofa/stools.dm b/code/game/objects/structures/stool_bed_chair_nest_sofa/stools.dm index 59ccd454a5d3..b9e169c20ed8 100644 --- a/code/game/objects/structures/stool_bed_chair_nest_sofa/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest_sofa/stools.dm @@ -157,14 +157,11 @@ return ..() /obj/item/stool/rustic - name = "stool" - icon = 'icons/obj/stool_rustic.dmi' - material = /decl/material/solid/organic/wood/walnut - color = /decl/material/solid/organic/wood/walnut::color - -/obj/item/stool/rustic/update_name() - ..() - SetName("rustic [name]") // rustic oaken stool, not oaken rustic stool + name_prefix = "rustic" + name = "stool" + icon = 'icons/obj/stool_rustic.dmi' + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color /obj/item/stool/rustic/can_be_padded() return FALSE diff --git a/code/modules/crafting/stack_recipes/recipes_grass.dm b/code/modules/crafting/stack_recipes/recipes_grass.dm index d6f262e90bc2..1005af46bfc9 100644 --- a/code/modules/crafting/stack_recipes/recipes_grass.dm +++ b/code/modules/crafting/stack_recipes/recipes_grass.dm @@ -11,6 +11,9 @@ /decl/stack_recipe/woven/basket result_type = /obj/item/basket +/decl/stack_recipe/woven/large_basket + result_type = /obj/item/basket/large + /decl/stack_recipe/woven/banner result_type = /obj/item/banner/woven diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm index 1097f54f9bc5..5487388845dc 100644 --- a/code/modules/detectivework/tools/rag.dm +++ b/code/modules/detectivework/tools/rag.dm @@ -50,13 +50,13 @@ return ..() /obj/item/chems/glass/rag/update_name() - . = ..() if(on_fire) - SetName("burning [name]") + name_prefix = "burning" else if(reagents && reagents.total_volume) - SetName("damp [name]") + name_prefix = "damp" else - SetName("dry [name]") + name_prefix = "dry" + . = ..() /obj/item/chems/glass/rag/on_update_icon() . = ..() diff --git a/code/modules/reagents/reagent_containers/beaker.dm b/code/modules/reagents/reagent_containers/beaker.dm index 258146c77c42..b593c3f968f3 100644 --- a/code/modules/reagents/reagent_containers/beaker.dm +++ b/code/modules/reagents/reagent_containers/beaker.dm @@ -65,6 +65,7 @@ take_damage(rand(4,8)) /obj/item/chems/glass/beaker/large + name_prefix = "large" name = "beaker" // see update_name override below desc = "A large beaker." icon = 'icons/obj/items/chem/beakers/large.dmi' @@ -74,10 +75,6 @@ possible_transfer_amounts = @"[5,10,15,25,30,60,120]" w_class = ITEM_SIZE_LARGE -/obj/item/chems/glass/beaker/large/update_name() - . = ..() - SetName("large [name]") // large glass beaker, not glass large beaker - /obj/item/chems/glass/beaker/bowl name = "mixing bowl" desc = "A large mixing bowl." diff --git a/icons/obj/items/storage/baskets/basket_large.dmi b/icons/obj/items/storage/baskets/basket_large.dmi index af9d0140ca7e4391ace607f2666842ae4817a899..71c23d7b6ce115ac70839991c4a2174f636cb779 100644 GIT binary patch delta 876 zcmV-y1C#uO39koGiBL{Q4GJ0x0000DNk~Le0001h0001h1Oos705K4J_y7O^5>QN3 zMZmzoWny-Uik`y3$^ZZVNk?3a@YVPL0004WQchCg*a8jS)Eauo0ylMnWB)CpHit?oReP?pA(;v zn1^JE3DG)>$kv&Zn4FDEpR$6hp9?q|02Q!!XnZSl*bvAs@0qm{0em1vK(H7l|oh_GFKCn9svcuPL@)#^G zP-v0Q=t6rtx;Wp1=9>8)v`YZrrN^xa0UYv{GJr0;n89-wrZIqj0F!r4QC z9c1uD7ucx({#nR|Y}(6t3BZ{D4mkUebv3-;EKr`~g_xX`dW`<{k0k)(&*0zwlz20P zIbMj#*^kmh%cyg9!GDU$**BO70#M%0An9_`nf$&4V7#5dhB`Q6F7b8%IASjGrsf`n zUU80!ii(Pg`V)G8TgAcBwofIj-70z&9mIOet=pFT3K*n^-orPCUp$u{Q$9l?%&B;wSOnB@_qnYlZ@QR zdnB&%egIo_S9Yk%BXO1Y1K6tD7Vl^@8+CaIG?k-I+CZhBq-sduEFfdc=!cXJ4KC2sO;mVWR@c@N-v+&ed&!51q zIzSh*`u=>UTd1Uh^(mP@A;6<6h<%<;l6v07mVV40MlvCfdkj@Xi17qN4r@{Q`><6StI{^r3|S00000001>1Oos70D0kh9smFU6;Mo6 zMZmzoWny-Uik`y3$^ZZVNk?43z`(>+yAA*V00DGTPE!Ct=GbNc006U*P*Q)1i!&v& zs2C__$i8Y7U$%b z#OK6kB<3OMG$C4N5!pH+c4ByqRI4d4ASp398<#$11y?^8aAE)eXfdQb6w_|B000AC zNklLV5Qd2k_XdCD9;Dt|@H{}pb8oP`|En}aNH&`dhSoVVJ(I7tSdM+8?)gRyGeC)P6zt0(1Bk=!2tmPCUlH65(^JmV$8u6*~yT6oP-QhH!o)c@i$`7UQD%Of^*V*&wIkA=n9?BF% zT2ZQ3Scj=7xZuTY&c%OPaZ<0a4uhyTFRc~PtAcePqN=8rh3TlEbRY#UrYG*SB6?M@ z4rG5mfA15+$GxuC%>SHkf2R3JhvB95B9TZW68U#*7v*xQc6N}BSJLrdwA9XSp(P;c zcra?59VFvWF(B!9Flw9~q^_V<5kS)MVAMD}tHT0Xl>$gQ9*ln)X9uy}88mBjJQ$^& zo$bz`S)=2@DDCWQcLvQG9S=rnXJ@-JXx8X>FuK;+(ecqAMk0|&Hjm^NeRe7YR;hed0Shr?{z?p|1`` zr^8N72}#R@4a8%3W~W|;0X{(mzoCDY9m<;Af24_(@?#PXn+a07*qo IM6N<$f^EqXfdBvi diff --git a/icons/obj/items/storage/baskets/basket_round.dmi b/icons/obj/items/storage/baskets/basket_round.dmi index 378fe0f2a2f09a711b1df90f79d6e01be84f619a..c84fe4b7e607201c0f120d47b6fd4b1913f11e25 100644 GIT binary patch delta 669 zcmV;O0%HBF2Z#nCiBL{Q4GJ0x0000DNk~Le0001h0001B1Oos704G#udXXV60i%&n zPJcJQAT>{ki!&v&s2C_{$i~?OP0Y*B zOi@V6PpQ-`&dD!{&xy}S%tLaL3DG)>@aj}naP@Nm2PXjS8)n6`+7S%^00H$$L_t(o zh3%Npj-wzHhUtp;UFhB~?L0uSJ^(7-cYm_@{;#rNCwP7abgnkD316DF-vJTP#6K`r z`Bw-b&U=1@(w^UCKjO!FHc|9LqN2P0{&yyV~f1lTvUD z_~~x_n)OCUAFf@eqJPW|CIrr%3|w6FPTa1dcjSQc`XO%3=FOlVkB8RN=IW}Hrhk{v zTMIMjZ*ODHQwL6VZr!1eu;4&Z)XHg9ad5@!&W#4ie+!E9&4O3vTyG);DJ zn};PC=nO_7U;yxT68<)haxQq_U2C`m@YXMyN6!ThtPe`jKW^i*{G_sO8EeUNiq$VP|7q`DwRs*TXEjgd>+7R^0vLFmTq|)<6hJS z+7iv@0jQ3hp>1OaUGsT>R@(t~T)aZpd>)`x?qK80D|F500b1os(L}?ORnO-ET5YBL zMVh=q*L)tJRc^x$CL;=6^LYTO%L1p^-F4cpenb8OHKTBoeln^F00000NkvXXu0mjf Do?$#_ delta 835 zcmV-J1HAl*2CN4miBL{Q4GJ0x0000DNk~Le0001>0001h1Oos70Det>D3Kv90jrTv zPJfAuGbOXA7|1u|;!G<_%uR)`QB~}jt?&M3`I%*)SA zQAo;9snjjb$uEh|iO)#PL(*wNw9X>3bwcdKa5Sk_6EHwo!PUyZlf>|M#*CCvyk4Gq<;?pga_cq+^1Ue{;yKwt?U^yc5HElmjeWqI}GSn5{t>CUnIQL8DPIhsoS&abWOxVB6D+9KOpnL~j6ee$%bo8xoD$Bu{i@B7K%~UOpO!3{eFJ~^~O^~#UBU7jc*O`AG zo0lsS6zl5A;{Q!}xw69E8$JpypMRQuab|_RH+-;FUV=q9v%=mRUiiAMVsPgTdvCls zqxYsM?7eXqdv6@Z-W!Lp_r_s}%X$oZZzK|lL?Uq>F5c)rlr+2C8R>pdrOnR0Lb@MR zX|tO-ObkT2A5>|x!^$f_r29dYHoFe^>@!pF21I(-(P0clrFA$0ujeKR?A7EzXXlkxOGg&6kU|+`l0cKW?rsf*tldP`c zf*EzyjsFGsWKmTg8H)P@jDPTDmp{y7vp~+KDn-_g)%eae<3~@fbqX%f{8>T zkvKUq^T8~{)?(&^S%^;py?Z+!lx}fD?^#imfZoymhpJOI!1tzZ*DiqG(f$Xk#fZM~ zmvPsQ=7XgF!D@g{M$HF9d@^c27~+#r^T80GjG7My`K06I@2V%{2NW4(pfn+To`3)V N002ovPDHLkV1h3AmfZjV From 6286dff462f219b8fa0d9e52d9a525da7a8b6348 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Wed, 4 Dec 2024 18:51:32 +1100 Subject: [PATCH 04/90] Adding hay. --- code/datums/extensions/storage/_storage.dm | 19 ++--- code/game/objects/structures/hay.dm | 73 ++++++++++++++++++ code/game/turfs/flooring/flooring_misc.dm | 4 +- code/game/turfs/floors/subtypes/floor_misc.dm | 4 +- .../crafting/stack_recipes/recipes_fodder.dm | 14 ++++ .../simple_animal/friendly/farm_animals.dm | 2 +- icons/effects/hay.dmi | Bin 0 -> 413 bytes icons/obj/food/hay.dmi | Bin 0 -> 292 bytes icons/obj/structures/haybale.dmi | Bin 0 -> 414 bytes icons/obj/structures/haystack.dmi | Bin 0 -> 460 bytes icons/turf/flooring/straw.dmi | Bin 0 -> 1716 bytes nebula.dme | 2 + 12 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 code/game/objects/structures/hay.dm create mode 100644 code/modules/crafting/stack_recipes/recipes_fodder.dm create mode 100644 icons/effects/hay.dmi create mode 100644 icons/obj/food/hay.dmi create mode 100644 icons/obj/structures/haybale.dmi create mode 100644 icons/obj/structures/haystack.dmi create mode 100644 icons/turf/flooring/straw.dmi diff --git a/code/datums/extensions/storage/_storage.dm b/code/datums/extensions/storage/_storage.dm index e6200fdaf083..1bdba0180ca4 100644 --- a/code/datums/extensions/storage/_storage.dm +++ b/code/datums/extensions/storage/_storage.dm @@ -79,12 +79,10 @@ var/global/list/_test_storage_items = list() LAZYDISTINCTADD(., storage_inv) /datum/storage/proc/show_to(mob/user) - if(storage_ui) - storage_ui.show_to(user) + storage_ui?.show_to(user) /datum/storage/proc/hide_from(mob/user) - if(storage_ui) - storage_ui.hide_from(user) + storage_ui?.hide_from(user) /datum/storage/proc/open(mob/user) if(!opened) @@ -98,11 +96,12 @@ var/global/list/_test_storage_items = list() robot.hud_used.toggle_show_robot_modules() prepare_ui() - storage_ui.on_open(user) - storage_ui.show_to(user) + if(storage_ui) + storage_ui.on_open(user) + storage_ui.show_to(user) /datum/storage/proc/prepare_ui() - storage_ui.prepare_ui() + storage_ui?.prepare_ui() /datum/storage/proc/close(mob/user) if(opened) @@ -110,12 +109,10 @@ var/global/list/_test_storage_items = list() play_close_sound() holder?.queue_icon_update() hide_from(user) - if(storage_ui) - storage_ui.after_close(user) + storage_ui?.after_close(user) /datum/storage/proc/close_all() - if(storage_ui) - storage_ui.close_all() + storage_ui?.close_all() /datum/storage/proc/storage_space_used() . = 0 diff --git a/code/game/objects/structures/hay.dm b/code/game/objects/structures/hay.dm new file mode 100644 index 000000000000..47fa6ac32056 --- /dev/null +++ b/code/game/objects/structures/hay.dm @@ -0,0 +1,73 @@ +// Items that provide animal feed. +/datum/storage/haystack + can_hold = list(/obj/item/food/hay) + +// Not actually a food item, but you can eat it if you like. +/obj/item/food/hay + name = "handful of hay" + icon = 'icons/obj/food/hay.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plantmatter/grass/dry + nutriment_amt = 1 + nutriment_type = /decl/material/solid/organic/plantmatter/grass + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/food/hay/end_throw() + . = ..() + addtimer(CALLBACK(src, PROC_REF(check_self_destroy)), 1, (TIMER_UNIQUE | TIMER_OVERRIDE) ) + +/obj/item/food/hay/proc/check_self_destroy() + if(isturf(loc) && !QDELETED(src)) + physically_destroyed() + +/obj/item/food/hay/physically_destroyed() + new /obj/effect/decal/cleanable/hay(loc) + . = ..() + +/obj/effect/decal/cleanable/hay + name = "loose hay" + desc = "Some loose hay from a haybale." + icon = 'icons/effects/hay.dmi' + icon_state = ICON_STATE_WORLD + color = /decl/material/solid/organic/plantmatter/grass/dry::color + sweepable = TRUE + +/obj/effect/decal/cleanable/hay/Initialize(ml, _age) + for(var/obj/effect/decal/cleanable/hay/hay in loc) + if(hay != src) + return INITIALIZE_HINT_QDEL + return ..() + +/obj/structure/haystack + name = "haystack" + desc = "A pile of dry, prickly hay. Not a great place for storing needles." + icon = 'icons/obj/structures/haystack.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plantmatter/grass/dry + storage = /datum/storage/haystack + material_alteration = MAT_FLAG_ALTERATION_COLOR + atom_flags = ATOM_FLAG_CLIMBABLE + var/const/FOOD_MAX = 20 + +/obj/structure/haystack/Initialize(ml, _mat, _reinf_mat) + . = ..() + for(var/i = 1 to FOOD_MAX) + new /obj/item/food/hay(src) + storage.make_exact_fit() + +/obj/structure/haystack/Exited(atom/movable/am, atom/new_loc) + . = ..() + if(!QDELETED(src) && !length(contents)) + physically_destroyed() + +/obj/structure/haystack/create_matter() + matter = null // Haystack is almost a dummy item; the matter is the food inside. + +/obj/structure/haystack/physically_destroyed(skip_qdel) + new /obj/effect/decal/cleanable/hay(loc) + . = ..() + +/obj/structure/haystack/bale + name = "haybale" + desc = "A tight bundle of dry grass, probably set aside as animal feed." + icon = 'icons/obj/structures/haybale.dmi' diff --git a/code/game/turfs/flooring/flooring_misc.dm b/code/game/turfs/flooring/flooring_misc.dm index eaed5e06b524..eb80eae759e6 100644 --- a/code/game/turfs/flooring/flooring_misc.dm +++ b/code/game/turfs/flooring/flooring_misc.dm @@ -76,8 +76,8 @@ /decl/flooring/straw name = "straw floor" desc = "A thick layer of straw, suitable for livestock." - icon = 'icons/turf/flooring/wildgrass.dmi' // temporary, replace with better icon at some point - icon_base = "wildgrass" + icon = 'icons/turf/flooring/straw.dmi' + icon_base = "straw" has_base_range = null icon_edge_layer = FLOOR_EDGE_GRASS_WILD damage_temperature = T0C+80 diff --git a/code/game/turfs/floors/subtypes/floor_misc.dm b/code/game/turfs/floors/subtypes/floor_misc.dm index fbc7d2400e17..a88eb9784ea3 100644 --- a/code/game/turfs/floors/subtypes/floor_misc.dm +++ b/code/game/turfs/floors/subtypes/floor_misc.dm @@ -45,8 +45,8 @@ /turf/floor/straw name = "loose straw" - icon = 'icons/turf/flooring/wildgrass.dmi' - icon_state = "wildgrass" + icon = 'icons/turf/flooring/straw.dmi' + icon_state = "straw" color = COLOR_WHEAT _flooring = /decl/flooring/straw diff --git a/code/modules/crafting/stack_recipes/recipes_fodder.dm b/code/modules/crafting/stack_recipes/recipes_fodder.dm new file mode 100644 index 000000000000..86ec028b152d --- /dev/null +++ b/code/modules/crafting/stack_recipes/recipes_fodder.dm @@ -0,0 +1,14 @@ +/decl/stack_recipe/fodder + result_type = /obj/structure/haystack + required_material = /decl/material/solid/organic/plantmatter/grass/dry + craft_stack_types = list(/obj/item/stack/material/bundle) + one_per_turf = TRUE + on_floor = TRUE + difficulty = MAT_VALUE_EASY_DIY + recipe_skill = SKILL_BOTANY + +/decl/stack_recipe/fodder/get_required_stack_amount(obj/item/stack/stack) + return 30 // Arbitrary amount to make 20 food items. + +/decl/stack_recipe/fodder/bale + result_type = /obj/structure/haystack/bale diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index b1df77c7be41..8d6b9992aca8 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -103,7 +103,7 @@ see_in_dark = 6 max_health = 50 butchery_data = /decl/butchery_data/animal/ruminant/cow - + // When cows can accept food items: /obj/item/food/hay var/static/list/responses = list( "looks at you imploringly", "looks at you pleadingly", diff --git a/icons/effects/hay.dmi b/icons/effects/hay.dmi new file mode 100644 index 0000000000000000000000000000000000000000..47c16d24770df9a0998355386cd4c9d51b22aba8 GIT binary patch literal 413 zcmV;O0b>4%P)V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zsXV_ZCq;>iGbOXA7|1u|;!G<_%uR)`l@(n5T)@Tx06PL2GXQEUS1IMVmD>yI(Aw%y z1icEC>!=fnCyWIN)Kt}R5KPa3>NQ&D=~H$GP&_P7kqC0!nwaE#mbuGf1kt0cxD zczsu)4>inuxe?Sfuavhxc0k}a8~!+UKbB=sK0LhtLVq4ldJiJ}$-l4C00000NkvXX Hu0mjfRbsC3 literal 0 HcmV?d00001 diff --git a/icons/obj/food/hay.dmi b/icons/obj/food/hay.dmi new file mode 100644 index 0000000000000000000000000000000000000000..2a24bc36b017f1733001a06bc3d2f7f39721396c GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*8>L*balsR)s{AxTF>*7iAWdWaj5FFjUM54l5`s{r)Am;N#aP zTHd-^=gyoD-VkbV(fGk5o%24LCmD)*dUseD2N_>B_EMPhXws2MAqv4OZT4%ZyLNUP zt8QK)al-t`BOh(AGrp}Gri#Y=jX7|PiNTsl%9tTb`zg>;KTj9O5RHk+2@fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*+P6Jpc>`s1)C~9WH=+fEg3-f0ad&zVFMX#QcO$_(?RS?*%T|em>=m z-|X@9^aucLH$6IevPHJ0FCvBZQqVPgds?&Rhpg`lY}km7u4Jz71&pB49xmaLgbssF z+DtXTU}fRTE__A@RfFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*+P6I=r#={MFOur--%g^s*%QS8L$u~D5=~+raC1{+#{LuX0!o@&`U^zWMMYy z3BXGN=eg{UFuLK~-SNi{I`;$7D=4TWUae~Y0000004jp0{{R3ySh-z`(#Aj+Cna0004WQchCV=-0C=2JR&a84 z_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5siY`1 zFF8Yri!&v&s2C_<$iDi0BwCm=o;Y$>i_@+ib+I4RCt{2TH%_bDh#cFq@A{NSAG9?z2qcd zcV`QZ$gDp&GoubxI6Z+RqcishvVqNFB)8GF5SNrfDcmU z1Azwf2xJThg4V!frHzN;ftd+kfQoggxpcoo5FgAF3=EAAG6H;tn&3G2s}(gcFr1+&_BC8)Y!u}B;Vic(+DE(&`LO}>7>?D{# zK#9fTSN;qT8aM0#bI=u%1!GqC?1wZ3;R=JB!4mlzKqRi%dVk=P+J zrUi3EBticLg0d4q#t`kxX<;B7lZ7t|#<+5TiP3dF-O>!z#57+s|Kw))J8JYz3fj1y zYY9sKIf4e(WlnyO=*Au=?MZ~xnjEa^iJ-Lv(OEv!#eCJ^N_?V^8P`?GaHJC%bsrLE zVJ*QDKPG5~btxkTn-@O_GRO$+nlRu$5ww;d_g~Cr;9A668%?~@u1=)0k(tgzmjo>l z&<#L3rQLzDLjQ$qCOYaA?;s*bdu-fAJN=P_(Ehe3$th$>HdHwA^Rml|TPx{5pUoJ5 z6SJB`P{W<)eDGaD2%<#=;fD#&^EOlp3GzJeRGlj&gkcW)+lT+Sd8H?5p@!qZ%O2!! z38C1$NU-oc?&nSXaT8iR^MaH&laiUx=HZ$%31N|7;dwq~7s>tc!MZ&kF!AT(e&>Hb zpO44w=KbU0atYyv%0cOQ+|Mz*KOgu1e%&9B=jX3*`n-QWpW%GJ2j;iX=&a2pgj*EM zK9Bp~+Uh6JTL0VA0d1=fR)E&}-yVXFHq{3!Kri*b9Smt(eXs_U>VLaTysbW11Je56 z{zc=WUht&TXf)1(wH3S_}|7!_qoQ>3i4ypgO107TUYX>@}{?`t4O#QDR=#ctf zOVAPZzm}lWD|kfxuOaA=`d>THw)$VOo2orS_DR}Q|0{vFPWx&bVSLJuPh0ALB^2v_ zZ$~fJA8AYduY_X#@9pTt`Xg7`U)?+V@@yzbvt|f5p_fIsEK-|Bv6;`GIZgGPz~f zt4joa?JE;*n%r&^&p%MxnP#{1)ukZe^aCcI+|IYtz|SqUP literal 0 HcmV?d00001 diff --git a/nebula.dme b/nebula.dme index 94ba5f208a83..930adf70a61e 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1459,6 +1459,7 @@ #include "code\game\objects\structures\grille.dm" #include "code\game\objects\structures\hand_cart.dm" #include "code\game\objects\structures\handrail.dm" +#include "code\game\objects\structures\hay.dm" #include "code\game\objects\structures\holosigns.dm" #include "code\game\objects\structures\inflatable.dm" #include "code\game\objects\structures\ironing_board.dm" @@ -2209,6 +2210,7 @@ #include "code\modules\crafting\stack_recipes\recipes_bricks.dm" #include "code\modules\crafting\stack_recipes\recipes_cardstock.dm" #include "code\modules\crafting\stack_recipes\recipes_coins.dm" +#include "code\modules\crafting\stack_recipes\recipes_fodder.dm" #include "code\modules\crafting\stack_recipes\recipes_grass.dm" #include "code\modules\crafting\stack_recipes\recipes_hardness.dm" #include "code\modules\crafting\stack_recipes\recipes_hardness_integrity.dm" From e174d8c232fb60693239983bf789d3ac390ec27a Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Fri, 27 Sep 2024 21:07:56 -0400 Subject: [PATCH 05/90] Fix HE pipes lacking color --- code/modules/atmospherics/_atmos_setup.dm | 8 ++++---- code/modules/atmospherics/he_pipes.dm | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/code/modules/atmospherics/_atmos_setup.dm b/code/modules/atmospherics/_atmos_setup.dm index 57b3c67d140a..74d85deb11a1 100644 --- a/code/modules/atmospherics/_atmos_setup.dm +++ b/code/modules/atmospherics/_atmos_setup.dm @@ -17,10 +17,10 @@ var/global/list/pipe_colors = list( "white" = PIPE_COLOR_WHITE, "dark gray" = COLOR_DARK_GRAY) -/proc/pipe_color_check(var/color) +/obj/machinery/atmospherics/proc/pipe_color_check(var/color) if(!color) - return 1 + return TRUE for(var/C in pipe_colors) if(color == pipe_colors[C]) - return 1 - return 0 + return TRUE + return FALSE diff --git a/code/modules/atmospherics/he_pipes.dm b/code/modules/atmospherics/he_pipes.dm index 49437ef28d4e..55afc98fd37f 100644 --- a/code/modules/atmospherics/he_pipes.dm +++ b/code/modules/atmospherics/he_pipes.dm @@ -27,6 +27,11 @@ . = ..() add_filter("glow",1, list(type = "drop_shadow", x = 0, y = 0, offset = 0, size = 4)) +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/pipe_color_check(var/color) + if (color == initial(pipe_color)) + return TRUE + return FALSE + /obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_dir(new_dir) . = ..() initialize_directions_he = get_initialize_directions() // all directions are HE From 071bbe0b9782672cbf11afd4d7ae75e0b4eb18ab Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Fri, 27 Sep 2024 21:11:43 -0400 Subject: [PATCH 06/90] Fix antag skill selector runtiming --- code/modules/mob/skills/skill_ui.dm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/skills/skill_ui.dm b/code/modules/mob/skills/skill_ui.dm index 540b250d4eb0..221439db085b 100644 --- a/code/modules/mob/skills/skill_ui.dm +++ b/code/modules/mob/skills/skill_ui.dm @@ -122,13 +122,20 @@ The generic antag version. . = ..() .["can_choose"] = can_choose() var/list/selection_data = list() - var/decl/skill/skill = GET_DECL(/decl/skill) + var/decl/skill/sample_skill // just used to get the skill level names + for(var/candidate_skill_type in skillset.skill_list) + var/decl/skill/candidate = GET_DECL(candidate_skill_type) + if(length(candidate.levels) == SKILL_MAX) // find a skill with all the levels, so avoid perks/traits + sample_skill = candidate + break + if(!sample_skill) + sample_skill = GET_DECL(/decl/skill/general/hauling) for(var/i in 1 to length(max_choices)) var/choices = max_choices[i] if(!choices) continue var/list/level_data = list() - level_data["name"] = skill.levels[i] + level_data["name"] = sample_skill.levels[i] level_data["level"] = i var/selected = LAZYACCESS(currently_selected, i) level_data["selected"] = list() From 3a459cc1ebcd697aef1053dd459c94e443f8826d Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Wed, 27 Nov 2024 20:47:13 -0500 Subject: [PATCH 07/90] Rename temporaray.dm to temporary.dm --- code/game/objects/effects/{temporaray.dm => temporary.dm} | 0 nebula.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/game/objects/effects/{temporaray.dm => temporary.dm} (100%) diff --git a/code/game/objects/effects/temporaray.dm b/code/game/objects/effects/temporary.dm similarity index 100% rename from code/game/objects/effects/temporaray.dm rename to code/game/objects/effects/temporary.dm diff --git a/nebula.dme b/nebula.dme index f342d9e5ce3e..f8b13ec706bb 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1045,7 +1045,7 @@ #include "code\game\objects\effects\portals.dm" #include "code\game\objects\effects\spiders.dm" #include "code\game\objects\effects\step_triggers.dm" -#include "code\game\objects\effects\temporaray.dm" +#include "code\game\objects\effects\temporary.dm" #include "code\game\objects\effects\temporary_effect.dm" #include "code\game\objects\effects\wet_floor.dm" #include "code\game\objects\effects\wormhole.dm" From 1f3322cba1b198f8c344356af138c896a74df46c Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Wed, 27 Nov 2024 20:48:48 -0500 Subject: [PATCH 08/90] Replace item and structure color sets with set_color --- .../game/gamemodes/endgame/supermatter_cascade/universe.dm | 4 ++-- code/game/machinery/computer/guestpass.dm | 2 +- code/game/objects/alien_props.dm | 3 +-- code/game/objects/items/flashlights/glowstick.dm | 2 +- code/game/objects/items/stacks/tiles/tile_types.dm | 1 - code/game/objects/items/weapons/cards_ids_syndicate.dm | 2 +- .../objects/structures/crates_lockers/closets/__closet.dm | 2 +- code/game/objects/structures/curtains.dm | 2 +- code/game/objects/structures/flora/plant.dm | 2 +- code/modules/paperwork/paper_sticky.dm | 2 +- code/modules/paperwork/pen/crayon.dm | 2 +- code/modules/power/lighting.dm | 7 ++----- code/modules/projectiles/guns/energy/capacitor.dm | 2 +- 13 files changed, 14 insertions(+), 19 deletions(-) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index 8de40b0d1234..e9b2d2e40fd4 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -15,9 +15,9 @@ var/global/universe_has_ended = 0 /datum/universal_state/supermatter_cascade/OnTurfChange(var/turf/T) var/turf/space/S = T if(istype(S)) - S.color = "#0066ff" + S.set_color("#0066ff") else - S.color = initial(S.color) + S.set_color(initial(S.color)) /datum/universal_state/supermatter_cascade/DecayTurf(var/turf/T) T.handle_universal_decay() diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index 37ac6e0d729a..af53c701163e 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -34,7 +34,7 @@ to_chat(usr, SPAN_NOTICE("Issuing reason: [reason].")) /obj/item/card/id/guest/proc/expire() - color = COLOR_BLACK + set_color(COLOR_BLACK) detail_color = COLOR_BLACK update_icon() diff --git a/code/game/objects/alien_props.dm b/code/game/objects/alien_props.dm index b6dca18e783c..6297ef140f0b 100644 --- a/code/game/objects/alien_props.dm +++ b/code/game/objects/alien_props.dm @@ -65,8 +65,7 @@ . = ..() if(!random_light_color) random_light_color = get_random_colour(FALSE, 100, 255) - b_color = random_light_color - color = random_light_color + set_color(random_light_color) // if stuff starts exploding due to too-early update_icon calls it's this thing's fault //Airlock /obj/machinery/door/airlock/alien diff --git a/code/game/objects/items/flashlights/glowstick.dm b/code/game/objects/items/flashlights/glowstick.dm index 689fd0a7eb82..c0f07103a330 100644 --- a/code/game/objects/items/flashlights/glowstick.dm +++ b/code/game/objects/items/flashlights/glowstick.dm @@ -43,5 +43,5 @@ color = "#ff00ff" /obj/item/flashlight/flare/glowstick/random/Initialize() - color = rgb(rand(50,255),rand(50,255),rand(50,255)) + set_color(rgb(rand(50,255),rand(50,255),rand(50,255))) . = ..() diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index a53c61d5bad1..d2ce17d3dd10 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -285,7 +285,6 @@ /obj/item/stack/tile/carpet/on_update_icon() . = ..() - color = get_color() if(detail_color) set_overlays(overlay_image(icon, "[icon_state]-detail", detail_color, RESET_COLOR)) diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm index 75851fa02dae..37020adb925d 100644 --- a/code/game/objects/items/weapons/cards_ids_syndicate.dm +++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm @@ -131,7 +131,7 @@ if(choice && CanUseTopic(user, state)) src.icon_state = choice.icon_state src.item_state = choice.item_state - src.color = choice.color + set_color(choice.color) src.detail_color = choice.detail_color src.extra_details = choice.extra_details update_icon() diff --git a/code/game/objects/structures/crates_lockers/closets/__closet.dm b/code/game/objects/structures/crates_lockers/closets/__closet.dm index 70b311eb6dcd..96312da861fe 100644 --- a/code/game/objects/structures/crates_lockers/closets/__closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/__closet.dm @@ -42,7 +42,7 @@ var/global/list/closets = list() var/decl/closet_appearance/app = GET_DECL(closet_appearance) if(app) icon = app.icon - color = null + reset_color() queue_icon_update() return INITIALIZE_HINT_LATELOAD diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm index bffd87cc4fe2..4e1bafbf36eb 100644 --- a/code/game/objects/structures/curtains.dm +++ b/code/game/objects/structures/curtains.dm @@ -60,7 +60,7 @@ if(curtain_kind_path) var/decl/curtain_kind/kind = GET_DECL(curtain_kind_path) alpha = kind.alpha - color = kind.color + set_color(kind.color) // // Curtain Structure diff --git a/code/game/objects/structures/flora/plant.dm b/code/game/objects/structures/flora/plant.dm index bec1cc918669..161543c408a0 100644 --- a/code/game/objects/structures/flora/plant.dm +++ b/code/game/objects/structures/flora/plant.dm @@ -70,7 +70,7 @@ /obj/structure/flora/plant/on_update_icon() . = ..() icon_state = "blank" - color = null + reset_color() set_overlays(plant.get_appearance(dead = dead, growth_stage = growth_stage, can_harvest = !!harvestable)) /obj/structure/flora/plant/attackby(obj/item/O, mob/user) diff --git a/code/modules/paperwork/paper_sticky.dm b/code/modules/paperwork/paper_sticky.dm index de9f83e3fdf5..0606f6bfbd40 100644 --- a/code/modules/paperwork/paper_sticky.dm +++ b/code/modules/paperwork/paper_sticky.dm @@ -84,7 +84,7 @@ /obj/item/sticky_pad/random/Initialize() . = ..() - color = pick(COLOR_YELLOW, COLOR_LIME, COLOR_CYAN, COLOR_ORANGE, COLOR_PINK) + set_color(pick(COLOR_YELLOW, COLOR_LIME, COLOR_CYAN, COLOR_ORANGE, COLOR_PINK)) //////////////////////////////////////////////// // Sticky Note Sheet diff --git a/code/modules/paperwork/pen/crayon.dm b/code/modules/paperwork/pen/crayon.dm index b4bfb68c3a97..0c3222998ac1 100644 --- a/code/modules/paperwork/pen/crayon.dm +++ b/code/modules/paperwork/pen/crayon.dm @@ -18,7 +18,7 @@ /obj/item/pen/crayon/Initialize() . = ..() if(use_stroke_color) - color = stroke_color + set_color(stroke_color) /obj/item/pen/crayon/make_pen_description() desc = "A colourful [stroke_color_name] [istype(material)?"[material.name] ":null][medium_name]. Please refrain from eating it or putting it in your nose." diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 76ea4bb5e1ee..241a5ed52e22 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -482,7 +482,7 @@ /obj/item/light/set_color(color) b_color = isnull(color) ? COLOR_WHITE : color - update_icon() + queue_icon_update() // avoid running update_icon before Initialize /obj/item/light/tube name = "light tube" @@ -552,7 +552,6 @@ // update the icon state and description of the light /obj/item/light/on_update_icon() . = ..() - color = b_color var/broken switch(status) if(LIGHT_OK) @@ -565,9 +564,7 @@ icon_state = "[base_state]_broken" desc = "A broken [name]." broken = TRUE - var/image/I = image(icon, src, "[base_state]_attachment[broken ? "_broken" : ""]") - I.color = null - add_overlay(I) + add_overlay(overlay_image(icon, "[base_state]_attachment[broken ? "_broken" : ""]", flags = RESET_COLOR|RESET_ALPHA)) /obj/item/light/Initialize(mapload) . = ..() diff --git a/code/modules/projectiles/guns/energy/capacitor.dm b/code/modules/projectiles/guns/energy/capacitor.dm index 38d3f62f52e5..1232ef3e8f39 100644 --- a/code/modules/projectiles/guns/energy/capacitor.dm +++ b/code/modules/projectiles/guns/energy/capacitor.dm @@ -250,7 +250,7 @@ var/global/list/laser_wavelengths if(charged) var/obj/item/projectile/P = new projectile_type(src) - P.color = selected_wavelength.color + P.set_color(selected_wavelength.color) P.set_light(l_color = selected_wavelength.light_color) P.damage = floor(sqrt(total_charge) * selected_wavelength.damage_multiplier) P.armor_penetration = floor(sqrt(total_charge) * selected_wavelength.armour_multiplier) From c23b2c84997fb5e0d1778dd81c1babc205b61c16 Mon Sep 17 00:00:00 2001 From: NebulaSS13Bot Date: Sat, 7 Dec 2024 00:53:42 +0000 Subject: [PATCH 09/90] Automatic changelog generation [ci skip] --- html/changelog.html | 12 ++++++------ html/changelogs/.all_changelog.yml | 4 ++++ html/changelogs/AutoChangeLog-pr-4583.yml | 5 ----- 3 files changed, 10 insertions(+), 11 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4583.yml diff --git a/html/changelog.html b/html/changelog.html index 526d388b528b..7aab615f9423 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -52,6 +52,12 @@ -->
+

07 December 2024

+

MistakeNot4892 updated:

+
    +
  • Most wooden floors and tables on space maps are now chipboard laminate instead.
  • +
+

05 December 2024

ophelia updated:

    @@ -106,12 +112,6 @@

    Sutures updated:

  • Added a wood plank texture to wood tables, used if the fantasy modpack is included.
  • Fixed wall banners not starting with banners.
- -

05 October 2024

-

MistakeNot4892 updated:

-
    -
  • Sledgehammers can demolish non-reinforced walls.
  • -
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 6bcd5bb49501..3906fe0882f2 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -14929,3 +14929,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - tweak: You can now put any disk into the research design database or research design console, but only the correct disk type (tech disk or design disk) will function. +2024-12-07: + MistakeNot4892: + - tweak: Most wooden floors and tables on space maps are now chipboard laminate + instead. diff --git a/html/changelogs/AutoChangeLog-pr-4583.yml b/html/changelogs/AutoChangeLog-pr-4583.yml deleted file mode 100644 index 9c592814efdd..000000000000 --- a/html/changelogs/AutoChangeLog-pr-4583.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: MistakeNot4892 -changes: - - {tweak: Most wooden floors and tables on space maps are now chipboard laminate - instead.} -delete-after: true From da85b88111ad77a74c992bcaa26fb0e691ec95f3 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 12:19:21 +1100 Subject: [PATCH 10/90] Adding a large cauldron that cannot be picked up. --- code/modules/food/cooking/cooking_vessels/pot.dm | 13 +++++++++++++ icons/obj/food/cooking_vessels/cauldron.dmi | Bin 0 -> 1078 bytes 2 files changed, 13 insertions(+) create mode 100644 icons/obj/food/cooking_vessels/cauldron.dmi diff --git a/code/modules/food/cooking/cooking_vessels/pot.dm b/code/modules/food/cooking/cooking_vessels/pot.dm index 93c6a4585eb3..9465db82d300 100644 --- a/code/modules/food/cooking/cooking_vessels/pot.dm +++ b/code/modules/food/cooking/cooking_vessels/pot.dm @@ -40,3 +40,16 @@ if(. == PROCESS_KILL) last_boil_temp = null + +/obj/item/chems/cooking_vessel/cauldron + name = "cauldron" + desc = "A large round-bodied vessel for making large quantities of potion or soup." + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + icon = 'icons/obj/food/cooking_vessels/cauldron.dmi' + volume = 1000 + w_class = ITEM_SIZE_STRUCTURE + density = TRUE + +/obj/item/chems/cooking_vessel/cauldron/can_be_picked_up(mob/user) + return FALSE diff --git a/icons/obj/food/cooking_vessels/cauldron.dmi b/icons/obj/food/cooking_vessels/cauldron.dmi new file mode 100644 index 0000000000000000000000000000000000000000..7be32a10bde46e4549464f184f1c1bf40bc7b108 GIT binary patch literal 1078 zcmV-61j+k}P)005u_0{{R3dEt5<0000jP)t-sz`(%5 z!O8#s|4Bz&Wny;t`1p#7o}!|;RZ?j3^z-=p^x);`+S}g%|1-eAz%rM_zW@LL0d!JM zQvg8b*k%9#0O@*ESad{Xb7OL8aCB*JZU6vyoSl=w4uUWYhR^IN7Q7mRN{kmT24gtr zE0Dq}ENskdL*v_9;G|Il9+v!F`Za&sZN~S9V|wPvDP=dbPMU`Ac)W;MaF@bY6s%V) zs8E)b9|GsWBgyb?tP&v$gtU(0B?~SVG!FVTE3*hCHa^S2;U7qr8>wVdenvNRiwYhj zqs4aq;ry&!RBcl~{&6*szs<#8&Apd)roCnw!RMfq8|kNqM60izgGo?tei}i|>#=i^ z1y0&_mtVBjj$MSn!dUS1V5t+D|42-OtG}hr_~D%NU*QSE-SHiYfi-ae00P2EL_t(& zf$f>kZrVT)#!Zbul^V$|?3!a~UZ9CB&L9)3N9N$DM^9+N}4bK%_g=qvQldoF!} zyi3MJz^o~MtZpyO{3Im4+40ACv8_+wdCcqK{m0O$Uq4B%J~;KuvdpDpCq)u>C*3Fq z#1Tma0IZIB`c0bV`8d7a76MTeh482r6H=(C z%AIZ|-5eQr(oLl;keHm&H`EV1ePZ3u`q~(+F0*av0l6oeGLPeUO7!t{KTrC`sLMe{ zI_C6v&s!|+Eq!!7Gb-svmse&s^qi26RD^d*q{g2d85$WOQfgO*xl(ATjH?MVZDfgd zwTFI=BPwO`>~!yWhACc#(rBGHGQ1w(ePZx+?Pd@CZbz5*@_5$mI58Xy$BD*Ud6o`y z7bE(*d^{ldXlTw{7?xA{*~^o`)z^X-ch}KHy}@^Jvj5i5-R?0Ab2fGJV0%8FAJc!z ze?=w#(LC5H!_wlgUgy2yaNgU?i?NWR7l#LR{X7UuP;gk+&x1ntWOzi^&x5Bl!!QiP zFwFV177Loj_VQkJ{SN#P+tVidp)(Z@}E#@Np%1d5!mwu*2H(K$k=&L3aam9&(b00V`_l&g?2uy_4{Cn zea1Mn$1n`TFwB2UaJq#cO=K6E%e|gD|4%D`VoD32BfWS0QNy?2scMyfA1mr7Z{%ud z9}?JxVbhX79;q@0L=o-cR$~boOl2aN67y-JvZ;?hscHb+(%(!29Poxtysi;L4_aQ+ z`oMR;tZspkmafBBsO}*cTMv(aN29L2F7v6~(5ei~FbwnRc`A8%d$D`VhHS`&Y*_NU w>ixHdYnuy~hEE$mXNFtYkPX?84PU9@GbAMo@~I=ung9R*07*qoM6N<$f>5askpKVy literal 0 HcmV?d00001 From 7e9b86efe877a4ce8005f0adc2c9c131f156cffe Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 12:55:57 +1100 Subject: [PATCH 11/90] Adding a candelabra. --- code/game/objects/items/candelabra.dm | 54 ++++++++++++++++++ code/game/objects/items/flame/_flame.dm | 4 +- code/game/objects/items/flame/flame_candle.dm | 10 +++- icons/obj/items/candelabra.dmi | Bin 0 -> 355 bytes icons/obj/items/flame/candle.dmi | Bin 1059 -> 1057 bytes nebula.dme | 1 + 6 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 code/game/objects/items/candelabra.dm create mode 100644 icons/obj/items/candelabra.dmi diff --git a/code/game/objects/items/candelabra.dm b/code/game/objects/items/candelabra.dm new file mode 100644 index 000000000000..1f82ec443aa7 --- /dev/null +++ b/code/game/objects/items/candelabra.dm @@ -0,0 +1,54 @@ +/datum/storage/candelabra + can_hold = list(/obj/item/flame/candle) + storage_slots = 3 + var/static/list/candle_offsets = list( + list("x" = -4, "y" = 17), + list("x" = 1, "y" = 19), + list("x" = 6, "y" = 17) + ) + +/datum/storage/candelabra/can_be_inserted(obj/item/W, mob/user, stop_messages, click_params) + . = ..() && holder && length(holder.get_stored_inventory()) < length(candle_offsets) + +/obj/item/candelabra + name = "candelabra" + desc = "A three-tined candle stand." + icon = 'icons/obj/items/candelabra.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/candelabra + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/candelabra/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM) && (used_item.isflamesource() || used_item.get_heat() > T100C)) + for(var/obj/item/flame/candle/candle in contents) + if(!candle.lit && candle.attackby(used_item, user)) + return TRUE + . = ..() + +/obj/item/candelabra/filled/Initialize(ml, material_key) + new /obj/item/flame/candle/random(src) + new /obj/item/flame/candle/random(src) + new /obj/item/flame/candle/random(src) + . = ..() + update_icon() + +// Workaround for vis_contents propagating color. +/obj/item/candelabra/on_update_icon() + ..() + var/datum/storage/candelabra/candles_storage = storage + if(istype(candles_storage)) + var/i = 1 + for(var/obj/item/flame/candle/candle in get_stored_inventory()) + var/offsets = candles_storage.candle_offsets[i] + candle.set_dir(SOUTH) + for(var/image/candle_overlay in candle.get_sconce_overlay()) + candle_overlay.pixel_x = offsets["x"] + candle_overlay.pixel_y = offsets["y"] + candle_overlay.dir = SOUTH + candle_overlay.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(candle_overlay) + i++ + if(i > length(candles_storage.candle_offsets)) + break + compile_overlays() diff --git a/code/game/objects/items/flame/_flame.dm b/code/game/objects/items/flame/_flame.dm index 52c0cb31cc7b..1078285da3b8 100644 --- a/code/game/objects/items/flame/_flame.dm +++ b/code/game/objects/items/flame/_flame.dm @@ -205,9 +205,9 @@ if(!other.can_manually_light) other.light(user) -/obj/item/flame/attackby(obj/item/W, mob/user) +/obj/item/flame/attackby(obj/item/used_item, mob/user) - if(!user.check_intent(I_FLAG_HARM) && !can_manually_light && (W.isflamesource() || W.get_heat() > T100C)) + if(!user.check_intent(I_FLAG_HARM) && !can_manually_light && (used_item.isflamesource() || used_item.get_heat() > T100C)) light(user) return TRUE diff --git a/code/game/objects/items/flame/flame_candle.dm b/code/game/objects/items/flame/flame_candle.dm index dcf647104f65..906824d52bcd 100644 --- a/code/game/objects/items/flame/flame_candle.dm +++ b/code/game/objects/items/flame/flame_candle.dm @@ -41,7 +41,7 @@ /obj/item/flame/candle/get_sconce_overlay() . = list(overlay_image(icon, "[icon_state]-sconce", color = color, flags = RESET_COLOR)) if(lit) - . += overlay_image(icon, "[icon_state]-sconce-lit", color = color, flags = RESET_COLOR) + . += overlay_image(icon, "[icon_state]-sconce-lit", color = COLOR_WHITE, flags = RESET_COLOR) /obj/item/flame/candle/on_update_icon() @@ -63,6 +63,9 @@ // TODO: emissives add_overlay(overlay_image(icon, "[icon_state]_lit", flags = RESET_COLOR)) + if(istype(loc, /obj/item/candelabra)) + loc.queue_icon_update() + /obj/item/flame/candle/proc/get_available_colors() return null @@ -83,6 +86,11 @@ /obj/item/flame/candle/get_available_scents() return null +/obj/item/flame/candle/set_dir(ndir) + if(istype(loc, /obj/item/candelabra)) + ndir = SOUTH + . = ..() + /obj/item/flame/candle/scented name = "scented candle" desc = "A candle which releases pleasant-smelling oils into the air when burned." diff --git a/icons/obj/items/candelabra.dmi b/icons/obj/items/candelabra.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3d0b0010945249def7f6a4317e5a1437c54b48a5 GIT binary patch literal 355 zcmV-p0i6DcP)fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3K9+DJL;6TZxM^C9|j)$T#HTOe;#vO@*-Gs><_=a#C=qQdV&Fa{*fp02BWt+1k96 zrT_o{fk{L`R5*?8kFgSiAP__kA-#v#2N?S(rq2wf*Ma~47U`Yad_de{n|*V8OZ3-L z`~$F|M=|%FpDZIP_{Gk_i$KR#$7Uj+eKf9_{KN7xu9*zz!&Ft|oXp$RaRmV7RMH0l zRE8bqk2p*a_}VbSiuK?MR<@nnmSF{@3=iD8=mcK#3vrzggcm8Cd}N_w0b_bg*^j9?4d`GrrkXH JX0b9OGXOxC7Ayb& delta 55 zcmZ3;v6y2*BIC}9Nwd^hmd`dgJVoVokH*$>Gk}!l)^jZlrKh;o)#*KmVPx>!_4wzj Lz{lo`6&aZU!!sF% diff --git a/nebula.dme b/nebula.dme index 44929d112015..340b6ddc06f4 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1086,6 +1086,7 @@ #include "code\game\objects\items\blueprints.dm" #include "code\game\objects\items\bodybag.dm" #include "code\game\objects\items\buttons.dm" +#include "code\game\objects\items\candelabra.dm" #include "code\game\objects\items\christmas.dm" #include "code\game\objects\items\contraband.dm" #include "code\game\objects\items\crutches.dm" From dc462371a9431bf80853a15dcb7be443a702ecef Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 14:24:29 +1100 Subject: [PATCH 12/90] Adding a small circular rug. --- code/game/objects/structures/rug.dm | 12 ++++++++++++ .../crafting/stack_recipes/recipes_grass.dm | 6 ++++++ .../crafting/stack_recipes/recipes_textiles.dm | 16 +++++++++++----- icons/obj/structures/rug.dmi | Bin 0 -> 352 bytes nebula.dme | 1 + 5 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 code/game/objects/structures/rug.dm create mode 100644 icons/obj/structures/rug.dmi diff --git a/code/game/objects/structures/rug.dm b/code/game/objects/structures/rug.dm new file mode 100644 index 000000000000..b4bf628184f6 --- /dev/null +++ b/code/game/objects/structures/rug.dm @@ -0,0 +1,12 @@ +/obj/structure/rug + name = "rug" + desc = "A small, circular floor covering." + icon = 'icons/obj/structures/rug.dmi' + material = /decl/material/solid/organic/cloth/wool + icon_state = ICON_STATE_WORLD + paint_color = COLOR_GRAY20 + color = COLOR_GRAY20 + +/obj/structure/rug/crafted + paint_color = null + color = null diff --git a/code/modules/crafting/stack_recipes/recipes_grass.dm b/code/modules/crafting/stack_recipes/recipes_grass.dm index d6f262e90bc2..a492af45bb25 100644 --- a/code/modules/crafting/stack_recipes/recipes_grass.dm +++ b/code/modules/crafting/stack_recipes/recipes_grass.dm @@ -8,6 +8,12 @@ return FALSE return ..() +/decl/stack_recipe/woven/rug + result_type = /obj/structure/rug/crafted + one_per_turf = TRUE + on_floor = TRUE + category = "furniture" + /decl/stack_recipe/woven/basket result_type = /obj/item/basket diff --git a/code/modules/crafting/stack_recipes/recipes_textiles.dm b/code/modules/crafting/stack_recipes/recipes_textiles.dm index c43dffe7ce14..b9dba122da80 100644 --- a/code/modules/crafting/stack_recipes/recipes_textiles.dm +++ b/code/modules/crafting/stack_recipes/recipes_textiles.dm @@ -7,9 +7,15 @@ crafting_extra_cost_factor = 1.5 // measure twice, cut once; material is lost. todo: produce scraps? abstract_type = /decl/stack_recipe/textiles +/decl/stack_recipe/textiles/rug + result_type = /obj/structure/rug/crafted + one_per_turf = TRUE + on_floor = TRUE + category = "furniture" + /decl/stack_recipe/textiles/cloak - result_type = /obj/item/clothing/suit/cloak/hide - category = "clothing" + result_type = /obj/item/clothing/suit/cloak/hide + category = "clothing" /decl/stack_recipe/textiles/banner name = "banner" @@ -60,9 +66,9 @@ category = "clothing" /decl/stack_recipe/textiles/leather/bedroll - result_type = /obj/item/bedroll - difficulty = MAT_VALUE_NORMAL_DIY // Slightly easier than making clothing. - category = "bedding" + result_type = /obj/item/bedroll + difficulty = MAT_VALUE_NORMAL_DIY // Slightly easier than making clothing. + category = "bedding" /decl/stack_recipe/textiles/leather/shoes result_type = /obj/item/clothing/shoes/craftable diff --git a/icons/obj/structures/rug.dmi b/icons/obj/structures/rug.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ab64dd8fba6a20b5be1a4790a19316ab78a05240 GIT binary patch literal 352 zcmV-m0iXVfP)i?^ zC?`dUi!&v&s2IpMx4!`(Mp%u<@hb1| ziE$6wxG(dRwefEeN!rj_N|8+k`2{#GMH#LjA{pM0HNl&p-@GxLKvg-LjT&{OB0T@a y+|G|#&wU0%7R^J|2DT6-3n*d%d*ptEc9sjA<$8$FksV_I0000 Date: Sat, 7 Dec 2024 15:11:48 +1100 Subject: [PATCH 13/90] Added several wider pillars. --- code/game/objects/structures/pillar.dm | 11 +++++++++++ .../crafting/stack_recipes/recipes_bricks.dm | 13 +++++++++++++ .../obj/structures/pillars/pillar_wide_inset.dmi | Bin 0 -> 387 bytes .../obj/structures/pillars/pillar_wide_round.dmi | Bin 0 -> 390 bytes .../obj/structures/pillars/pillar_wide_square.dmi | Bin 0 -> 347 bytes 5 files changed, 24 insertions(+) create mode 100644 icons/obj/structures/pillars/pillar_wide_inset.dmi create mode 100644 icons/obj/structures/pillars/pillar_wide_round.dmi create mode 100644 icons/obj/structures/pillars/pillar_wide_square.dmi diff --git a/code/game/objects/structures/pillar.dm b/code/game/objects/structures/pillar.dm index 6f625ac789b5..6c77b5c53792 100644 --- a/code/game/objects/structures/pillar.dm +++ b/code/game/objects/structures/pillar.dm @@ -17,3 +17,14 @@ /obj/structure/pillar/triad icon = 'icons/obj/structures/pillars/pillar_triad.dmi' + +/obj/structure/pillar/wide + name = "wide pillar" + w_class = ITEM_SIZE_LARGE_STRUCTURE + icon = 'icons/obj/structures/pillars/pillar_wide_round.dmi' + +/obj/structure/pillar/wide/square + icon = 'icons/obj/structures/pillars/pillar_wide_square.dmi' + +/obj/structure/pillar/wide/inset + icon = 'icons/obj/structures/pillars/pillar_wide_inset.dmi' diff --git a/code/modules/crafting/stack_recipes/recipes_bricks.dm b/code/modules/crafting/stack_recipes/recipes_bricks.dm index 1901075e8e0d..ec8bf11e3b3b 100644 --- a/code/modules/crafting/stack_recipes/recipes_bricks.dm +++ b/code/modules/crafting/stack_recipes/recipes_bricks.dm @@ -71,6 +71,19 @@ name = "pillar, round" result_type = /obj/structure/pillar/round +/decl/stack_recipe/bricks/furniture/pillar/wide_round + name = "pillar, wide round" + result_type = /obj/structure/pillar/wide + +/decl/stack_recipe/bricks/furniture/pillar/wide_square + name = "pillar, wide square" + + result_type = /obj/structure/pillar/wide/square + +/decl/stack_recipe/bricks/furniture/pillar/wide_inset + name = "pillar, wide inset" + result_type = /obj/structure/pillar/wide/inset + /decl/stack_recipe/bricks/furniture/pillar/pedestal name = "pedestal, square" result_type = /obj/structure/pedestal diff --git a/icons/obj/structures/pillars/pillar_wide_inset.dmi b/icons/obj/structures/pillars/pillar_wide_inset.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8f307cd2eb0b4e4ad7be6734a1be1a50b223b3f8 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvp#Yx{S0LThHSf^Dlb-G|*RJ0B z|NnouyYT^_C}T;GUoeBivm0qZPG(g|M2SmkadJ^+K}lwQ9s@(goZzs6qSEhQf(t%= zeWK;9t99jJaWn(XeIgchCnG~WBywYaBhPrEK zx3TKx6%r@RpFHx>_B!L+x?!ql%-@&;$CwzbnWT&vvb3K9EnVg5;uxYav2;Q&Z?l4c z+g7~`hxH0Lm?hK=jxy$y{14@-VV~2v?}&@t{l6a9?>e-apWCZz&~%VB(aFF{@XnO% zI4uKz$G3`(bAy_eHZ@2++ciDs+Hc>gJn5!_qCA7&$)e52S$?LSkxWf!Gioq02$r;4 z*c+d;{@B6vr1GRASuCkvEd(5EPL}V{C_3==`{%9v3qQ6V{L&f!_^`p6i3esxIhANe fo{X}%eD;RDZn5pj3W2krz-91s^>bP0l+XkKhH{;r literal 0 HcmV?d00001 diff --git a/icons/obj/structures/pillars/pillar_wide_round.dmi b/icons/obj/structures/pillars/pillar_wide_round.dmi new file mode 100644 index 0000000000000000000000000000000000000000..c0625980dd8753fcb66fba404b086387fe7e2d98 GIT binary patch literal 390 zcmV;10eSw3P)fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*+P6 zMdnPMSmN)Hwk%%;E4ZPh#_&{-;g}O*2Qda<$$1!5sGZ56wUmu!V=HC-yJ6MP*WPg% zI1~t6DG8#$R;hp&-z((2$QyKw9f5fnJ8X4r=^myEnvue&)brOD@*Q}*S_M^s5$AYM kNlYK9y!$Dim(^>20RPc0p&`v}N&o-=07*qoM6N<$f)Y=nn*aa+ literal 0 HcmV?d00001 diff --git a/icons/obj/structures/pillars/pillar_wide_square.dmi b/icons/obj/structures/pillars/pillar_wide_square.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a5ea0d80445b27b3f5b3ff849f3e779f4a47951b GIT binary patch literal 347 zcmV-h0i^zkP)fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*+P6ES+`vw;%^cz0PgpMPvYXlYju1a3TX=X%TnjS tNWv9JjOvVmQ*%WpVVf0|N?fV0eE@t%G>Z98YI6Vp002ovPDHLkV1jY6i< Date: Mon, 2 Dec 2024 18:54:24 +1100 Subject: [PATCH 14/90] Adding gemstones and basic gemcutting. --- code/game/turfs/flooring/_flooring.dm | 3 + code/game/turfs/flooring/flooring_grass.dm | 4 + code/game/turfs/floors/floor_digging.dm | 29 +++-- code/game/turfs/turf_digging.dm | 38 ++++-- code/game/turfs/walls/wall_natural.dm | 5 + code/modules/gemstones/_gemstone.dm | 89 ++++++++++++++ code/modules/gemstones/gemstone_cuts.dm | 75 ++++++++++++ code/modules/materials/_materials.dm | 5 + .../solids/materials_solid_gemstones.dm | 111 ++++++++++-------- .../solids/materials_solid_mineral.dm | 2 + .../solids/materials_solid_stone.dm | 2 + code/modules/mechs/equipment/utility.dm | 2 +- code/modules/mining/drilling/drill_act.dm | 2 +- icons/obj/items/gemstones/baguette.dmi | Bin 0 -> 423 bytes icons/obj/items/gemstones/hexagon.dmi | Bin 0 -> 419 bytes icons/obj/items/gemstones/octagon.dmi | Bin 0 -> 445 bytes icons/obj/items/gemstones/poor.dmi | Bin 0 -> 382 bytes icons/obj/items/gemstones/round.dmi | Bin 0 -> 401 bytes icons/obj/items/gemstones/uncut.dmi | Bin 0 -> 538 bytes mods/content/fantasy/datum/skills.dm | 5 +- nebula.dme | 2 + 21 files changed, 303 insertions(+), 71 deletions(-) create mode 100644 code/modules/gemstones/_gemstone.dm create mode 100644 code/modules/gemstones/gemstone_cuts.dm create mode 100644 icons/obj/items/gemstones/baguette.dmi create mode 100644 icons/obj/items/gemstones/hexagon.dmi create mode 100644 icons/obj/items/gemstones/octagon.dmi create mode 100644 icons/obj/items/gemstones/poor.dmi create mode 100644 icons/obj/items/gemstones/round.dmi create mode 100644 icons/obj/items/gemstones/uncut.dmi diff --git a/code/game/turfs/flooring/_flooring.dm b/code/game/turfs/flooring/_flooring.dm index 3fc9cf8adc2e..9d3ce2f33cfd 100644 --- a/code/game/turfs/flooring/_flooring.dm +++ b/code/game/turfs/flooring/_flooring.dm @@ -347,3 +347,6 @@ var/global/list/flooring_cache = list() /decl/flooring/proc/handle_environment_proc(turf/floor/target) return PROCESS_KILL + +/decl/flooring/proc/handle_turf_digging(turf/floor/target) + return TRUE diff --git a/code/game/turfs/flooring/flooring_grass.dm b/code/game/turfs/flooring/flooring_grass.dm index 802c509f5738..a9e70bbf7368 100644 --- a/code/game/turfs/flooring/flooring_grass.dm +++ b/code/game/turfs/flooring/flooring_grass.dm @@ -21,6 +21,10 @@ return TRUE return ..() +/decl/flooring/grass/handle_turf_digging(turf/floor/target) + target.set_flooring(null) + return FALSE + /decl/flooring/grass/wild name = "wild grass" icon = 'icons/turf/flooring/wildgrass.dmi' diff --git a/code/game/turfs/floors/floor_digging.dm b/code/game/turfs/floors/floor_digging.dm index 4262e953ad82..3351970e8af6 100644 --- a/code/game/turfs/floors/floor_digging.dm +++ b/code/game/turfs/floors/floor_digging.dm @@ -1,3 +1,6 @@ +/turf/floor + var/gemstone_dropped = FALSE + /turf/floor/proc/is_fundament() var/decl/flooring/flooring = get_topmost_flooring() return flooring ? !flooring.constructed : TRUE @@ -23,21 +26,31 @@ /turf/floor/can_dig_trench(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return can_be_dug(tool_hardness, using_tool) && get_physical_height() > -(FLUID_DEEP) -/turf/floor/dig_trench(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) - if(!is_fundament()) +/turf/floor/dig_trench(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + if(is_fundament()) + handle_trench_digging(user) + +/turf/floor/proc/handle_trench_digging(mob/user) + var/decl/flooring/flooring = get_topmost_flooring() + if(!flooring.handle_turf_digging(src)) return - var/new_height = max(get_physical_height()-TRENCH_DEPTH_PER_ACTION, -(FLUID_DEEP)) - var/height_diff = abs(get_physical_height()-new_height) // Only drop mats if we actually changed the turf height sufficiently. + var/old_height = get_physical_height() + var/new_height = max(old_height-TRENCH_DEPTH_PER_ACTION, -(FLUID_DEEP)) + var/height_diff = abs(old_height-new_height) if(height_diff >= TRENCH_DEPTH_PER_ACTION) - drop_diggable_resources() + drop_diggable_resources(user) set_physical_height(new_height) -/turf/floor/dig_pit(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) +/turf/floor/dig_pit(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return has_flooring() ? null : ..() /turf/floor/get_diggable_resources() var/decl/material/my_material = get_material() if(is_fundament() && istype(my_material) && my_material.dug_drop_type && (get_physical_height() > -(FLUID_DEEP))) - return list(my_material.dug_drop_type = list(3, 2)) - return null + . = list() + .[my_material.dug_drop_type] = list("amount" = 3, "variance" = 2, "material" = my_material.type) + if(!gemstone_dropped && prob(my_material.gemstone_chance) && LAZYLEN(my_material.gemstone_types)) + gemstone_dropped = TRUE + var/gem_mat = pick(my_material.gemstone_types) + .[/obj/item/gemstone] = list("amount" = 1, "material" = gem_mat) diff --git a/code/game/turfs/turf_digging.dm b/code/game/turfs/turf_digging.dm index 6eea34afe2e0..5f832ae8045c 100644 --- a/code/game/turfs/turf_digging.dm +++ b/code/game/turfs/turf_digging.dm @@ -1,5 +1,5 @@ -/// Return an assoc list of resource item type to a base and a random component -/// ex. return list(/obj/item/stack/material/ore/handful/sand = list(3, 2)) +/// Return an assoc list of resource item type to a metadata list containing base amount, random component, and material override +/// ex. return list(/obj/item/stack/material/ore/handful/sand = list("amount" = 3, "variance" = 2, "material" = /decl/material/foo)) /turf/proc/get_diggable_resources() return null @@ -10,17 +10,31 @@ /turf/proc/can_be_dug(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return FALSE -/turf/proc/drop_diggable_resources() +/turf/proc/drop_diggable_resources(mob/user) SHOULD_CALL_PARENT(TRUE) var/list/diggable_resources = get_diggable_resources() if(!length(diggable_resources)) return for(var/resource_type in diggable_resources) - var/list/resource_amounts = diggable_resources[resource_type] + + var/list/resource_data = diggable_resources[resource_type] + var/list/loot = list() + var/amount = max(1, resource_data["amount"] + resource_data["variance"]) + var/spawn_material = resource_data["material"] + if(ispath(resource_type, /obj/item/stack)) - LAZYADD(., new resource_type(src, resource_amounts[1] + rand(resource_amounts[2]), get_material_type())) + loot += new resource_type(src, amount, spawn_material) else - LAZYADD(., new resource_type(src, get_material_type())) + for(var/i = 1 to amount) + loot += new resource_type(src, spawn_material) + + if(length(loot)) + if(user) + for(var/obj/item/thing in loot) + if(thing.material && thing.material != get_material()) + to_chat(user, SPAN_NOTICE("You unearth \a [thing]!")) + LAZYADD(., loot) + clear_diggable_resources() // Procs for digging pits. @@ -29,10 +43,10 @@ /turf/proc/try_dig_pit(var/mob/user, var/obj/item/tool, using_tool = TOOL_SHOVEL) if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 5 SECONDS, check_skill = SKILL_HAULING, set_cooldown = TRUE)) - return dig_pit(tool?.material?.hardness, using_tool) + return dig_pit(user, tool?.material?.hardness, using_tool) return null -/turf/proc/dig_pit(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) +/turf/proc/dig_pit(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return can_dig_pit(tool_hardness, using_tool) && new /obj/structure/pit(src) // Procs for digging farms. @@ -44,10 +58,10 @@ if(!material?.tillable) return if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 5 SECONDS, set_cooldown = TRUE, check_skill = SKILL_BOTANY)) - return dig_farm(tool?.material?.hardness, using_tool) + return dig_farm(user, tool?.material?.hardness, using_tool) return null -/turf/proc/dig_farm(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) +/turf/proc/dig_farm(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return can_dig_farm(tool_hardness, using_tool) && new /obj/machinery/portable_atmospherics/hydroponics/soil(src) // Proc for digging trenches. @@ -56,8 +70,8 @@ /turf/proc/try_dig_trench(mob/user, obj/item/tool, using_tool = TOOL_SHOVEL) if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 2.5 SECONDS, check_skill = SKILL_HAULING, set_cooldown = TRUE)) - return dig_trench(tool?.material?.hardness, using_tool) + return dig_trench(user, tool?.material?.hardness, using_tool) return null -/turf/proc/dig_trench(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) +/turf/proc/dig_trench(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) return FALSE diff --git a/code/game/turfs/walls/wall_natural.dm b/code/game/turfs/walls/wall_natural.dm index e878e59747e5..96967f55e2ef 100644 --- a/code/game/turfs/walls/wall_natural.dm +++ b/code/game/turfs/walls/wall_natural.dm @@ -10,6 +10,7 @@ var/image/ore_overlay var/static/list/exterior_wall_shine_cache = list() var/being_mined = FALSE + var/gem_dropped = FALSE /turf/wall/natural/flooded flooded = /decl/material/liquid/water @@ -150,6 +151,10 @@ if(prob(30) && !ramp_slope_direction && material) var/drop_type = material.ore_type || /obj/item/stack/material/ore pass_geodata_to(new drop_type(src, material.ore_result_amount, material.type)) + if(!gem_dropped && material && prob(material.gemstone_chance) && LAZYLEN(material.gemstone_types)) + gem_dropped = TRUE + new /obj/item/gemstone(get_turf(src), pickweight(material.gemstone_types)) + visible_message(SPAN_NOTICE("A glimmer of colour shines amongst the rubble...")) /turf/wall/natural/proc/pass_geodata_to(obj/O) var/datum/extension/geological_data/ours = get_extension(src, /datum/extension/geological_data) diff --git a/code/modules/gemstones/_gemstone.dm b/code/modules/gemstones/_gemstone.dm new file mode 100644 index 000000000000..087266d34f89 --- /dev/null +++ b/code/modules/gemstones/_gemstone.dm @@ -0,0 +1,89 @@ +var/global/list/_available_gemstone_cuts + +/proc/get_available_gemstone_cuts() + if(!global._available_gemstone_cuts) + global._available_gemstone_cuts = list() + for(var/decl/gemstone_cut/cut as anything in decls_repository.get_decls_of_type_unassociated(/decl/gemstone_cut)) + if(cut.can_be_cut) + global._available_gemstone_cuts += cut + return global._available_gemstone_cuts + +/obj/item/gemstone + name = "uncut gemstone" + desc = "A hunk of uncut gemstone." + icon = 'icons/obj/items/gemstones/uncut.dmi' + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/gemstone/diamond + material_alteration = MAT_FLAG_ALTERATION_COLOR // Name and desc are handled manually. + var/decl/gemstone_cut/cut = /decl/gemstone_cut/uncut + var/work_skill = SKILL_CONSTRUCTION + +/obj/item/gemstone/Initialize(ml, material_key) + cut = GET_DECL(cut) + . = ..() + update_from_cut() + +/obj/item/gemstone/proc/update_from_cut() + icon = cut.icon + desc = cut.desc + update_name() + update_icon() + +/obj/item/gemstone/update_name() + SetName("[cut.adjective] [material.solid_name]") + +/obj/item/gemstone/get_single_monetary_worth() + . = ..() * cut.worth_multiplier + +/obj/item/gemstone/attackby(obj/item/used_item, mob/user) + if(IS_HAMMER(used_item) && !user.check_intent(I_FLAG_HARM)) // TOOL_CHISEL when? + if(!cut.can_attempt_cut) + to_chat(user, SPAN_WARNING("\The [src] has already been cut.")) + return TRUE + var/decl/gemstone_cut/desired_cut = input(user, "What cut would you like to attempt?", "Cut Gemstone") as null|anything in get_available_gemstone_cuts() + if(!desired_cut || QDELETED(src) || QDELETED(user) || !CanPhysicallyInteract(user) || !cut.can_attempt_cut) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] begins carefully cutting \the [src].")) + if(!user.do_skilled(10 SECONDS, work_skill, src, check_holding = TRUE) || !CanPhysicallyInteract(user)) + if(QDELETED(src) || !cut.can_attempt_cut || QDELETED(user)) + return TRUE + to_chat(user, SPAN_DANGER("You were interrupted, botching the cut!")) + cut = GET_DECL(/decl/gemstone_cut/poor) + else + if(QDELETED(src) || !cut.can_attempt_cut || QDELETED(user)) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] finishes cutting \the [src].")) + if(user.skill_fail_prob(work_skill, 100, SKILL_EXPERT)) + to_chat(user, SPAN_DANGER("You've done a really poor job...")) + cut = GET_DECL(/decl/gemstone_cut/poor) + else + cut = desired_cut + update_from_cut() + return TRUE + . = ..() + +// Subtypes for mapping/spawning etc. +/obj/item/gemstone/poor + name = "poorly-cut diamond" + cut = /decl/gemstone_cut/poor + icon = 'icons/obj/items/gemstones/poor.dmi' + +/obj/item/gemstone/baguette + name = "baguette-cut diamond" + cut = /decl/gemstone_cut/baguette + icon = 'icons/obj/items/gemstones/baguette.dmi' + +/obj/item/gemstone/hexagon + name = "hexagon-cut diamond" + cut = /decl/gemstone_cut/hexagon + icon = 'icons/obj/items/gemstones/hexagon.dmi' + +/obj/item/gemstone/octagon + name = "octagon-cut diamond" + cut = /decl/gemstone_cut/octagon + icon = 'icons/obj/items/gemstones/octagon.dmi' + +/obj/item/gemstone/round + name = "round-cut diamond" + cut = /decl/gemstone_cut/round + icon = 'icons/obj/items/gemstones/round.dmi' diff --git a/code/modules/gemstones/gemstone_cuts.dm b/code/modules/gemstones/gemstone_cuts.dm new file mode 100644 index 000000000000..86509cc2c177 --- /dev/null +++ b/code/modules/gemstones/gemstone_cuts.dm @@ -0,0 +1,75 @@ +/decl/gemstone_cut + abstract_type = /decl/gemstone_cut + var/worth_multiplier = 1.5 + var/name + var/desc + var/adjective + var/icon + // Can we cut this cut into a new cut? + var/can_attempt_cut = FALSE + // Can we attempt to cut to this cut? + var/can_be_cut = TRUE + +/decl/gemstone_cut/validate() + . = ..() + if(!istext(name)) + . += "invalid or null name" + if(!istext(desc)) + . += "invalid or null desc" + if(!istext(adjective)) + . += "invalid or null adjective" + if(icon) + if(!check_state_in_icon(ICON_STATE_WORLD, icon)) + . += "missing world state from '[icon]'" + if(!check_state_in_icon(ICON_STATE_INV, icon)) + . += "missing inventory state from '[icon]'" + var/check_state = "[ICON_STATE_WORLD]-set" + if(!check_state_in_icon(check_state, icon)) + . += "missing state '[check_state]' from '[icon]'" + check_state = "[ICON_STATE_INV]-set" + if(!check_state_in_icon(check_state, icon)) + . += "missing state '[check_state]' from '[icon]'" + else + . += "null or unset icon" + +// Subtypes below. +/decl/gemstone_cut/uncut + name = "uncut" + adjective = "uncut" + desc = "A rough, uncut gemstone." + icon = 'icons/obj/items/gemstones/uncut.dmi' + can_attempt_cut = TRUE + can_be_cut = FALSE + worth_multiplier = 1 + +/decl/gemstone_cut/poor + name = "poorly-cut" + adjective = "poorly-cut" + desc = "A poorly-cut and uneven gemstone." + icon = 'icons/obj/items/gemstones/poor.dmi' + worth_multiplier = 0.5 + can_be_cut = FALSE + +/decl/gemstone_cut/baguette + name = "baguette" + adjective = "baguette-cut" + desc = "A square-cut gemstone." + icon = 'icons/obj/items/gemstones/baguette.dmi' + +/decl/gemstone_cut/hexagon + name = "hexagon" + adjective = "hexagon-cut" + desc = "A hexagon-cut gemstone." + icon = 'icons/obj/items/gemstones/hexagon.dmi' + +/decl/gemstone_cut/octagon + name = "octagon" + adjective = "octagon-cut" + desc = "A octagon-cut gemstone." + icon = 'icons/obj/items/gemstones/octagon.dmi' + +/decl/gemstone_cut/round + name = "round" + adjective = "round-cut" + desc = "A round-cut gemstone." + icon = 'icons/obj/items/gemstones/round.dmi' diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm index 01aa188e0cc5..4b12ce62dee1 100644 --- a/code/modules/materials/_materials.dm +++ b/code/modules/materials/_materials.dm @@ -363,6 +363,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) /// If an item has a null paint_verb, it automatically sets it based on material. var/paint_verb = "painted" + /// Chance of a natural wall made of this material dropping a gemstone, if the gemstone_types list is populated. + var/gemstone_chance = 5 + /// Assoc weighted list of gemstone material types to weighting. + var/list/gemstone_types + // Placeholders for light tiles and rglass. /decl/material/proc/reinforce(var/mob/user, var/obj/item/stack/material/used_stack, var/obj/item/stack/material/target_stack, var/use_sheets = 1) if(!used_stack.can_use(use_sheets)) diff --git a/code/modules/materials/definitions/solids/materials_solid_gemstones.dm b/code/modules/materials/definitions/solids/materials_solid_gemstones.dm index f0718ad4ccfe..dcb3b5d38a62 100644 --- a/code/modules/materials/definitions/solids/materials_solid_gemstones.dm +++ b/code/modules/materials/definitions/solids/materials_solid_gemstones.dm @@ -1,54 +1,69 @@ /decl/material/solid/gemstone - name = null - flags = MAT_FLAG_UNMELTABLE - cut_delay = 60 - color = COLOR_DIAMOND - opacity = 0.4 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - reflectiveness = MAT_VALUE_MIRRORED - conductive = 0 - ore_icon_overlay = "gems" - default_solid_form = /obj/item/stack/material/gemstone - abstract_type = /decl/material/solid/gemstone - sound_manipulate = 'sound/foley/pebblespickup1.ogg' - sound_dropped = 'sound/foley/pebblesdrop1.ogg' + flags = MAT_FLAG_UNMELTABLE + cut_delay = 60 + color = COLOR_DIAMOND + opacity = 0.4 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + conductive = 0 + ore_icon_overlay = "gems" + default_solid_form = /obj/item/stack/material/gemstone + abstract_type = /decl/material/solid/gemstone + sound_manipulate = 'sound/foley/pebblespickup1.ogg' + sound_dropped = 'sound/foley/pebblesdrop1.ogg' + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null + hardness = MAT_VALUE_VERY_HARD + reflectiveness = MAT_VALUE_VERY_SHINY + construction_difficulty = MAT_VALUE_VERY_HARD_DIY /decl/material/solid/gemstone/diamond - name = "diamond" - uid = "solid_diamond" - lore_text = "An extremely hard allotrope of carbon. Valued for its use in industrial tools." - melting_point = 4300 - boiling_point = null - ignition_point = null - brute_armor = 10 - burn_armor = 50 // Diamond walls are immune to fire, therefore it makes sense for them to be almost undamageable by burn damage type. - stack_origin_tech = @'{"materials":6}' - hardness = MAT_VALUE_VERY_HARD + 20 - construction_difficulty = MAT_VALUE_VERY_HARD_DIY - ore_name = "rough diamonds" - ore_result_amount = 1 - ore_spread_chance = 10 - ore_scan_icon = "mineral_rare" - xarch_source_mineral = /decl/material/gas/ammonia - value = 1.8 - sparse_material_weight = 5 - rich_material_weight = 5 - ore_type_value = ORE_PRECIOUS - ore_data_value = 2 - exoplanet_rarity_plant = MAT_RARITY_UNCOMMON - exoplanet_rarity_gas = MAT_RARITY_NOWHERE - dissolves_in = MAT_SOLVENT_IMMUNE - dissolves_into = null + name = "diamond" + uid = "solid_diamond" + lore_text = "An extremely hard allotrope of carbon. Valued for its use in industrial tools." + melting_point = 4300 + boiling_point = null + ignition_point = null + brute_armor = 10 + burn_armor = 50 // Diamond walls are immune to fire, therefore it makes sense for them to be almost undamageable by burn damage type. + stack_origin_tech = @'{"materials":6}' + hardness = MAT_VALUE_VERY_HARD + 20 + ore_name = "rough diamonds" + ore_result_amount = 1 + ore_spread_chance = 10 + ore_scan_icon = "mineral_rare" + xarch_source_mineral = /decl/material/gas/ammonia + value = 1.8 + sparse_material_weight = 5 + rich_material_weight = 5 + ore_type_value = ORE_PRECIOUS + ore_data_value = 2 /decl/material/solid/gemstone/crystal - name = "crystal" - uid = "solid_crystal" - hardness = MAT_VALUE_VERY_HARD - reflectiveness = MAT_VALUE_VERY_SHINY + name = "crystal" + uid = "solid_crystal" + value = 2 hidden_from_codex = TRUE - value = 2 - exoplanet_rarity_plant = MAT_RARITY_UNCOMMON - exoplanet_rarity_gas = MAT_RARITY_NOWHERE - dissolves_in = MAT_SOLVENT_IMMUNE - dissolves_into = null + +/decl/material/solid/gemstone/ruby + name = "ruby" + lore_text = "A rich red stone sometimes found in marble." + uid = "solid_ruby" + value = 1.6 + color = "#d00000" + +/decl/material/solid/gemstone/sapphire + name = "sapphire" + lore_text = "A deep blue gemstone sometimes found in clay or other sediment." + uid = "solid_sapphite" + value = 1.6 + color = "#2983de" + +/decl/material/solid/gemstone/topaz + name = "topaz" + lore_text = "A golden gemstone sometimes found in granite." + uid = "solid_topaz" + value = 1.6 + color = "#f7b92d" diff --git a/code/modules/materials/definitions/solids/materials_solid_mineral.dm b/code/modules/materials/definitions/solids/materials_solid_mineral.dm index 2be84c6c5df9..3dea5d14d81e 100644 --- a/code/modules/materials/definitions/solids/materials_solid_mineral.dm +++ b/code/modules/materials/definitions/solids/materials_solid_mineral.dm @@ -258,6 +258,8 @@ // lower than the temperature expected from a kiln so that clay can be used to make bricks to make a high-temperature kiln. bakes_into_at_temperature = 950 CELSIUS can_backfill_turf_type = /turf/floor/clay + gemstone_chance = 0.01 + gemstone_types = list(/decl/material/solid/gemstone/sapphire = 1) /decl/material/solid/soil name = "soil" diff --git a/code/modules/materials/definitions/solids/materials_solid_stone.dm b/code/modules/materials/definitions/solids/materials_solid_stone.dm index 6334b03f1b8e..acf1e65ed86f 100644 --- a/code/modules/materials/definitions/solids/materials_solid_stone.dm +++ b/code/modules/materials/definitions/solids/materials_solid_stone.dm @@ -51,6 +51,7 @@ brute_armor = 15 explosion_resistance = 15 integrity = 500 //granite is very strong + gemstone_types = list(/decl/material/solid/gemstone/topaz = 1) dissolves_into = list( /decl/material/solid/silicon = 0.75, /decl/material/solid/bauxite = 0.15, @@ -88,6 +89,7 @@ brute_armor = 3 integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system construction_difficulty = MAT_VALUE_HARD_DIY + gemstone_types = list(/decl/material/solid/gemstone/ruby = 1) /decl/material/solid/stone/basalt name = "basalt" diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm index f645599c8ac1..f76503b97bbf 100644 --- a/code/modules/mechs/equipment/utility.dm +++ b/code/modules/mechs/equipment/utility.dm @@ -517,7 +517,7 @@ for(var/turf/asteroid as anything in RANGE_TURFS(target, 1)) if (!(get_dir(owner, asteroid) & owner.dir)) continue - if(asteroid.can_be_dug(drill_head.material?.hardness) && asteroid.drop_diggable_resources()) + if(asteroid.can_be_dug(drill_head.material?.hardness) && asteroid.drop_diggable_resources(user)) drill_head.durability -= 1 scoop_ore(asteroid) return diff --git a/code/modules/mining/drilling/drill_act.dm b/code/modules/mining/drilling/drill_act.dm index 6a17a4c5b534..39759df1a4c2 100644 --- a/code/modules/mining/drilling/drill_act.dm +++ b/code/modules/mining/drilling/drill_act.dm @@ -1,7 +1,7 @@ /turf/proc/drill_act() SHOULD_CALL_PARENT(TRUE) drop_diggable_resources() - dig_pit(MAT_VALUE_VERY_HARD) + dig_pit(tool_hardness = MAT_VALUE_VERY_HARD) var/base_turf = get_base_turf_by_area(src) if(!istype(src, base_turf)) return ChangeTurf(base_turf) diff --git a/icons/obj/items/gemstones/baguette.dmi b/icons/obj/items/gemstones/baguette.dmi new file mode 100644 index 0000000000000000000000000000000000000000..1fecb840ccbf5ded0e5e05be39e759c59eaaae30 GIT binary patch literal 423 zcmV;Y0a*TtP)fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3K9+Gp{T)uOz>yQi+Q*C9|j)C}zmTnO2mTn+jpWRhH)$<)jc)1vgK(IJJa0Gx4cZ zR&e!m0ecJpTK_=<$43C`0002CNklz<=fH%o}n5;R(};BJ66nX~yHcCTpUcq72-0cXy9%Lm0?6pg)T RrF;MY002ovPDHLkV1g8@vlIXT literal 0 HcmV?d00001 diff --git a/icons/obj/items/gemstones/hexagon.dmi b/icons/obj/items/gemstones/hexagon.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8b9b72ab45371ba64bd05443aa8b344dbc7aa05e GIT binary patch literal 419 zcmV;U0bKrxP)V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zDKoDuHLoPUs8WfGGbOXA7$|1Q#hF%=n41b=!&R2&7v-c7R0TIrw>Y(gI5Y97R90~H za{+q{09yY+1II@I>i_@%wMj%lR7i>KltC7QAPfbea)1IJpuBJZ6Fq>~``@W{$B%tx zZ~eO@lL0n3_g{G$b6*S~$+^N)Mupb`E~rQ-^pp}PJfU!?g)4OpVVMBPG3MMgSQvmn zg{gLpZQE95U^KLbhFW6n4I=6eW8|?nwASE=unT+{kHUK6=F;@fNtbmsS{9DzBKT8RQtO1?X0`A=Tl@DZJ5|aXjh!X$+ N002ovPDHLkV1hDUtkwVk literal 0 HcmV?d00001 diff --git a/icons/obj/items/gemstones/octagon.dmi b/icons/obj/items/gemstones/octagon.dmi new file mode 100644 index 0000000000000000000000000000000000000000..06b5d8617572be65c905bcee8a4f6b25db21fda6 GIT binary patch literal 445 zcmV;u0Yd(XP)p8x;V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zDKoDuHLoPUs8WfGGbOXA7$|1Q#hF%=n41b=!&R2&7v-c7R0TIrw>Y(gI5Y97R90~H za{+q{09yY+1II@I>i_@%&q+iKl*)-z0j`1V9a@2Uvoh61;B*B8b@IGXP0py nJ%$~(&Q{t7nB9^)cfRHg>yH^c0zk}a00000NkvXXu0mjfGR?Zi literal 0 HcmV?d00001 diff --git a/icons/obj/items/gemstones/poor.dmi b/icons/obj/items/gemstones/poor.dmi new file mode 100644 index 0000000000000000000000000000000000000000..95fb0bb44f4e3fae2f36829be265e99c5e107d0e GIT binary patch literal 382 zcmV-^0fGLBP)V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zDKoDuHLoPUs8WfGGbOXA7$|1Q#hF%=n41b=!&R2&7v-c7R0TIrw>Y(gI5Y97R90~H za{+q{09yY+1II@I>i_@%kV!;AR7i>KlfezcAPfKKuUb_3Fc&7~KhVcQbhWi6pt0_2l~lwJjF#bs`X3p{Nteu=Bz`;cw{i cjY;w+Z;A8@xVZmdk^lez07*qoM6N<$g0dl?b^rhX literal 0 HcmV?d00001 diff --git a/icons/obj/items/gemstones/round.dmi b/icons/obj/items/gemstones/round.dmi new file mode 100644 index 0000000000000000000000000000000000000000..12517ea0b4f5358688b42a8bc61a44ee8f38d4e0 GIT binary patch literal 401 zcmV;C0dD?@P)fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3K9+Gp{T)uOz>yQi+Q*C9|j)C}zmTnO2mTn+jpWRhH)$<)jc)1vgK(IJJa0Gx4cZ zR&e!m0ecJpTK_=<$43C`0001>NklH1vqxoL$SXkyLiM*w{N0 z_qBNJsTU9t8%c!_eBUt0?|^361YoV@0ljU!4!r&-PPqnsQBNlKQ2rt??7gNCe00DGTPE!Ct=GbNc004n{R9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3K9+Gp{T)uOz>yQi+Q*C9|j)C}zmTnO2mTn+jpWRhH)$<)jc)1vgK(IJJa0Gx4cZ zR&e!m0ecJpTK_=<$43C`0003gNkl=Hp3`N1o_K`4s6gdX~a)7XF_wfw6 z|5d^!g=Nngr%37FA>KTs8NitT%FDsNg#!RxTVdISCV|ntg{FWprG^4ya;64z2Ev4jm&^-_jh+Y{2#dihV zTL3DefQV{kBSsH?EK3RdSp&eBr7sF_189Jla+YaYN>q&sz(8Z)i!xk6;}#?2oQoRM zmQf$U2-176fXgImXqyOTnYF zH2@$mtQfCm8P{p<2;nAcy_6K@UrZJYaB*#MW#b?CBb$Ib`9 cnKKXb4eT5(mk}vo3IG5A07*qoM6N<$g0WZT2LJ#7 literal 0 HcmV?d00001 diff --git a/mods/content/fantasy/datum/skills.dm b/mods/content/fantasy/datum/skills.dm index 164ade162b6d..f800e76d7be3 100644 --- a/mods/content/fantasy/datum/skills.dm +++ b/mods/content/fantasy/datum/skills.dm @@ -73,7 +73,7 @@ /decl/skill/crafting/artifice name = "Artifice" uid = "skill_crafting_artifice" - desc = "Your ability to create, install, and comprehend complex devices and mechanisms, as well as your ability to create finely-detailed objects." + desc = "Your ability to create, install, and comprehend complex devices and mechanisms, as well as your ability to create finely-detailed objects like cut gems or jewellery." levels = list( "Unskilled" = "You know that gears turn together when intermeshed and that axles are used to connect spinning things, but you've never done more work on a machine than hitting it if it's broken. You struggle with the precision needed to work on finely-detailed objects.", "Basic" = "You know some basic mechanical principles, like the construction of a basic pulley, or how to put a wheel on an axle. You could fix a broken or stuck well winch, but you'd struggle to deal with a malfunctioning windmill or granary. You have a steadier hand than most, able to place small gems on jewelry and connect small mechanisms.", @@ -306,3 +306,6 @@ "Experienced" = "You work as an pharmacist, or else you are a doctor with training in chemistry. If you are a pharmacist, you can make most medications. At this stage, you're working mostly by-the-book.
- You can examine held containers for some reagents.", "Master" = "You specialized in chemistry or pharmaceuticals; you are either a medical researcher or professional chemist. You can create custom mixes and make even the trickiest of medications easily. You understand how your pharmaceuticals interact with the bodies of your patients. You are probably the originator of at least one new chemical innovation.
- You can examine held containers for all reagents." ) + +/obj/item/gemstone + work_skill = SKILL_ARTIFICE diff --git a/nebula.dme b/nebula.dme index 44929d112015..63eab7de9d32 100644 --- a/nebula.dme +++ b/nebula.dme @@ -2456,6 +2456,8 @@ #include "code\modules\games\cards_cag.dm" #include "code\modules\games\spaceball_cards.dm" #include "code\modules\games\tarot.dm" +#include "code\modules\gemstones\_gemstone.dm" +#include "code\modules\gemstones\gemstone_cuts.dm" #include "code\modules\genetics\_gene.dm" #include "code\modules\genetics\plants\_gene_plant.dm" #include "code\modules\genetics\plants\_plant_trait.dm" From 8ca797128c29392912434ab828dee6ac53b11640 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Thu, 5 Dec 2024 14:23:41 +1100 Subject: [PATCH 15/90] Removed deity mode. --- code/modules/species/outsider/shadow.dm | 48 - code/modules/species/outsider/starlight.dm | 153 --- maps/exodus/exodus.dm | 1 - maps/exodus/exodus_antagonism.dm | 9 - maps/modpack_testing/modpack_testing.dm | 1 - maps/tradeship/tradeship.dm | 1 - mods/gamemodes/cult/_cult.dme | 4 - mods/gamemodes/cult/ghosttrap.dm | 6 - mods/gamemodes/cult/items.dm | 2 +- mods/gamemodes/deity/_defines.dm | 19 - mods/gamemodes/deity/_deity.dm | 2 - mods/gamemodes/deity/_deity.dme | 80 -- mods/gamemodes/deity/codex.dm | 38 - mods/gamemodes/deity/deity_base.dm | 14 - mods/gamemodes/deity/deity_base.dmm | 1035 ----------------- mods/gamemodes/deity/deity_role.dm | 15 - .../deity/extensions/deity_be_near.dm | 67 -- mods/gamemodes/deity/forms/forms.dm | 48 - .../deity/forms/narsie/deity_items/basic.dm | 34 - .../deity/forms/narsie/deity_items/minions.dm | 37 - .../forms/narsie/deity_items/sacrificing.dm | 42 - .../forms/narsie/deity_items/smithing.dm | 29 - mods/gamemodes/deity/forms/narsie/items.dm | 77 -- mods/gamemodes/deity/forms/narsie/narsie.dm | 51 - .../deity/forms/narsie/spells/tear_veil.dm | 37 - .../deity/forms/narsie/structures.dm | 36 - .../forms/starlight/deity_items/artifacts.dm | 32 - .../forms/starlight/deity_items/phenomena.dm | 41 - .../forms/starlight/deity_items/spells.dm | 62 - mods/gamemodes/deity/forms/starlight/items.dm | 159 --- mods/gamemodes/deity/forms/starlight/mobs.dm | 29 - .../forms/starlight/spells/disable_tech.dm | 4 - .../forms/starlight/spells/starlight_aura.dm | 5 - .../forms/starlight/spells/veil_of_shadows.dm | 57 - .../deity/forms/starlight/starlight.dm | 47 - .../deity/forms/starlight/structures.dm | 272 ----- .../forms/tower/deity_items/conjuration.dm | 107 -- .../forms/tower/deity_items/transmutation.dm | 97 -- mods/gamemodes/deity/forms/tower/spells.dm | 67 -- .../gamemodes/deity/forms/tower/structures.dm | 25 - mods/gamemodes/deity/forms/tower/tower.dm | 49 - mods/gamemodes/deity/gamemode.dm | 12 - mods/gamemodes/deity/god_cultist_role.dm | 106 -- mods/gamemodes/deity/mobs/deity.dm | 134 --- mods/gamemodes/deity/mobs/deity_Stat.dm | 14 - mods/gamemodes/deity/mobs/deity_boons.dm | 54 - mods/gamemodes/deity/mobs/deity_click.dm | 24 - mods/gamemodes/deity/mobs/deity_hud.dm | 9 - mods/gamemodes/deity/mobs/deity_items.dm | 33 - mods/gamemodes/deity/mobs/deity_phenomena.dm | 94 -- mods/gamemodes/deity/mobs/deity_power.dm | 21 - mods/gamemodes/deity/mobs/deity_pylon.dm | 21 - mods/gamemodes/deity/mobs/deity_sources.dm | 84 -- mods/gamemodes/deity/mobs/deity_topic.dm | 56 - mods/gamemodes/deity/mobs/deity_tracking.dm | 40 - mods/gamemodes/deity/mobs/freelook/cultnet.dm | 13 - mods/gamemodes/deity/mobs/freelook/mask.dm | 11 - .../deity/mobs/items/blood_crafting.dm | 19 - mods/gamemodes/deity/mobs/items/deity_item.dm | 39 - mods/gamemodes/deity/mobs/items/general.dm | 26 - mods/gamemodes/deity/mobs/items/generic.dm | 25 - mods/gamemodes/deity/mobs/menu/deity_nano.dm | 81 -- .../deity/mobs/phenomena/_defines.dm | 4 - .../deity/mobs/phenomena/communication.dm | 80 -- .../deity/mobs/phenomena/conjuration.dm | 67 -- .../deity/mobs/phenomena/conversion.dm | 51 - .../gamemodes/deity/mobs/phenomena/generic.dm | 36 - mods/gamemodes/deity/mobs/phenomena/narsie.dm | 37 - .../deity/mobs/phenomena/phenomena.dm | 75 -- .../deity/mobs/phenomena/starlight.dm | 232 ---- .../deity/mobs/phenomena/transmutation.dm | 26 - mods/gamemodes/deity/mobs/say.dm | 9 - mods/gamemodes/deity/overrides.dm | 27 - mods/gamemodes/deity/screen/intent.dm | 45 - mods/gamemodes/deity/spells/boon.dm | 11 - mods/gamemodes/deity/spells/construction.dm | 55 - mods/gamemodes/deity/spells/open_gateway.dm | 34 - mods/gamemodes/deity/spells/vision.dm | 21 - mods/gamemodes/deity/structures/altar.dm | 106 -- .../gamemodes/deity/structures/blood_forge.dm | 66 -- mods/gamemodes/deity/structures/pylon.dm | 75 -- mods/gamemodes/deity/structures/structures.dm | 68 -- mods/gamemodes/deity/structures/trap.dm | 30 - nano/templates/deity.tmpl | 116 -- nebula.dme | 2 - test/check-paths.sh | 2 +- 86 files changed, 2 insertions(+), 5128 deletions(-) delete mode 100644 code/modules/species/outsider/shadow.dm delete mode 100644 code/modules/species/outsider/starlight.dm delete mode 100644 mods/gamemodes/deity/_defines.dm delete mode 100644 mods/gamemodes/deity/_deity.dm delete mode 100644 mods/gamemodes/deity/_deity.dme delete mode 100644 mods/gamemodes/deity/codex.dm delete mode 100644 mods/gamemodes/deity/deity_base.dm delete mode 100644 mods/gamemodes/deity/deity_base.dmm delete mode 100644 mods/gamemodes/deity/deity_role.dm delete mode 100644 mods/gamemodes/deity/extensions/deity_be_near.dm delete mode 100644 mods/gamemodes/deity/forms/forms.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/deity_items/basic.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/deity_items/minions.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/deity_items/sacrificing.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/deity_items/smithing.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/items.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/narsie.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/spells/tear_veil.dm delete mode 100644 mods/gamemodes/deity/forms/narsie/structures.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/deity_items/artifacts.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/deity_items/phenomena.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/deity_items/spells.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/items.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/mobs.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/spells/disable_tech.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/spells/starlight_aura.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/spells/veil_of_shadows.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/starlight.dm delete mode 100644 mods/gamemodes/deity/forms/starlight/structures.dm delete mode 100644 mods/gamemodes/deity/forms/tower/deity_items/conjuration.dm delete mode 100644 mods/gamemodes/deity/forms/tower/deity_items/transmutation.dm delete mode 100644 mods/gamemodes/deity/forms/tower/spells.dm delete mode 100644 mods/gamemodes/deity/forms/tower/structures.dm delete mode 100644 mods/gamemodes/deity/forms/tower/tower.dm delete mode 100644 mods/gamemodes/deity/gamemode.dm delete mode 100644 mods/gamemodes/deity/god_cultist_role.dm delete mode 100644 mods/gamemodes/deity/mobs/deity.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_Stat.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_boons.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_click.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_hud.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_items.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_phenomena.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_power.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_pylon.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_sources.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_topic.dm delete mode 100644 mods/gamemodes/deity/mobs/deity_tracking.dm delete mode 100644 mods/gamemodes/deity/mobs/freelook/cultnet.dm delete mode 100644 mods/gamemodes/deity/mobs/freelook/mask.dm delete mode 100644 mods/gamemodes/deity/mobs/items/blood_crafting.dm delete mode 100644 mods/gamemodes/deity/mobs/items/deity_item.dm delete mode 100644 mods/gamemodes/deity/mobs/items/general.dm delete mode 100644 mods/gamemodes/deity/mobs/items/generic.dm delete mode 100644 mods/gamemodes/deity/mobs/menu/deity_nano.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/_defines.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/communication.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/conjuration.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/conversion.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/generic.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/narsie.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/phenomena.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/starlight.dm delete mode 100644 mods/gamemodes/deity/mobs/phenomena/transmutation.dm delete mode 100644 mods/gamemodes/deity/mobs/say.dm delete mode 100644 mods/gamemodes/deity/overrides.dm delete mode 100644 mods/gamemodes/deity/screen/intent.dm delete mode 100644 mods/gamemodes/deity/spells/boon.dm delete mode 100644 mods/gamemodes/deity/spells/construction.dm delete mode 100644 mods/gamemodes/deity/spells/open_gateway.dm delete mode 100644 mods/gamemodes/deity/spells/vision.dm delete mode 100644 mods/gamemodes/deity/structures/altar.dm delete mode 100644 mods/gamemodes/deity/structures/blood_forge.dm delete mode 100644 mods/gamemodes/deity/structures/pylon.dm delete mode 100644 mods/gamemodes/deity/structures/structures.dm delete mode 100644 mods/gamemodes/deity/structures/trap.dm delete mode 100644 nano/templates/deity.tmpl diff --git a/code/modules/species/outsider/shadow.dm b/code/modules/species/outsider/shadow.dm deleted file mode 100644 index 709f5d38ffe9..000000000000 --- a/code/modules/species/outsider/shadow.dm +++ /dev/null @@ -1,48 +0,0 @@ -/decl/bodytype/starlight/shadow - name = "shadow" - desc = "A wound of darkness inflicted upon the world." - icon_base = 'icons/mob/human_races/species/shadow/body.dmi' - icon_deformed = 'icons/mob/human_races/species/shadow/body.dmi' - body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS - eye_darksight_range = 8 - uid = "bodytype_starlight_shadow" - -/decl/blood_type/shadowstuff - name = "shadowstuff" - antigen_category = "shadowstuff" - splatter_name = "shadowstuff" - splatter_desc = "A puddle of shadowstuff." - splatter_colour = COLOR_GRAY80 - -/decl/species/starlight/shadow - name = "Shadow" - name_plural = "shadows" - description = "A being of pure darkness, hates the light and all that comes with it." - butchery_data = null - - available_bodytypes = list(/decl/bodytype/starlight/shadow) - - unarmed_attacks = list(/decl/natural_attack/claws/strong, /decl/natural_attack/bite/sharp) - shock_vulnerability = 0 - - blood_types = list( - /decl/blood_type/shadowstuff - ) - flesh_color = "#aaaaaa" - - remains_type = /obj/effect/decal/cleanable/ash - death_message = "dissolves into ash..." - - species_flags = SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED - -/decl/species/starlight/shadow/handle_environment_special(var/mob/living/human/H) - if(H.is_in_stasis() || H.stat == DEAD || H.isSynthetic()) - return - var/light_amount = 0 - if(isturf(H.loc)) - var/turf/T = H.loc - light_amount = T.get_lumcount() * 10 - if(light_amount > 2) //if there's enough light, start dying - H.take_overall_damage(1,1) - else //heal in the dark - H.heal_overall_damage(1,1) \ No newline at end of file diff --git a/code/modules/species/outsider/starlight.dm b/code/modules/species/outsider/starlight.dm deleted file mode 100644 index 215ba3cf5e9e..000000000000 --- a/code/modules/species/outsider/starlight.dm +++ /dev/null @@ -1,153 +0,0 @@ -/decl/species/starlight - abstract_type = /decl/species/starlight - butchery_data = null - spawn_flags = SPECIES_IS_RESTRICTED - available_pronouns = list(/decl/pronouns/neuter) - force_background_info = list( - /decl/background_category/heritage = /decl/background_detail/heritage/other - ) - hidden_from_codex = TRUE - -/decl/bodytype/starlight - abstract_type = /decl/bodytype/starlight - has_limbs = list( - BP_CHEST = list("path" = /obj/item/organ/external/chest/unbreakable), - BP_GROIN = list("path" = /obj/item/organ/external/groin/unbreakable), - BP_HEAD = list("path" = /obj/item/organ/external/head/unbreakable), - BP_L_ARM = list("path" = /obj/item/organ/external/arm/unbreakable), - BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/unbreakable), - BP_L_LEG = list("path" = /obj/item/organ/external/leg/unbreakable), - BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/unbreakable), - BP_L_HAND = list("path" = /obj/item/organ/external/hand/unbreakable), - BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/unbreakable), - BP_L_FOOT = list("path" = /obj/item/organ/external/foot/unbreakable), - BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/unbreakable) - ) - has_organ = list( - BP_BRAIN = /obj/item/organ/internal/brain/starlight - ) - -/obj/item/organ/internal/brain/starlight - name = "essence of fire" - desc = "A fancy name for ash. Still, it does look a bit different from the regular stuff." - icon = 'icons/obj/objects.dmi' - icon_state = "ash" - -/decl/bodytype/starlight/starborn - name = "starborn" - desc = "A blazing mass of light." - icon_base = 'icons/mob/human_races/species/starborn/body.dmi' - icon_deformed = 'icons/mob/human_races/species/starborn/body.dmi' - husk_icon = 'icons/mob/human_races/species/starborn/husk.dmi' - body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_PAIN | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS - uid = "bodytype_starlight_starborn" - cold_level_1 = 260 - cold_level_2 = 250 - cold_level_3 = 235 - heat_level_1 = 20000 - heat_level_2 = 30000 - heat_level_3 = 40000 - cold_discomfort_level = 300 - cold_discomfort_strings = list( - "You feel your fire dying out...", - "Your fire begins to shrink away from the cold.", - "You feel slow and sluggish from the cold." - ) - heat_discomfort_level = 10000 - heat_discomfort_strings = list( - "Surprisingly, you start burning!", - "You're... burning!?!" - ) - -/decl/blood_type/starstuff - name = "starstuff" - antigen_category = "starstuff" - splatter_name = "starstuff" - splatter_desc = "A puddle of starstuff." - splatter_colour = "#ffff00" - -/decl/species/starlight/handle_death(var/mob/living/human/H) - addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, dust)),0) - -/decl/species/starlight/starborn - name = "Starborn" - name_plural = "Starborn" - description = "Beings of fire and light, split off from a sun deity of unbelievable power." - available_bodytypes = list(/decl/bodytype/starlight/starborn) - - blood_types = list( - /decl/blood_type/starstuff - ) - flesh_color = "#ffff00" - - unarmed_attacks = list(/decl/natural_attack/punch/starborn) - - warning_low_pressure = 50 - hazard_low_pressure = 0 - shock_vulnerability = 0 - hunger_factor = 0 - thirst_factor = 0 - death_message = "dissolves into pure flames!" - breath_type = null - - - total_health = 250 - body_temperature = T0C + 500 //We are being of fire and light. - species_flags = SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED | SPECIES_FLAG_NO_TANGLE - - base_auras = list( - /obj/aura/starborn - ) - -/decl/species/starlight/starborn/handle_death(var/mob/living/human/H) - ..() - var/turf/T = get_turf(H) - T.add_to_reagents(/decl/material/liquid/fuel, 20) - T.hotspot_expose(FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE) - -/decl/bodytype/starlight/blueforged - name = "blueforged" - desc = "A mass of carved and shaped spacetime." - icon_base = 'icons/mob/human_races/species/blueforged/body.dmi' - icon_deformed = 'icons/mob/human_races/species/blueforged/body.dmi' - eye_icon = 'icons/mob/human_races/species/blueforged/eyes.dmi' - body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS - override_organ_types = list(BP_EYES = /obj/item/organ/internal/eyes/blueforged) - uid = "bodytype_starlight_blueforged" - -/decl/blood_type/spacestuff - name = "spacestuff" - antigen_category = "spacestuff" - splatter_name = "spacestuff" - splatter_desc = "A puddle of spacestuff." - splatter_colour = "#2222ff" - -/decl/species/starlight/blueforged - name = "Blueforged" - name_plural = "Blueforged" - description = "Living chunks of spacetime, carved out of the original dimension and given life by a being of unbelievable power." - available_bodytypes = list(/decl/bodytype/starlight/blueforged) - - flesh_color = "#2222ff" - - warning_low_pressure = 50 - hazard_low_pressure = 0 - hunger_factor = 0 - thirst_factor = 0 - breath_type = null - - burn_mod = 10 - brute_mod = 0 - oxy_mod = 0 - toxins_mod = 0 - radiation_mod = 0 - species_flags = SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED | SPECIES_FLAG_NO_TANGLE - -/decl/species/starlight/blueforged/handle_death(var/mob/living/human/H) - ..() - new /obj/effect/temporary(get_turf(H),11, 'icons/mob/mob.dmi', "liquify") - -/obj/item/organ/internal/eyes/blueforged - name = "bluespace prism" - desc = "You can see an endless blue plane when looking through it. Your eyes tingle if you stare too hard." - icon = 'icons/mob/human_races/species/blueforged/organs.dmi' diff --git a/maps/exodus/exodus.dm b/maps/exodus/exodus.dm index 6c13c0ddb9ce..44e718bbf096 100644 --- a/maps/exodus/exodus.dm +++ b/maps/exodus/exodus.dm @@ -1,7 +1,6 @@ #if !defined(USING_MAP_DATUM) #include "../../mods/gamemodes/cult/_cult.dme" - #include "../../mods/gamemodes/deity/_deity.dme" #include "../../mods/gamemodes/heist/_heist.dme" #include "../../mods/gamemodes/meteor/_meteor.dme" #include "../../mods/gamemodes/ninja/_ninja.dme" diff --git a/maps/exodus/exodus_antagonism.dm b/maps/exodus/exodus_antagonism.dm index 92660ef36082..322bebbf1d34 100644 --- a/maps/exodus/exodus_antagonism.dm +++ b/maps/exodus/exodus_antagonism.dm @@ -3,15 +3,6 @@ LAZYINITLIST(protected_jobs) protected_jobs |= list(/datum/job/officer, /datum/job/warden, /datum/job/detective, /datum/job/captain, /datum/job/lawyer, /datum/job/hos) -/decl/special_role/godcultist/Initialize() - . = ..() - LAZYINITLIST(restricted_jobs) - restricted_jobs |= list(/datum/job/lawyer, /datum/job/captain, /datum/job/hos) - LAZYINITLIST(protected_jobs) - protected_jobs |= list(/datum/job/officer, /datum/job/warden, /datum/job/detective) - LAZYINITLIST(blacklisted_jobs) - blacklisted_jobs |= /datum/job/chaplain - /decl/special_role/cultist/Initialize() . = ..() LAZYINITLIST(restricted_jobs) diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm index 0e75223cde40..de68e49bc7bd 100644 --- a/maps/modpack_testing/modpack_testing.dm +++ b/maps/modpack_testing/modpack_testing.dm @@ -4,7 +4,6 @@ #include "blank.dmm" #include "../../mods/gamemodes/cult/_cult.dme" - #include "../../mods/gamemodes/deity/_deity.dme" #include "../../mods/gamemodes/heist/_heist.dme" #include "../../mods/gamemodes/meteor/_meteor.dme" #include "../../mods/gamemodes/ninja/_ninja.dme" diff --git a/maps/tradeship/tradeship.dm b/maps/tradeship/tradeship.dm index 115fdd551c98..f3134a1184a8 100644 --- a/maps/tradeship/tradeship.dm +++ b/maps/tradeship/tradeship.dm @@ -5,7 +5,6 @@ #endif #include "../../mods/gamemodes/cult/_cult.dme" - #include "../../mods/gamemodes/deity/_deity.dme" #include "../../mods/gamemodes/heist/_heist.dme" #include "../../mods/gamemodes/ninja/_ninja.dme" #include "../../mods/gamemodes/revolution/_revolution.dme" diff --git a/mods/gamemodes/cult/_cult.dme b/mods/gamemodes/cult/_cult.dme index bda33c4bf964..e35ffed9db68 100644 --- a/mods/gamemodes/cult/_cult.dme +++ b/mods/gamemodes/cult/_cult.dme @@ -1,10 +1,6 @@ #ifndef GAMEMODE_PACK_CULT #define GAMEMODE_PACK_CULT -#ifdef GAMEMODE_PACK_DEITY -#warn Deity modpack loaded before Cult modpack, Nar'sie godform will be unavailable! -#endif - // BEGIN_INCLUDE #include "_cult.dm" #include "archaeology.dm" diff --git a/mods/gamemodes/cult/ghosttrap.dm b/mods/gamemodes/cult/ghosttrap.dm index 3e5d7452df6f..07faf87515f2 100644 --- a/mods/gamemodes/cult/ghosttrap.dm +++ b/mods/gamemodes/cult/ghosttrap.dm @@ -20,9 +20,3 @@ var/obj/item/soulstone/stone = new(get_turf(user)) stone.shade = new(stone) request_player(stone.shade, "The soul stone shade summon ritual has been performed. ") - -#ifdef GAMEMODE_PACK_DEITY -/decl/ghosttrap/cult_shade/Initialize() - ban_checks |= /decl/special_role/godcultist - . = ..() -#endif \ No newline at end of file diff --git a/mods/gamemodes/cult/items.dm b/mods/gamemodes/cult/items.dm index 01a8555e665d..1674cdb92eb8 100644 --- a/mods/gamemodes/cult/items.dm +++ b/mods/gamemodes/cult/items.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/items/weapon/swords/cult.dmi' material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME -// separated into a proc so that deity can modify it +// separated into a proc so that subtypes can modify it /obj/item/sword/cultblade/proc/can_use_safely(mob/living/user) return iscultist(user) diff --git a/mods/gamemodes/deity/_defines.dm b/mods/gamemodes/deity/_defines.dm deleted file mode 100644 index 99f85b14f61c..000000000000 --- a/mods/gamemodes/deity/_defines.dm +++ /dev/null @@ -1,19 +0,0 @@ -#define DEITY_TREE_SACRIFICE "Sacrificing" -#define DEITY_TREE_SOUL "Soul Arts" -#define DEITY_TREE_DARK_MINION "Summoning" -#define DEITY_TREE_TRANSMUTATION "Transmutation" -#define DEITY_TREE_CONJURATION "Conjuration" -#define DEITY_TREE_ARTIFACT "Artifacts" -#define DEITY_TREE_FIRECONJ "Fire Conjuration" -#define DEITY_TREE_HERALD "Phenomena" - -#define DEITY_BLOOD_CRAFT "Blood Crafting" -#define DEITY_ARMOR_CRAFT "Armor Crafting" -#define DEITY_VOID_CRAFT "Void Crafting" -#define DEITY_UNLOCK_ARMS "Unlock Armaments" -#define DEITY_UNLOCK_HEAL "Unlock Cleric Spells" - -#define isdeity(A) istype(A, /mob/living/deity) - -#define DEITY_STRUCTURE_NEAR_IMPORTANT 1 //Whether this needs to be near an important structure. -#define DEITY_STRUCTURE_ALONE 2 //Whether this can be near another of the same type. \ No newline at end of file diff --git a/mods/gamemodes/deity/_deity.dm b/mods/gamemodes/deity/_deity.dm deleted file mode 100644 index 6c658e122b37..000000000000 --- a/mods/gamemodes/deity/_deity.dm +++ /dev/null @@ -1,2 +0,0 @@ -/decl/modpack/deity - name = "Deity Gamemode Content" \ No newline at end of file diff --git a/mods/gamemodes/deity/_deity.dme b/mods/gamemodes/deity/_deity.dme deleted file mode 100644 index a1603dd317d8..000000000000 --- a/mods/gamemodes/deity/_deity.dme +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GAMEMODE_PACK_DEITY -#define GAMEMODE_PACK_DEITY -// BEGIN_INCLUDE -#include "_defines.dm" -#include "_deity.dm" -#include "codex.dm" -#include "deity_base.dm" -#include "deity_role.dm" -#include "gamemode.dm" -#include "god_cultist_role.dm" -#include "overrides.dm" -#include "extensions\deity_be_near.dm" -#include "forms\forms.dm" -// These should only load if cult is loaded. -#ifdef GAMEMODE_PACK_CULT -#include "forms\narsie\items.dm" -#include "forms\narsie\narsie.dm" -#include "forms\narsie\structures.dm" -#include "forms\narsie\deity_items\basic.dm" -#include "forms\narsie\deity_items\minions.dm" -#include "forms\narsie\deity_items\sacrificing.dm" -#include "forms\narsie\deity_items\smithing.dm" -#include "forms\narsie\spells\tear_veil.dm" -#endif -#include "forms\starlight\items.dm" -#include "forms\starlight\mobs.dm" -#include "forms\starlight\starlight.dm" -#include "forms\starlight\structures.dm" -#include "forms\starlight\deity_items\artifacts.dm" -#include "forms\starlight\deity_items\phenomena.dm" -#include "forms\starlight\deity_items\spells.dm" -#include "forms\starlight\spells\disable_tech.dm" -#include "forms\starlight\spells\starlight_aura.dm" -#include "forms\starlight\spells\veil_of_shadows.dm" -#include "forms\tower\spells.dm" -#include "forms\tower\structures.dm" -#include "forms\tower\tower.dm" -#include "forms\tower\deity_items\conjuration.dm" -#include "forms\tower\deity_items\transmutation.dm" -#include "mobs\deity.dm" -#include "mobs\deity_boons.dm" -#include "mobs\deity_click.dm" -#include "mobs\deity_hud.dm" -#include "mobs\deity_items.dm" -#include "mobs\deity_phenomena.dm" -#include "mobs\deity_power.dm" -#include "mobs\deity_pylon.dm" -#include "mobs\deity_sources.dm" -#include "mobs\deity_Stat.dm" -#include "mobs\deity_topic.dm" -#include "mobs\deity_tracking.dm" -#include "mobs\say.dm" -#include "mobs\freelook\cultnet.dm" -#include "mobs\freelook\mask.dm" -#include "mobs\items\blood_crafting.dm" -#include "mobs\items\deity_item.dm" -#include "mobs\items\general.dm" -#include "mobs\items\generic.dm" -#include "mobs\menu\deity_nano.dm" -#include "mobs\phenomena\_defines.dm" -#include "mobs\phenomena\communication.dm" -#include "mobs\phenomena\conjuration.dm" -#include "mobs\phenomena\conversion.dm" -#include "mobs\phenomena\generic.dm" -#include "mobs\phenomena\narsie.dm" -#include "mobs\phenomena\phenomena.dm" -#include "mobs\phenomena\starlight.dm" -#include "mobs\phenomena\transmutation.dm" -#include "screen\intent.dm" -#include "spells\boon.dm" -#include "spells\construction.dm" -#include "spells\open_gateway.dm" -#include "spells\vision.dm" -#include "structures\altar.dm" -#include "structures\blood_forge.dm" -#include "structures\pylon.dm" -#include "structures\structures.dm" -#include "structures\trap.dm" -// END_INCLUDE -#endif \ No newline at end of file diff --git a/mods/gamemodes/deity/codex.dm b/mods/gamemodes/deity/codex.dm deleted file mode 100644 index fae5bfe607a3..000000000000 --- a/mods/gamemodes/deity/codex.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/codex_entry/deity - abstract_type = /datum/codex_entry/deity - -/datum/codex_entry/deity/altar - associated_paths = list(/obj/structure/deity/altar) - mechanics_text = "To place someone upon the altar, first have them in an aggressive grab and click the altar while adjacent." - antag_text = "This structure anchors your deity within this realm, granting them additional power to influence it and empower their followers. Additionally, using it as a focus for their powers, they can convert someone laying on top of the altar.
" - disambiguator = "occult" - -/datum/codex_entry/deity/blood_forge - associated_paths = list(/obj/structure/deity/blood_forge) - antag_text = "Allows creation of special items by feeding your blood into it. Only usable by cultists of the aligned deity." - disambiguator = "occult" - -/datum/codex_entry/deity/gateway - associated_paths = list(/obj/structure/deity/gateway) - antag_text = "Stand within the gateway to be transported to an unknown dimension and transformed into a flaming Starborn, a mysterious Blueforged or a subtle Shadowling." - disambiguator = "occult" - -/datum/codex_entry/deity/radiant_statue - associated_paths = list(/obj/structure/deity/radiant_statue) - antag_text = "Allows storage of power if cultists are nearby. This stored power can be expended to charge Starlight items." - disambiguator = "occult" - -/datum/codex_entry/deity/blood_forge/starlight - associated_paths = list(/obj/structure/deity/blood_forge/starlight) - antag_text = "Allows creation of special Starlight items. Only usable by cultists of the aligned deity. Use of this powerful forge will inflict burns." - disambiguator = "occult" - -/datum/codex_entry/deity/wizard_recharger - associated_paths = list(/obj/structure/deity/wizard_recharger) - antag_text = "A well of arcane power. When charged, a cultist may absorb this power to refresh their spells." - disambiguator = "occult" - -/datum/codex_entry/deity/pylon - associated_paths = list(/obj/structure/deity/pylon) - antag_text = "Serves as a conduit for a deity to speak through, making their will known in this dimension to any who hear it." - disambiguator = "occult" \ No newline at end of file diff --git a/mods/gamemodes/deity/deity_base.dm b/mods/gamemodes/deity/deity_base.dm deleted file mode 100644 index 0d7268ebd643..000000000000 --- a/mods/gamemodes/deity/deity_base.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/map_template/ruin/antag_spawn/deity - name = "Deity Base" - mappaths = list( - "mods/gamemodes/deity/deity_base.dmm" - ) - apc_test_exempt_areas = list( - /area/map_template/deity_spawn = NO_SCRUBBER|NO_VENT|NO_APC - ) - -/area/map_template/deity_spawn - name = "\improper Deity Spawn" - icon_state = "yellow" - requires_power = 0 - dynamic_lighting = FALSE diff --git a/mods/gamemodes/deity/deity_base.dmm b/mods/gamemodes/deity/deity_base.dmm deleted file mode 100644 index 7e009c2d0bd7..000000000000 --- a/mods/gamemodes/deity/deity_base.dmm +++ /dev/null @@ -1,1035 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/space/infinity, -/area/map_template/deity_spawn) -"b" = ( -/turf/unsimulated/floor/lava, -/area/map_template/deity_spawn) -"c" = ( -/turf/unsimulated/floor/water, -/area/map_template/deity_spawn) -"d" = ( -/obj/abstract/landmark{ - name = "DeitySpawn" - }, -/turf/unsimulated/floor/lava, -/area/map_template/deity_spawn) -"e" = ( -/obj/abstract/landmark{ - name = "DeitySpawn" - }, -/turf/unsimulated/floor/water, -/area/map_template/deity_spawn) - -(1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(7,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(8,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(9,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(10,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(11,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(12,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(13,1,1) = {" -a -a -a -a -b -b -b -b -b -b -d -b -b -b -b -b -b -a -a -a -a -"} -(14,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(15,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(16,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(17,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(18,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(19,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(20,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(21,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(22,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(23,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(24,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(25,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(26,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(27,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(28,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(29,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(30,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(31,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(32,1,1) = {" -a -a -a -a -c -c -c -c -c -c -e -c -c -c -c -c -c -a -a -a -a -"} -(33,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(34,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(35,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(36,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(37,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(38,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(39,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(40,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(41,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(42,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(43,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(44,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} diff --git a/mods/gamemodes/deity/deity_role.dm b/mods/gamemodes/deity/deity_role.dm deleted file mode 100644 index 0426f6e8568e..000000000000 --- a/mods/gamemodes/deity/deity_role.dm +++ /dev/null @@ -1,15 +0,0 @@ -/decl/special_role/deity - name = "Deity" - name_plural = "Deities" - mob_path = /mob/living/deity - welcome_text = "This is not your world. This is not your reality. But here you exist. Use your powers, feed off the faith of others.
You have to click on yourself to choose your form.
Everything you say will be heard by your cultists!
To get points your cultists need to build!
Build Shrine and Construction are the best starting boons!" - landmark_id = "DeitySpawn" - - flags = ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB - - hard_cap = 2 - hard_cap_round = 2 - initial_spawn_req = 1 - initial_spawn_target = 1 - - base_to_load = "Deity Base" diff --git a/mods/gamemodes/deity/extensions/deity_be_near.dm b/mods/gamemodes/deity/extensions/deity_be_near.dm deleted file mode 100644 index 5eed3ae1fe40..000000000000 --- a/mods/gamemodes/deity/extensions/deity_be_near.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/extension/deity_be_near - base_type = /datum/extension/deity_be_near - expected_type = /obj/item - var/keep_away_instead = FALSE - var/mob/living/deity/connected_deity - var/threshold_base = 6 - var/expected_helmet - flags = EXTENSION_FLAG_IMMEDIATE - -/datum/extension/deity_be_near/New(var/datum/holder, var/mob/living/deity/connect) - ..() - events_repository.register(/decl/observ/moved, holder,src, PROC_REF(check_movement)) - connected_deity = connect - events_repository.register(/decl/observ/destroyed, holder, src, PROC_REF(dead_deity)) - var/obj/O = holder - O.desc += "
This item deals damage to its wielder the [keep_away_instead ? "closer" : "farther"] it is from a deity structure" - - -/datum/extension/deity_be_near/Destroy() - events_repository.unregister(/decl/observ/moved, holder,src) - events_repository.unregister(/decl/observ/destroyed, holder, src) - events_repository.unregister(/decl/observ/item_equipped, holder, src) - . = ..() - -/datum/extension/deity_be_near/proc/check_movement() - var/obj/item/I = holder - if(!isliving(I.loc)) - return - var/min_dist = INFINITY - for(var/s in connected_deity.structures) - var/dist = get_dist(holder,s) - if(dist < min_dist) - min_dist = dist - if(keep_away_instead && min_dist < threshold_base) - deal_damage(I.loc, round(threshold_base/min_dist)) - else if(min_dist > threshold_base) - deal_damage(I.loc, round(min_dist/threshold_base)) - - -/datum/extension/deity_be_near/proc/deal_damage(var/mob/living/victim, var/mult) - return - -/datum/extension/deity_be_near/proc/dead_deity() - var/obj/item/I = holder - I.visible_message(SPAN_WARNING("\The [holder]'s power fades!")) - qdel(src) - -/datum/extension/deity_be_near/proc/wearing_full() - var/obj/item/I = holder - - if(!ishuman(I.loc)) - return FALSE - var/mob/living/human/H = I.loc - if(H.get_equipped_slot_for_item(I) != slot_wear_suit_str) - return FALSE - if(expected_helmet && !istype(H.get_equipped_item(slot_head_str), expected_helmet)) - return FALSE - return TRUE - -/datum/extension/deity_be_near/champion/deal_damage(var/mob/living/victim,var/mult) - victim.take_damage(3 * mult, OXY) - -/datum/extension/deity_be_near/oracle/deal_damage(var/mob/living/victim, var/mult) - victim.take_damage(mult, BURN) - -/datum/extension/deity_be_near/traitor/deal_damage(var/mob/living/victim, var/mult) - victim.take_damage(5 * mult, PAIN) \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/forms.dm b/mods/gamemodes/deity/forms/forms.dm deleted file mode 100644 index 6f1f2f135b30..000000000000 --- a/mods/gamemodes/deity/forms/forms.dm +++ /dev/null @@ -1,48 +0,0 @@ -/*A god form basically is a combination of a sprite sheet choice and a gameplay choice. -Each plays slightly different and has different challenges/benefits -*/ - -/datum/god_form - var/name = "Form" - var/info = "This is a form your being can take." - var/desc = "This is the mob's description given." - var/faction = MOB_FACTION_NEUTRAL //For stuff like mobs and shit - var/god_icon_state = "nar-sie" //What you look like - var/pylon_icon_state //What image shows up when appearing in a pylon - var/mob/living/deity/linked_god = null - var/starting_power_min = 10 - var/starting_regeneration = 1 - var/list/buildables = list() //Both a list of var changes and a list of buildables. - var/list/items - -/datum/god_form/New(var/mob/living/deity/D) - ..() - D.icon_state = god_icon_state - D.desc = desc - D.power_min = starting_power_min - D.power_per_regen = starting_regeneration - linked_god = D - if(items && items.len) - var/list/complete_items = list() - for(var/l in items) - var/datum/deity_item/di = new l() - complete_items[di.name] = di - D.set_items(complete_items) - items.Cut() - -// TODO: Make this not a thing. It's so bad. -/datum/god_form/proc/sync_structure(var/obj/O) - var/list/svars = buildables[O.type] - if(!svars) - return - for(var/V in svars) - O.vars[V] = svars[V] - -/datum/god_form/proc/take_charge(var/mob/living/user, var/charge) - return TRUE - -/datum/god_form/Destroy() - if(linked_god) - linked_god.form = null - linked_god = null - return ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/deity_items/basic.dm b/mods/gamemodes/deity/forms/narsie/deity_items/basic.dm deleted file mode 100644 index 59e8a7d15865..000000000000 --- a/mods/gamemodes/deity/forms/narsie/deity_items/basic.dm +++ /dev/null @@ -1,34 +0,0 @@ -/datum/deity_item/boon/eternal_darkness - name = "Eternal Darkness" - desc = "Allows a follower to cause insanity in a target." - category = "Dark Spells" - base_cost = 40 - boon_path = /spell/targeted/shatter - -/datum/deity_item/boon/torment - name = "Torment" - desc = "Gives a follower the ability to cause mass hysteria and pain." - category = "Dark Spells" - base_cost = 50 - boon_path = /spell/targeted/torment - -/datum/deity_item/boon/blood_shard - name = "Blood Shard" - desc = "Lets a follower cause a target's blood to literally explode out of their skin into dangerous projectiles." - category = "Dark Spells" - base_cost = 75 - boon_path = /spell/hand/charges/blood_shard - -/datum/deity_item/boon/drain_blood - name = "Drain Blood" - desc = "Lets a follower drain blood from all those around them." - category = "Dark Spells" - base_cost = 110 - boon_path = /spell/aoe_turf/drain_blood - -/datum/deity_item/phenomenon/exude_blood - name = "Phenomenon: Exude Blood" - desc = "You extract the raw blood used in your faith and give it to one of your flock." - category = "Dark Spells" - base_cost = 30 - phenomenon_path = /datum/phenomenon/exude_blood \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/deity_items/minions.dm b/mods/gamemodes/deity/forms/narsie/deity_items/minions.dm deleted file mode 100644 index be4c8fe14edc..000000000000 --- a/mods/gamemodes/deity/forms/narsie/deity_items/minions.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/deity_item/minions - name = DEITY_TREE_DARK_MINION - desc = "Unlock abilities that allow your followers to craft and summon useful creatures." - category = DEITY_TREE_DARK_MINION - base_cost = 75 - -/datum/deity_item/boon/soul_shard - name = "Soul Stone Shard" - desc = "Give your follower a sliver of soulstone to capture a life in." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 20 - boon_path = /obj/item/soulstone - -/datum/deity_item/boon/blood_zombie - name = "Blood Plague" - desc = "Give a vessel to a follower filled with infection so vile, it turns all sapient creatures into mindless husks." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 300 - boon_path = /obj/item/chems/drinks/zombiedrink - -/datum/deity_item/boon/tear_veil - name = "Tear Veil" - desc = "Grant your follower the ability to literally rip a hole in this reality, allowing things to pass through." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 100 - boon_path = /spell/tear_veil - -/datum/deity_item/phenomenon/hellscape - name = "Phenomenon: Reveal Hellscape" - desc = "You show a non-believer what their future will be like." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 110 - phenomenon_path = /datum/phenomenon/hellscape \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/deity_items/sacrificing.dm b/mods/gamemodes/deity/forms/narsie/deity_items/sacrificing.dm deleted file mode 100644 index 7e5d631c7f93..000000000000 --- a/mods/gamemodes/deity/forms/narsie/deity_items/sacrificing.dm +++ /dev/null @@ -1,42 +0,0 @@ -/datum/deity_item/sacrifice - name = DEITY_TREE_SACRIFICE - desc = "Unlocks the tools necessary to allow your followers to sacrifice in your name." - category = DEITY_TREE_SACRIFICE - base_cost = 50 - max_level = 1 - -/datum/deity_item/boon/sac_dagger - name = "Sacrificial Dagger" - desc = "A small dagger embued with your powers. Lets your followers give you power through sacrifices on an altar." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 10 - boon_path = /obj/item/knife/ritual/sacrifice - -/datum/deity_item/boon/sac_spell - name = "Sacrifice Spell" - desc = "This ability makes the user take INCREDIBLE amounts of damage to heal a target for a similar amount of damage." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 10 - boon_path = /spell/targeted/heal_target/sacrifice - -/datum/deity_item/boon/execution_axe - name = "Greedy Axe" - desc = "This axe can store the very souls of those it kills to be later transfered to you through an altar." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 50 - boon_path = /obj/item/bladed/axe/fire/cult - -/datum/deity_item/blood_stone - name = "Bloodied Stone" - desc = "Unlocks the blood stone building, which allows followers to increase your power through ritual and prayer." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 50 - max_level = 1 - -/datum/deity_item/blood_stone/buy(var/mob/living/deity/user) - ..() - user.form.buildables |= /obj/structure/deity/blood_stone \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/deity_items/smithing.dm b/mods/gamemodes/deity/forms/narsie/deity_items/smithing.dm deleted file mode 100644 index bcb12ff11e34..000000000000 --- a/mods/gamemodes/deity/forms/narsie/deity_items/smithing.dm +++ /dev/null @@ -1,29 +0,0 @@ -/datum/deity_item/blood_crafting/narsie - recipes = list( - /obj/item/sword/cultblade = 50, - /obj/item/clothing/head/culthood/alt = 10, - /obj/item/clothing/suit/cultrobes/alt = 20 - ) - -/datum/deity_item/blood_crafting/armored - name = DEITY_ARMOR_CRAFT - desc = "Unlock the secrets to tempered blood smithing, allowing your followers to smith more powerful and expensive armaments." - category = DEITY_BLOOD_CRAFT - base_cost = 75 - requirements = list(DEITY_BLOOD_CRAFT = 1) - recipes = list( - /obj/item/clothing/suit/cultrobes/magusred = 80, - /obj/item/clothing/head/culthood/magus = 50, - /obj/structure/constructshell/cult = 70 - ) //also shield? - -/datum/deity_item/blood_crafting/space - name = DEITY_VOID_CRAFT - desc = "Allows your followers to craft space suits, allowing you to finally spread across the cosmos." - category = DEITY_BLOOD_CRAFT - base_cost = 100 - requirements = list(DEITY_BLOOD_CRAFT = 1, DEITY_ARMOR_CRAFT = 1) - recipes = list( - /obj/item/clothing/suit/space/cult = 100, - /obj/item/clothing/head/helmet/space/cult = 70 - ) //Probably more too. \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/items.dm b/mods/gamemodes/deity/forms/narsie/items.dm deleted file mode 100644 index 56d3ffe89f8f..000000000000 --- a/mods/gamemodes/deity/forms/narsie/items.dm +++ /dev/null @@ -1,77 +0,0 @@ - -//SACRIFICE DAGGER -//If used on a person on an altar, causes the user to carve into them, dealing moderate damage and gaining points for the altar's god. -/obj/item/knife/ritual/sacrifice - name = "sacrificial dagger" - desc = "This knife is dull but well used." - material = /decl/material/solid/stone/cult - -/obj/item/knife/ritual/sacrifice/resolve_attackby(var/atom/a, var/mob/user, var/click_params) - var/turf/T = get_turf(a) - var/obj/structure/deity/altar/altar = locate() in T - if(!altar) - return ..() - if(isliving(a)) - var/mob/living/L = a - var/multiplier = 1 - if(L.mind) - multiplier++ - if(ishuman(L)) - var/mob/living/human/H = L - if(H.should_have_organ(BP_HEART)) - multiplier++ - if(L.stat == DEAD) - to_chat(user, SPAN_WARNING("\The [a] is already dead! There is nothing to take!")) - return - - user.visible_message(SPAN_WARNING("\The [user] hovers \the [src] over \the [a], whispering an incantation.")) - if(!do_after(user,200, L)) - return - user.visible_message(SPAN_DANGER("\The [user] plunges the knife down into \the [a]!")) - L.take_damage(20) - if(altar.linked_god) - altar.linked_god.adjust_power_min(2 * multiplier,0,"from a delicious sacrifice!") - - -//EXEC AXE -//If a person hit by this axe within three seconds dies, sucks in their soul to be harvested at altars. -/obj/item/bladed/axe/fire/cult - name = "terrible axe" - desc = "Its head is sharp and stained red with heavy use." - icon = 'icons/obj/items/weapon/bone_axe.dmi' - var/stored_power = 0 - -/obj/item/bladed/axe/fire/cult/examine(mob/user) - . = ..() - if(stored_power) - to_chat(user, SPAN_NOTICE("It exudes a death-like smell.")) - -/obj/item/bladed/axe/fire/cult/resolve_attackby(var/atom/a, var/mob/user, var/click_params) - if(istype(a, /obj/structure/deity/altar)) - var/obj/structure/deity/altar/altar = a - if(stored_power && altar.linked_god) - altar.linked_god.adjust_power_min(stored_power, "from harvested souls.") - altar.visible_message(SPAN_WARNING("\The [altar] absorbs a black mist exuded from \the [src].")) - return - if(ismob(a)) - var/mob/M = a - if(M.stat != DEAD) - events_repository.register(/decl/observ/death, M,src, TYPE_PROC_REF(/obj/item/bladed/axe/fire/cult, gain_power)) - spawn(30) - events_repository.unregister(/decl/observ/death, M,src) - return ..() - -/obj/item/bladed/axe/fire/cult/proc/gain_power() - stored_power += 50 - src.visible_message(SPAN_OCCULT("\The [src] screeches as the smell of death fills the air!")) - -/obj/item/chems/drinks/zombiedrink - name = "well-used urn" - desc = "Said to bring those who drink it back to life, no matter the price." - icon = 'icons/obj/xenoarchaeology.dmi' - icon_state = "urn" - volume = 10 - amount_per_transfer_from_this = 10 - -/obj/item/chems/drinks/zombiedrink/populate_reagents() - add_to_reagents(/decl/material/liquid/zombie, reagents.maximum_volume) diff --git a/mods/gamemodes/deity/forms/narsie/narsie.dm b/mods/gamemodes/deity/forms/narsie/narsie.dm deleted file mode 100644 index 8ebf2dfc818b..000000000000 --- a/mods/gamemodes/deity/forms/narsie/narsie.dm +++ /dev/null @@ -1,51 +0,0 @@ -/datum/god_form/narsie - name = "Nar-Sie" - info = {"The Geometer of Blood, you crave blood and destruction.
- Benefits:
- +Can gain power from blood sacrifices.
- +Ability to forge weapons and armor.
- Drawbacks:
- -Servant abilities require copious amounts of their blood. - "} - desc = "A being made of a million nightmares, a billion deaths." - god_icon_state = "nar-sie" - pylon_icon_state = "shade" - faction = "cult" - - buildables = list( - /obj/structure/deity/altar/narsie, - /obj/structure/deity/pylon - ) - items = list( - /datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/boon/eternal_darkness, - /datum/deity_item/boon/torment, - /datum/deity_item/boon/blood_shard, - /datum/deity_item/boon/drain_blood, - /datum/deity_item/phenomenon/exude_blood, - /datum/deity_item/sacrifice, - /datum/deity_item/boon/sac_dagger, - /datum/deity_item/boon/sac_spell, - /datum/deity_item/boon/execution_axe, - /datum/deity_item/blood_stone, - /datum/deity_item/minions, - /datum/deity_item/boon/soul_shard, - /datum/deity_item/boon/blood_zombie, - /datum/deity_item/boon/tear_veil, - /datum/deity_item/phenomenon/hellscape, - /datum/deity_item/blood_crafting/narsie, - /datum/deity_item/blood_crafting/armored, - /datum/deity_item/blood_crafting/space - ) - -/datum/god_form/narsie/take_charge(var/mob/living/user, var/charge) - charge = min(100, charge * 0.25) - if(prob(charge)) - to_chat(user, SPAN_WARNING("You feel drained...")) - var/mob/living/human/H = user - if(istype(H) && H.should_have_organ(BP_HEART)) - H.vessel.remove_any(charge) - else - user.take_damage(charge) - return 1 \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/spells/tear_veil.dm b/mods/gamemodes/deity/forms/narsie/spells/tear_veil.dm deleted file mode 100644 index daf6b5d59d9d..000000000000 --- a/mods/gamemodes/deity/forms/narsie/spells/tear_veil.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/tear_veil - name = "Tear Veil" - desc = "Use your mental strength to literally tear a hole from this dimension to the next, letting things through..." - - charge_max = 300 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "const_floor" - cast_sound = 'sound/effects/meteorimpact.ogg' - var/list/possible_spawns = list( - /mob/living/simple_animal/hostile/scarybat/cult, - /mob/living/simple_animal/hostile/creature/cult, - /mob/living/simple_animal/hostile/revenant/cult - ) - -/spell/tear_veil/choose_targets() - var/turf/T = get_turf(holder) - holder.visible_message(SPAN_NOTICE("A strange portal rips open underneath \the [holder]!")) - var/obj/effect/gateway/hole = new(get_turf(T)) - hole.density = FALSE - return list(hole) - -/spell/tear_veil/cast(var/list/targets, var/mob/holder, var/channel_count) - if(channel_count == 1) - return - var/type = pick(possible_spawns) - var/mob/living/L = new type(get_turf(targets[1])) - L.faction = holder.faction - L.visible_message(SPAN_WARNING("\A [L] escapes from the portal!")) - -/spell/tear_veil/after_spell(var/list/targets) - qdel(targets[1]) - return \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/narsie/structures.dm b/mods/gamemodes/deity/forms/narsie/structures.dm deleted file mode 100644 index af576963a1f0..000000000000 --- a/mods/gamemodes/deity/forms/narsie/structures.dm +++ /dev/null @@ -1,36 +0,0 @@ -/obj/structure/deity/altar/narsie - name = "altar" - desc = "A small desk, covered in blood." - icon_state = "talismanaltar" - -//BLOODLETTING STRUCTURE -//A follower can stand here and mumble prayers as they let their blood flow slowly into the structure. -/obj/structure/deity/blood_stone - name = "bloody stone" - desc = "A jagged stone covered in the various stages of blood, from dried to fresh." - icon_state = "blood_stone" - // TODO: material-based health for deity structures - current_health = 100 //It's a piece of rock. - build_cost = 700 - -/obj/structure/deity/blood_stone/attack_hand(var/mob/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return ..() - var/mob/living/human/H = user - user.visible_message( - SPAN_WARNING("\The [user] calmly slices their finger on \the [src], smearing their blood over the black stone."), - SPAN_WARNING("You slowly slide your finger down one of \the [src]'s sharp edges, smearing your blood over its smooth surface.") - ) - while(do_after(H, 5 SECONDS, src)) - user.audible_message("\The [user] utters something under their breath.", SPAN_OCCULT("You mutter a dark prayer to your master as you feel the stone eat away at your lifeforce.")) - if(H.should_have_organ(BP_HEART)) - H.drip(5, get_turf(src)) - else - H.take_damage(5) - linked_god.adjust_power_min(1, 1) - return TRUE - -/datum/codex_entry/deity/blood_stone - associated_paths = list(/obj/structure/deity/blood_stone) - antag_text = "Allows the user to feed blood directly to the aligned deity, granting it power." - disambiguator = "occult" \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/deity_items/artifacts.dm b/mods/gamemodes/deity/forms/starlight/deity_items/artifacts.dm deleted file mode 100644 index 286be5afd10f..000000000000 --- a/mods/gamemodes/deity/forms/starlight/deity_items/artifacts.dm +++ /dev/null @@ -1,32 +0,0 @@ -/datum/deity_item/boon/blazing_blade - name = "Blazing Blade" - desc = "A divine blade of burning fury. If it stays too far away from an altar of some sort, it disappears." - base_cost = 250 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/sword/blazing - -/datum/deity_item/boon/holy_beacon - name = "Holy Beacon" - desc = "A staff capable of producing an almost harmless bolt of sunlight, capable of blinding anyone in the room, at least for a while." - base_cost = 200 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/gun/energy/staff/beacon - -/datum/deity_item/boon/black_death - name = "Black Death" - desc = "A small dagger capable of poisoning those it bites. Careful, if it loses all its charges, it will burn the user. It can be recharged at a radiant statue." - base_cost = 150 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/knife/ritual/shadow - -/datum/deity_item/blood_crafting/firecrafting - name = "Fire Crafting" - desc = "Gain the ability for your minions to build smithing stations that can make many rings of power." - base_cost = 300 - category = DEITY_TREE_ARTIFACT - max_level = 1 - forge_type = /obj/structure/deity/blood_forge/starlight - recipes = list(/obj/item/clothing/gloves/ring/aura_ring/talisman_of_starborn = 70, - /obj/item/clothing/gloves/ring/aura_ring/talisman_of_blueforged = 70, - /obj/item/clothing/gloves/ring/aura_ring/talisman_of_shadowling = 70 - ) \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/deity_items/phenomena.dm b/mods/gamemodes/deity/forms/starlight/deity_items/phenomena.dm deleted file mode 100644 index 37f830d27cbe..000000000000 --- a/mods/gamemodes/deity/forms/starlight/deity_items/phenomena.dm +++ /dev/null @@ -1,41 +0,0 @@ -/datum/deity_item/phenomenon/herald - name = "Choose Herald" - desc = "Gives you the ability to choose a herald. Can only be used once so be careful." - phenomenon_path = /datum/phenomenon/herald - base_cost = 100 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomenon/wisp - name = "Summon Wisp" - desc = "Manipulate around a small light." - phenomenon_path = /datum/phenomenon/movable_object/wisp - base_cost = 100 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomenon/flickering_whisper - name = "Flickering Whisper" - desc = "Send a subtle message to a non-follower, and see what they see for a while." - phenomenon_path = /datum/phenomenon/flickering_whisper - base_cost = 50 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomenon/burning_glare - name = "Burning Glare" - desc = "Use your divine power to physically burn a person." - phenomenon_path = /datum/phenomenon/burning_glare - base_cost = 200 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomenon/open_gateway - name = "Open Gateway" - desc = "Unlocks the ability to open a gateway. Required for rebirth." - phenomenon_path = /datum/phenomenon/create_gateway - base_cost = 250 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomenon/divine_right - name = "Divine Right" - desc = "Unlocks the ability to possess your Herald, permanently transforming you into a physical god." - phenomenon_path = /datum/phenomenon/divine_right - base_cost = 300 - category = DEITY_TREE_HERALD \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/deity_items/spells.dm b/mods/gamemodes/deity/forms/starlight/deity_items/spells.dm deleted file mode 100644 index 33c6e19a55a5..000000000000 --- a/mods/gamemodes/deity/forms/starlight/deity_items/spells.dm +++ /dev/null @@ -1,62 +0,0 @@ -/datum/deity_item/boon/starburst - name = "Starburst" - desc = "Grant your minion the power to blind non-followers nearby." - base_cost = 60 - boon_path = /spell/targeted/genetic/blind/starburst - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/exchange_wounds - name = "Exchange Wounds" - desc = "Allow a follower to sacrifice their own well-being for that of those around them." - base_cost = 120 - boon_path = /spell/aoe_turf/exchange_wounds - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/radiant_aura - name = "Radiant Aura" - desc = "This spell makes one of your followers immune to laser fire, for a short while at least." - base_cost = 70 - boon_path = /spell/radiant_aura/starlight - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/burning_touch - name = "Burning Touch" - desc = "Sets your minion's hand aflame, allowing them to burn people with an ever-increasing flame." - base_cost = 60 - boon_path = /spell/targeted/equip_item/burning_hand - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/burning_grip - name = "Burning Grip" - desc = "Give your follower the ability to burn an item in someone's hand so badly it causes them to burn." - base_cost = 50 - boon_path = /spell/hand/burning_grip - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/blood_boil - name = "Blood Boil" - desc = "Allow a follower to concentrate so deeply on a target that their body temperature increases, eventually setting them on fire." - base_cost = 90 - boon_path = /spell/targeted/blood_boil - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/fireball - name = "Fireball" - desc = "A classic spell, grants your follower the ability to throw an exploding ball of flame in any direction." - base_cost = 100 - boon_path = /spell/targeted/projectile/dumbfire/fireball - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/emp - name = "Disable Machinery" - desc = "Gives your follower a spell of disabling machinery, and mechanical hearts." - base_cost = 110 - boon_path = /spell/aoe_turf/disable_tech/starlight - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/cure_light - name = "Cure Light Wounds" - desc = "Grant mercy on your followers, giving them the ability to heal themselves slightly." - base_cost = 70 - boon_path = /spell/targeted/heal_target - category = DEITY_TREE_FIRECONJ \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/items.dm b/mods/gamemodes/deity/forms/starlight/items.dm deleted file mode 100644 index 31645b2d3acd..000000000000 --- a/mods/gamemodes/deity/forms/starlight/items.dm +++ /dev/null @@ -1,159 +0,0 @@ -/obj/item/clothing/gloves/ring/aura_ring - var/obj/aura/granted_aura - -/obj/item/clothing/gloves/ring/aura_ring/equipped(var/mob/living/L, var/slot) - ..() - if(granted_aura && slot == slot_gloves_str) - L.add_aura(granted_aura) - -/obj/item/clothing/gloves/ring/aura_ring/dropped(var/mob/living/L) - ..() - if(granted_aura) - L.remove_aura(granted_aura) - -/obj/item/clothing/gloves/ring/aura_ring/Destroy() - QDEL_NULL(granted_aura) - . = ..() - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_starborn - name = "Talisman of the Starborn" - desc = "This ring seems to shine with more light than is put on it." - icon = 'icons/clothing/accessories/jewelry/rings/ring_star.dmi' - material = /decl/material/solid/metal/blackbronze - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_starborn/Initialize() - . = ..() - granted_aura = new /obj/aura/starborn() - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_blueforged - name = "Talisman of the Blueforged" - desc = "The gem on this ring is quite peculiar..." - icon = 'icons/clothing/accessories/jewelry/rings/ring_blue.dmi' - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_blueforged/Initialize() - . = ..() - granted_aura = new /obj/aura/blueforge_aura() - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_shadowling - name = "Talisman of the Shadowling" - desc = "If you weren't looking at this, you probably wouldn't have noticed it." - icon = 'icons/clothing/accessories/jewelry/rings/ring_shadow.dmi' - material = /decl/material/solid/metal/blackbronze - -/obj/item/clothing/gloves/ring/aura_ring/talisman_of_shadowling/Initialize() - . = ..() - granted_aura = new /obj/aura/shadowling_aura() - -/obj/item/clothing/suit/armor/sunsuit - name = "knight's armor" - desc = "Now, you can be the knight in shining armor you've always wanted to be. With complementary sun insignia." - icon = 'icons/clothing/suits/deity/star_champion.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, - ARMOR_BULLET = ARMOR_BALLISTIC_AP, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_MINOR - ) - -/obj/item/clothing/head/helmet/sunhelm - name = "knight's helm" - desc = "It's a shiny metal helmet. It looks ripped straight out of the Dark Ages, actually." - icon = 'icons/clothing/head/star_champion.dmi' - flags_inv = HIDEEARS | BLOCK_ALL_HAIR - -/obj/item/clothing/suit/armor/sunrobe - name = "oracle's robe" - desc = "The robes of a priest. One that praises the sun, apparently. Well, it certainly reflects light well." - icon = 'icons/clothing/suits/deity/star_oracle.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_KNIVES, - ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_MINOR - ) - -/obj/item/clothing/suit/armor/sunrobe/Initialize() - . = ..() - set_light(4, 0.3) - -/obj/item/clothing/suit/space/shadowsuit - name = "traitor's cloak" - desc = "There is absolutely nothing visible through the fabric. The shadows stick to your skin when you touch it." - item_flags = ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_AIRTIGHT - min_pressure_protection = 0 - icon = 'icons/clothing/suits/deity/star_traitor.dmi' - -/obj/item/clothing/head/helmet/space/shadowhood - name = "traitor's hood" - desc = "No light can pierce this hood. It's unsettling." - icon = 'icons/clothing/head/star_traitor.dmi' - flags_inv = HIDEEARS | BLOCK_ALL_HAIR - -/obj/item/knife/ritual/shadow - name = "black death" - desc = "An obsidian dagger. The singed remains of a green cloth are wrapped around the 'handle.'" - var/charge = 5 - -/obj/item/knife/ritual/shadow/apply_hit_effect(var/mob/living/target, var/mob/living/user, var/hit_zone) - . = ..() - if(charge) - if(target.get_damage(BRUTE) > 15) - var/datum/reagents/R = target.reagents - if(!R) - return - R.add_reagent(/decl/material/liquid/venom, 5) - new /obj/effect/temporary(get_turf(target),3, 'icons/effects/effects.dmi', "fire_goon") - charge-- - else - user.take_damage(5, BURN) - if(prob(5)) - to_chat(user, SPAN_WARNING("\The [src] appears to be out of power!")) - new /obj/effect/temporary(get_turf(user),3, 'icons/effects/effects.dmi', "fire_goon") - -/obj/item/gun/energy/staff/beacon - name = "holy beacon" - desc = "Look closely into its crystal; there's a miniature sun. Or maybe that's just some fancy LEDs. Either way, it looks thoroughly mystical." - icon = 'icons/obj/wizard.dmi' - icon_state = "starstaff" - self_recharge = 0 - max_shots = 10 - projectile_type = /obj/item/projectile/energy/flash - required_antag_type = /decl/special_role/godcultist - -/obj/item/sword/blazing - name = "blazing blade" - icon = 'icons/obj/items/weapon/swords/flaming.dmi' - atom_damage_type = BURN - material_alteration = MAT_FLAG_ALTERATION_NONE - var/last_near_structure = 0 - var/mob/living/deity/linked - -/obj/item/sword/blazing/Initialize(var/maploading, var/material, var/deity) - . = ..() - START_PROCESSING(SSobj, src) - linked = deity - -/obj/item/sword/blazing/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/sword/blazing/Process() - if(!linked || last_near_structure + 10 SECONDS > world.time) - return - - if(linked.near_structure(src,1)) - if(last_near_structure < world.time - 30 SECONDS) - to_chat(loc, SPAN_NOTICE("\The [src] surges with power anew!")) - last_near_structure = world.time - else - if(last_near_structure < world.time - 30 SECONDS) //If it has been at least 30 seconds. - if(prob(5)) - to_chat(loc, SPAN_WARNING("\The [src] begins to fade, its power dimming this far away from a shrine.")) - else if(last_near_structure + 1800 < world.time) - visible_message(SPAN_WARNING("\The [src] disintegrates into a pile of ash!")) - new /obj/effect/decal/cleanable/ash(get_turf(src)) - qdel(src) diff --git a/mods/gamemodes/deity/forms/starlight/mobs.dm b/mods/gamemodes/deity/forms/starlight/mobs.dm deleted file mode 100644 index 5748cf2e2f40..000000000000 --- a/mods/gamemodes/deity/forms/starlight/mobs.dm +++ /dev/null @@ -1,29 +0,0 @@ -/mob/living/starlight_soul - name = "soul" - desc = "A captured soul." - anchored = TRUE - butchery_data = null - -/mob/living/starlight_soul/Initialize(var/maploading, var/mob/living/old_mob) - . = ..() - if(old_mob) - name = old_mob.real_name - -/mob/living/starlight_soul/proc/set_deity(var/mob/living/deity/deity) - var/mob/observer/eye/freelook/cult/eye - if(eyeobj) - eye = eyeobj - eyeobj.release(src) - else - eye = new(src) - eye.suffix = "Soul" - eyeobj = eye - eye.visualnet = deity.eyenet - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - godcult.add_antagonist_mind(src.mind,1,"lost soul of [deity]", "You have been captured by \the [deity]! You now can only see into your own reality through the same rips and tears it uses. Your only chance at another body will be one in your captor's image...",specific_god=deity) - eyeobj.possess(src) - -/mob/living/starlight_soul/Destroy() - if(eyeobj) - QDEL_NULL(eyeobj) - . = ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/spells/disable_tech.dm b/mods/gamemodes/deity/forms/starlight/spells/disable_tech.dm deleted file mode 100644 index f6462ae33fed..000000000000 --- a/mods/gamemodes/deity/forms/starlight/spells/disable_tech.dm +++ /dev/null @@ -1,4 +0,0 @@ -/spell/aoe_turf/disable_tech/starlight - hidden_from_codex = TRUE - charge_max = 600 - spell_flags = 0 \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/spells/starlight_aura.dm b/mods/gamemodes/deity/forms/starlight/spells/starlight_aura.dm deleted file mode 100644 index 8ad867e41b3e..000000000000 --- a/mods/gamemodes/deity/forms/starlight/spells/starlight_aura.dm +++ /dev/null @@ -1,5 +0,0 @@ -/spell/radiant_aura/starlight - name = "Starlight Aura" - desc = "This spell makes you immune to laser fire, for a short while at least." - spell_flags = 0 - charge_max = 400 diff --git a/mods/gamemodes/deity/forms/starlight/spells/veil_of_shadows.dm b/mods/gamemodes/deity/forms/starlight/spells/veil_of_shadows.dm deleted file mode 100644 index e47edecd0822..000000000000 --- a/mods/gamemodes/deity/forms/starlight/spells/veil_of_shadows.dm +++ /dev/null @@ -1,57 +0,0 @@ -/spell/veil_of_shadows - name = "Veil of Shadows" - desc = "Become intangable, invisible. Like a ghost." - charge_max = 400 - invocation_type = SpI_EMOTE - invocation = "flickers out of existance" - school = "Divine" - spell_flags = 0 - duration = 100 - var/timer_id - var/light_steps = 4 - - hud_state = "wiz_statue" - -/spell/veil_of_shadows/choose_targets() - if(!timer_id && ishuman(holder)) - return list(holder) - . = null - -/spell/veil_of_shadows/cast(var/list/targets, var/mob/user) - var/mob/living/human/H = user - H.AddMovementHandler(/datum/movement_handler/mob/incorporeal) - if(H.add_cloaking_source(src)) - H.visible_message(SPAN_WARNING("\The [H] shrinks from view!")) - events_repository.register(/decl/observ/moved, H,src,PROC_REF(check_light)) - timer_id = addtimer(CALLBACK(src,PROC_REF(cancel_veil)),duration, TIMER_STOPPABLE) - -/spell/veil_of_shadows/proc/cancel_veil() - var/mob/living/human/H = holder - H.RemoveMovementHandler(/datum/movement_handler/mob/incorporeal) - deltimer(timer_id) - timer_id = null - var/turf/T = get_turf(H) - if(T.get_lumcount() > 0.1) //If we're somewhere somewhat shadowy we can stay invis as long as we stand still - drop_cloak() - else - events_repository.unregister(/decl/observ/moved, H,src) - events_repository.register(/decl/observ/moved, H,src,PROC_REF(drop_cloak)) - -/spell/veil_of_shadows/proc/drop_cloak() - var/mob/living/human/H = holder - if(H.remove_cloaking_source(src)) - H.visible_message(SPAN_NOTICE("\The [H] appears from nowhere!")) - events_repository.unregister(/decl/observ/moved, H,src) - -/spell/veil_of_shadows/proc/check_light() - if(light_steps) - light_steps-- - return - light_steps = initial(light_steps) - for(var/obj/machinery/light/light in view(1,holder)) - light.flicker(20) - -/spell/veil_of_shadows/Destroy() - deltimer(timer_id) - cancel_veil() - .= ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/starlight.dm b/mods/gamemodes/deity/forms/starlight/starlight.dm deleted file mode 100644 index 1469947fe10a..000000000000 --- a/mods/gamemodes/deity/forms/starlight/starlight.dm +++ /dev/null @@ -1,47 +0,0 @@ -/datum/god_form/starlight - name = "Starlight Herald" - info = {"Sun and fire incarnate.
- Benefits:
- +Ability to summon powerful minions via sacrifices.
- +Bless one of your minions as a Herald, giving them species powers and armor.
- Drawbacks:
- -Servant's powers will burn them.
- -You require copious amounts of power regeneration.
- "} - desc = "The bringer of life, and all that entails." - god_icon_state = "sungod" - pylon_icon_state = "god" - faction = "herald" - - buildables = list(/obj/structure/deity/altar/starlight, - /obj/structure/deity/pylon/starlight, - /obj/structure/deity/radiant_statue, - ) - items = list(/datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/boon/blazing_blade, - /datum/deity_item/boon/holy_beacon, - /datum/deity_item/boon/black_death, - /datum/deity_item/blood_crafting/firecrafting, - /datum/deity_item/boon/starburst, - /datum/deity_item/boon/exchange_wounds, - /datum/deity_item/boon/radiant_aura, - /datum/deity_item/boon/burning_touch, - /datum/deity_item/boon/burning_grip, - /datum/deity_item/boon/blood_boil, - /datum/deity_item/boon/emp, - /datum/deity_item/boon/cure_light, - /datum/deity_item/phenomenon/herald, - /datum/deity_item/phenomenon/wisp, - /datum/deity_item/phenomenon/flickering_whisper, - /datum/deity_item/phenomenon/burning_glare, - /datum/deity_item/phenomenon/open_gateway, - /datum/deity_item/phenomenon/divine_right - ) - -/datum/god_form/starlight/take_charge(var/mob/living/user, var/charge) - charge = max(5, charge/100) - if(prob(charge)) - to_chat(user, SPAN_DANGER("Your body burns!")) - user.take_damage(charge, BURN) - return 1 \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/starlight/structures.dm b/mods/gamemodes/deity/forms/starlight/structures.dm deleted file mode 100644 index 7134d19ce481..000000000000 --- a/mods/gamemodes/deity/forms/starlight/structures.dm +++ /dev/null @@ -1,272 +0,0 @@ -/obj/structure/deity/altar/starlight - icon_state = "altarcandle" - -/obj/structure/deity/pylon/starlight - name = "sun pylon" - desc = "A miniature sun, floating ontop of a small pillar." - icon_state = "star_pylon" - -/obj/structure/deity/gateway - name = "gateway" - desc = "A gateway into the unknown." - icon = 'icons/obj/singularity.dmi' - icon_state = "singularity_s1" - power_adjustment = 1 - density = FALSE - var/weakref/target_ref - var/start_time = 0 - var/power_drain = 7 - var/looking_for - var/static/list/possible_forms = list( - "Starborn" = list( - "description" = "A species of hardy fire-wreathed soldiers.", - "message" = "As a Starborn, you are immune to laser-fire. You are a hardy soldier, able to take on the greatest of foes.", - "species" = "Starborn" - ), - "Blueforged" = list( - "description" = "Trans-dimensional beings with a multitude of miraculous abilities.", - "message" = "As a Blueforged, you are immune to all physical damage... except for heat. Not even your god can protect you.", - "species" = "Blueforged", - "spells" = list( - /spell/targeted/ethereal_jaunt, - /spell/targeted/shatter, - /spell/hand/burning_grip, - /spell/aoe_turf/disable_tech, - /spell/targeted/projectile/magic_missile, - /spell/open_gateway - ) - ), - "Shadowling" = list( - "description" = "Beings that come from a place of no light. They sneak from place to place, disabling everyone they touch.", - "message" = "As a Shadow you take damage from the light itself but have the ability to vanish from sight itself.", - "species" = "Shadow", - "spells" = list( - /spell/veil_of_shadows, - /spell/targeted/subjugation, - /spell/targeted/projectile/magic_missile - ) - ) - ) - -/obj/structure/deity/gateway/Initialize() - . = ..() - if(linked_god) - linked_god.power_per_regen -= power_drain - START_PROCESSING(SSobj, src) - -/obj/structure/deity/gateway/Process() - if(!linked_god) - return - if(linked_god.power <= 0) - to_chat(linked_god,SPAN_WARNING("\The [src] disappears from your lack of power!")) - qdel(src) - return - var/mob/living/human/target - if(target_ref) - target = target_ref.resolve() - if(target) - if(get_turf(target) != get_turf(src)) - target = null - target_ref = null - start_time = 0 - return - else if(prob(5)) - to_chat(target,SPAN_DANGER("\The [src] sucks at your lifeforce!")) - if(start_time && world.time > start_time + 300) - start_time = 0 - to_chat(target,SPAN_DANGER("You have been sucked into \the [src], your soul used to fuel \the [linked_god]'s minions.")) - var/mob/living/starlight_soul/ss = new(get_turf(linked_god),target) - if(target.mind) - target.mind.transfer_to(ss) - else - ss.ckey = target.ckey - ss.set_deity(linked_god) - target.dust() - if(power_drain >= 3) - linked_god.power_per_regen += 3 - power_drain -= 3 - else - //Get new target - var/mob/living/human/T = locate() in get_turf(src) - if(T) - target_ref = weakref(T) - start_time = world.time - to_chat(T, SPAN_DANGER("You feel your lifeforce begin to drain into \the [src]!")) - -/obj/structure/deity/gateway/Destroy() - linked_god.power_per_regen += power_drain - . = ..() - -/obj/structure/deity/gateway/attack_deity(var/mob/living/deity/deity) - var/list/html = list() - html += "

Servant List

" - html += "
Select a minion type to summon
" - html += "" - for(var/a in possible_forms) - var/list/form = possible_forms[a] - html += "" - html += "
NameDescription
[a][form["description"]]
" - show_browser(linked_god, jointext(html, null), "window=gateway") - -/obj/structure/deity/gateway/CanUseTopic(var/mob/user) - if(linked_god && (user == linked_god || user.loc == linked_god.loc)) - return STATUS_INTERACTIVE - return STATUS_CLOSE - -/obj/structure/deity/gateway/proc/stop_looking_for(var/successful) - if(looking_for) - if(!successful) - to_chat(linked_god, SPAN_WARNING("\The [src] did not find any [looking_for]. You may try again if you wish.")) - looking_for = null - -/obj/structure/deity/gateway/OnTopic(var/mob/user, var/list/href_list) - if(href_list["accept"] && istype(user,/mob/living/starlight_soul)) - if(href_list["accept"] != looking_for) - return TOPIC_HANDLED - var/mob/living/human/H = new(get_turf(src)) - user.mind.transfer_to(H) - H.set_species(possible_forms[looking_for]["species"]) - for(var/s in possible_forms[looking_for]["spells"]) - var/spell/S = new s - H.add_spell(S) - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - godcult.add_antagonist_mind(H.mind, 1, "[looking_for] of [linked_god]", "You are a powerful entity in the service to \the [linked_god]. [possible_forms[looking_for]["species"]]", specific_god = linked_god) - stop_looking_for(TRUE) - - return TOPIC_HANDLED - if(href_list["spawn_type"] && user == linked_god) - if(looking_for) - to_chat(usr, SPAN_WARNING("\The [src] is already looking for a [looking_for].")) - else - looking_for = href_list["spawn_type"] - to_chat(usr, SPAN_NOTICE("\The [src] is now looking for a [looking_for].")) - for(var/l in get_turf(linked_god)) - if(istype(l, /mob/living/starlight_soul)) - to_chat(l, "\The [src] is looking for a soul to become a [looking_for]. Accept? (Yes)") - addtimer(CALLBACK(src, PROC_REF(stop_looking_for), FALSE), 30 SECONDS) - show_browser(linked_god, null, "window=gateway") - return TOPIC_HANDLED - -/obj/structure/deity/radiant_statue - name = "radiant statue" - icon_state = "statue" - build_cost = 750 - power_adjustment = 1 - deity_flags = DEITY_STRUCTURE_NEAR_IMPORTANT|DEITY_STRUCTURE_ALONE - var/charge = 0 - var/charging = 0 //Charging, dispersing, etc. - -/obj/structure/deity/radiant_statue/on_update_icon() - ..() - if(charging) - icon_state = "statue_charging" - else if(charge) - icon_state = "statue_active" - else - icon_state = "statue" - -/obj/structure/deity/radiant_statue/Destroy() - if(charging) - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/structure/deity/radiant_statue/proc/get_followers_nearby() - . = list() - if(linked_god) - for(var/m in linked_god.minions) - var/datum/mind/M = m - if(get_dist(M.current, src) <= 3) - . += M.current - -/obj/structure/deity/radiant_statue/attack_hand(var/mob/L) - SHOULD_CALL_PARENT(FALSE) - var/obj/O = L.get_equipped_item(slot_wear_suit_str) - if(O && has_extension(O,/datum/extension/deity_be_near)) - if(activate_charging()) - to_chat(L, SPAN_NOTICE("You place your hands on \the [src], feeling your master's power course through you.")) - else - to_chat(L, SPAN_WARNING("\The [src] has already been activated.")) - else - to_chat(L, SPAN_WARNING("\The [src] does not recognize you as a herald of \the [linked_god]. You must wear a full set of herald's armor.")) - return TRUE - -/obj/structure/deity/radiant_statue/attack_deity(var/mob/living/deity/deity) - if(activate_charging()) - to_chat(deity,SPAN_NOTICE("You activate \the [src], and it begins to charge as long as at least one of your followers is nearby.")) - else - to_chat(deity,SPAN_WARNING("\The [src] is either already activated, or there are no followers nearby to charge it.")) - -/obj/structure/deity/radiant_statue/proc/activate_charging() - var/list/followers = get_followers_nearby() - if(is_processing || !followers.len) - return 0 - charging = 1 - START_PROCESSING(SSobj, src) - src.visible_message(SPAN_NOTICE("\The [src] hums, activating.")) - update_icon() - return 1 - -/obj/structure/deity/radiant_statue/attackby(var/obj/item/I, var/mob/user) - if(charging && (istype(I, /obj/item/knife/ritual/shadow) || istype(I, /obj/item/gun/energy/staff/beacon)) && charge_item(I, user)) - return - ..() - -/obj/structure/deity/radiant_statue/proc/charge_item(var/obj/item/I, var/mob/user) - . = 0 - if(istype(I, /obj/item/gun/energy)) - var/obj/item/gun/energy/energy = I - var/obj/item/cell/power_supply = energy.get_cell() - if(power_supply) - power_supply.give(energy.charge_cost * energy.max_shots) - . = 1 - else if(istype(I ,/obj/item/knife/ritual/shadow)) - var/obj/item/knife/ritual/shadow/shad = I - shad.charge = initial(shad.charge) - . = 1 - if(.) - to_chat(user, SPAN_NOTICE("\The [src]'s glow envelops \the [I], restoring it to proper use.")) - charge -= 1 - -/obj/structure/deity/radiant_statue/Process() - if(charging) - charge++ - var/list/followers = get_followers_nearby() - if(followers.len == 0) - stop_charging() - return - - if(charge == 40) - src.visible_message(SPAN_NOTICE("\The [src] lights up, pulsing with energy.")) - charging = 0 - update_icon() - else - charge -= 0.5 - var/list/followers = get_followers_nearby() - if(followers.len) - for(var/m in followers) - var/mob/living/L = m - L.heal_damage(BURN, 5) - if(prob(5)) - to_chat(L, SPAN_NOTICE("You feel a pleasant warmth spread throughout your body...")) - for(var/s in L.mind.learned_spells) - var/spell/spell = s - spell.charge_counter = spell.charge_max - if(charge == 0) - stop_charging() - -/obj/structure/deity/radiant_statue/proc/stop_charging() - STOP_PROCESSING(SSobj, src) - src.visible_message(SPAN_NOTICE("\The [src] powers down, returning to its dormant form.")) - charging = 0 - update_icon() - -/obj/structure/deity/blood_forge/starlight - name = "radiant forge" - desc = "a swath of heat and fire permeats from this forge." - recipe_feat_list = "Fire Crafting" - text_modifications = list( - "Cost" = "Burn", - "Dip" = "fire. Pain envelopes you as dark burns mar your hands and you begin to shape it into something more useful", - "Shape" = "You shape the fire, ignoring the painful burns it gives you in the process.", - "Out" = "flames" - ) diff --git a/mods/gamemodes/deity/forms/tower/deity_items/conjuration.dm b/mods/gamemodes/deity/forms/tower/deity_items/conjuration.dm deleted file mode 100644 index 0d6f820540ba..000000000000 --- a/mods/gamemodes/deity/forms/tower/deity_items/conjuration.dm +++ /dev/null @@ -1,107 +0,0 @@ -/datum/deity_item/conjuration - name = DEITY_TREE_CONJURATION - desc = "Conjuration is the school of creation and teleportation, summoning fireballs or teleporting long distances, this school is extremely powerful." - category = DEITY_TREE_CONJURATION - max_level = 3 - base_cost = 50 - -/datum/deity_item/conjuration/get_cost(var/mob/living/deity/D) - return base_cost * (level + 1) - -//Level 1 -/datum/deity_item/boon/single_charge/create_air - name = "Create Air" - desc = "Allows your follower to generate a livable atmosphere in the area they are in." - base_cost = 25 - category = DEITY_TREE_CONJURATION - boon_path = /spell/create_air/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/boon/single_charge/acid_spray - name = "Acid Spray" - desc = "The simplest form of aggressive conjuration: acid spray is quite effective in melting both man and object." - base_cost = 130 - category = DEITY_TREE_CONJURATION - boon_path = /spell/acid_spray/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/boon/single_charge/force_wall - name = "Force Wall" - desc = "A temporary invincible wall for followers to summon." - base_cost = 30 - category = DEITY_TREE_CONJURATION - boon_path = /spell/aoe_turf/conjure/forcewall/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/phenomenon/dimensional_locker - name = "Phenomenon: Dimensional Locker" - desc = "Gain the ability to move a magical locker around. While it cannot move living things, you can move it around as you please, even disappearing it into the nether." - base_cost = 50 - category = DEITY_TREE_CONJURATION - phenomenon_path = /datum/phenomenon/movable_object/dimensional_locker - requirements = list(DEITY_TREE_CONJURATION = 1) - -//Level 2 -/datum/deity_item/boon/single_charge/faithful_hound - name = "Faithful Hound" - desc = "This spell allows a follower to summon a singular spectral dog that guards the nearby area. Anyone without the password is barked at or bitten." - base_cost = 40 - category = DEITY_TREE_CONJURATION - boon_path = /spell/aoe_turf/conjure/faithful_hound/tower - requirements = list(DEITY_TREE_CONJURATION = 2) - -/datum/deity_item/wizard_armaments - name = DEITY_UNLOCK_ARMS - desc = "Unlock spells related to the summoning of weapons and armor. These spells only last a short duration, but are extremely effective." - base_cost = 25 - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 2) - -/datum/deity_item/boon/single_charge/sword - name = "Summon Sword" - desc = "This spell allows your followers to summon a golden firey sword for a short duration." - base_cost = 50 - boon_path = /spell/targeted/equip_item/dyrnwyn/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_UNLOCK_ARMS = 1) - -/datum/deity_item/boon/single_charge/shield - name = "Summon Shield" - desc = "This spell allows your followers to summon a magical shield for a short duration." - base_cost = 20 - boon_path = /spell/targeted/equip_item/shield/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_UNLOCK_ARMS = 1) - -/datum/deity_item/phenomenon/portals - name = "Phenomenon: Portals" - desc = "Gain the ability to create portals for your followers to enter through. You will need to create two for it work. Any created past that will delete the oldest portal." - base_cost = 75 - requirements = list(DEITY_TREE_CONJURATION = 2) - category = DEITY_TREE_CONJURATION - phenomenon_path = /datum/phenomenon/portals - -//Level 3 -/datum/deity_item/boon/single_charge/fireball - name = "Fireball" - desc = "Embue your follower with the power of exploding fire." - base_cost = 85 - boon_path = /spell/targeted/projectile/dumbfire/fireball/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 3) - -/datum/deity_item/boon/single_charge/force_portal - name = "Force Portal" - desc = "This spell allows a follower to summon a force portal. Anything that hits the portal gets sucked inside and is then thrown out when the portal explodes." - base_cost = 45 - boon_path = /spell/aoe_turf/conjure/force_portal/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 3) - -/datum/deity_item/phenomenon/banishing_smite - name = "Phenomenon: Banishing Smite" - desc = "Gain the ability to smite an individual, dealing damage to them. If they are weakened enough, this can cause them to temporarily be transported." - base_cost = 75 - requirements = list(DEITY_TREE_CONJURATION = 3) - category = DEITY_TREE_CONJURATION - phenomenon_path = /datum/phenomenon/banishing_smite \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/tower/deity_items/transmutation.dm b/mods/gamemodes/deity/forms/tower/deity_items/transmutation.dm deleted file mode 100644 index 5eb1dd34785c..000000000000 --- a/mods/gamemodes/deity/forms/tower/deity_items/transmutation.dm +++ /dev/null @@ -1,97 +0,0 @@ -/datum/deity_item/transmutation - name = DEITY_TREE_TRANSMUTATION - desc = "Transmutation is the school of change. It cannot be used to create things, only modify them or even destroy them." - category = DEITY_TREE_TRANSMUTATION - max_level = 3 - base_cost = 50 - -/datum/deity_item/conjuration/get_cost(var/mob/living/deity/D) - return base_cost * (level + 1) - -//Level 1 -/datum/deity_item/boon/single_charge/slippery_surface - name = "Slippery Surface" - desc = "Allows a follower to slicken a small patch of floor. Anyone without sure-footing will find it hard to stay upright." - base_cost = 10 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/hand/slippery_surface/tower - -/datum/deity_item/boon/single_charge/smoke - name = "Smoke" - desc = "Allows a follower to distill the nearby air into smoke." - base_cost = 10 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/aoe_turf/smoke/tower - -//Level 2 -/datum/deity_item/boon/single_charge/knock - name = "Knock" - desc = "Allows a follower to open nearby doors without the keys." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/aoe_turf/knock/tower - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - -/datum/deity_item/boon/single_charge/burning_grip - name = "Burning Grip" - desc = "Allows a follower cause an object to heat up intensly in someone's hand, making them drop it and whatever skin is attached." - base_cost = 15 - boon_path = /spell/hand/burning_grip/tower - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - -/datum/deity_item/phenomenon/warp_body - name = "Phenomenon: Warp Body" - desc = "Gain the ability to warp the very structure of a target's body, wracking pain and weakness." - base_cost = 75 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - phenomenon_path = /datum/phenomenon/warp - -//Level 3 -/datum/deity_item/boon/single_charge/jaunt - name = "Ethereal Jaunt" - desc = "Allows a follower to liquify for a short duration, letting them pass through all dense objects." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/targeted/ethereal_jaunt/tower - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - -/datum/deity_item/healing_spells - name = DEITY_UNLOCK_HEAL - desc = "Of transmutation, healing is perhaps the most immediately effective and useful. This unlocks the healing spells for your followers." - base_cost = 50 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - -/datum/deity_item/boon/single_charge/heal - name = "Minor Heal" - desc = "Allows your follower to heal themselves, or others, for a slight amount." - base_cost = 15 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - boon_path = /spell/targeted/heal_target/tower - -/datum/deity_item/boon/single_charge/heal/major - name = "Major Heal" - desc = "Allows your follower to heal others for a great amount." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - boon_path = /spell/targeted/heal_target/major/tower - -/datum/deity_item/boon/single_charge/heal/area - name = "Area Heal" - desc = "Allows your follower to heal everyone in an area for minor damage." - base_cost = 20 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - boon_path = /spell/targeted/heal_target/area/tower - -/datum/deity_item/phenomenon/rock_form - name = "Phenomenon: Rock Form" - desc = "Gain the ability to transform your followers into beings of rock and stone." - base_cost = 75 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - phenomenon_path = /datum/phenomenon/rock_form \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/tower/spells.dm b/mods/gamemodes/deity/forms/tower/spells.dm deleted file mode 100644 index 18b88647edfe..000000000000 --- a/mods/gamemodes/deity/forms/tower/spells.dm +++ /dev/null @@ -1,67 +0,0 @@ -/spell/create_air/tower - desc = "Allows you to generate a livable atmosphere in the area you are in." - charge_max = 5 - -/spell/hand/burning_grip/tower - desc = "Allows you cause an object to heat up intensly in someone's hand, making them drop it and whatever skin is attached." - charge_max = 3 - -/spell/hand/slippery_surface/tower - desc = "Allows you to slicken a small patch of floor. Anyone without sure-footing will find it hard to stay upright." - charge_max = 2 - -/spell/aoe_turf/knock/tower - charge_max = 2 - hidden_from_codex = TRUE - -/spell/aoe_turf/smoke/tower - charge_max = 2 - hidden_from_codex = TRUE - -/spell/aoe_turf/conjure/faithful_hound/tower - desc = "This spell allows you to summon a singular spectral dog that guards the nearby area. Anyone without the password is barked at or bitten." - charge_max = 1 - spell_flags = 0 - -/spell/aoe_turf/conjure/force_portal/tower - desc = "This spell allows you to summon a force portal. Anything that hits the portal gets sucked inside and is then thrown out when the portal explodes." - charge_max = 2 - spell_flags = 0 - -/spell/acid_spray/tower - desc = "The simplest form of aggressive conjuration: acid spray is quite effective in melting both man and object." - charge_max = 2 - -/spell/targeted/heal_target/tower - desc = "Allows you to heal yourself, or others, for a slight amount." - charge_max = 2 - -/spell/targeted/heal_target/major/tower - charge_max = 1 - spell_flags = INCLUDEUSER | SELECTABLE - desc = "Allows you to heal others for a great amount." - -/spell/targeted/heal_target/area/tower - desc = "Allows you to heal everyone in an area for minor damage." - charge_max = 1 - -/spell/targeted/ethereal_jaunt/tower - desc = "Allows you to liquefy for a short duration, letting you pass through all dense objects." - charge_max = 2 - spell_flags = Z2NOCAST | INCLUDEUSER - -/spell/aoe_turf/conjure/forcewall/tower - desc = "A temporary invincible wall for you to summon." - charge_max = 3 - -/spell/targeted/equip_item/dyrnwyn/tower - desc = "This spell allows you to summon a fiery golden sword for a short duration." - charge_max = 1 - -/spell/targeted/equip_item/shield/tower - desc = "This spell allows you to summon a magical shield for a short duration." - charge_max = 1 - -/spell/targeted/projectile/dumbfire/fireball/tower - desc = "Imbue yourself with the power of exploding fire." - charge_max = 2 \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/tower/structures.dm b/mods/gamemodes/deity/forms/tower/structures.dm deleted file mode 100644 index 453caf22de25..000000000000 --- a/mods/gamemodes/deity/forms/tower/structures.dm +++ /dev/null @@ -1,25 +0,0 @@ -/obj/structure/deity/altar/tower - icon_state = "tomealtar" - -/obj/structure/deity/wizard_recharger - name = "fountain of power" - desc = "Refreshing, cool water surrounded by archaic carvings." - icon_state = "fountain" - power_adjustment = 2 - build_cost = 700 - -/obj/structure/deity/wizard_recharger/attack_hand(var/mob/hitter) - SHOULD_CALL_PARENT(FALSE) - if(!length(hitter.mind?.learned_spells)) - to_chat(hitter, SPAN_WARNING("You don't feel as if this will do anything for you.")) - return TRUE - - hitter.visible_message(SPAN_NOTICE("\The [hitter] dips their hands into \the [src], a soft glow emanating from them.")) - if(do_after(hitter,300,src,check_holding=0)) - for(var/s in hitter.mind.learned_spells) - var/spell/spell = s - spell.charge_counter = spell.charge_max - to_chat(hitter, SPAN_NOTICE("You feel refreshed!")) - else - to_chat(hitter, SPAN_WARNING("You need to keep in contact with \the [src]!")) - return TRUE \ No newline at end of file diff --git a/mods/gamemodes/deity/forms/tower/tower.dm b/mods/gamemodes/deity/forms/tower/tower.dm deleted file mode 100644 index 37f63bce440e..000000000000 --- a/mods/gamemodes/deity/forms/tower/tower.dm +++ /dev/null @@ -1,49 +0,0 @@ -/datum/god_form/wizard - name = "The Tower" - info = {"Only from destruction does the Tower grow. Its bricks smelted from crumbled ignorance and the fires of ambition.
- Benefits:
- +Learn spells from two different schools.
- +Deity gains power through each spell use.

- Drawbacks:
- -Abilities hold a limited amount of charge and must be charged at a fountain of power. - "} - desc = "A single solitary tower" - god_icon_state = "tower" - pylon_icon_state = "nim" - - buildables = list(/obj/structure/deity/altar/tower, - /obj/structure/deity/pylon, - /obj/structure/deity/wizard_recharger - ) - items = list(/datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/conjuration, - /datum/deity_item/boon/single_charge/create_air, - /datum/deity_item/boon/single_charge/acid_spray, - /datum/deity_item/boon/single_charge/force_wall, - /datum/deity_item/phenomenon/dimensional_locker, - /datum/deity_item/boon/single_charge/faithful_hound, - /datum/deity_item/wizard_armaments, - /datum/deity_item/boon/single_charge/sword, - /datum/deity_item/boon/single_charge/shield, - /datum/deity_item/phenomenon/portals, - /datum/deity_item/boon/single_charge/fireball, - /datum/deity_item/boon/single_charge/force_portal, - /datum/deity_item/phenomenon/banishing_smite, - /datum/deity_item/transmutation, - /datum/deity_item/boon/single_charge/slippery_surface, - /datum/deity_item/boon/single_charge/smoke, - /datum/deity_item/boon/single_charge/knock, - /datum/deity_item/boon/single_charge/burning_grip, - /datum/deity_item/phenomenon/warp_body, - /datum/deity_item/boon/single_charge/jaunt, - /datum/deity_item/healing_spells, - /datum/deity_item/boon/single_charge/heal, - /datum/deity_item/boon/single_charge/heal/major, - /datum/deity_item/boon/single_charge/heal/area, - /datum/deity_item/phenomenon/rock_form - ) - -/datum/god_form/wizard/take_charge(var/mob/living/user, var/charge) - linked_god.adjust_power_min(max(round(charge/100), 1),silent = 1) - return 1 \ No newline at end of file diff --git a/mods/gamemodes/deity/gamemode.dm b/mods/gamemodes/deity/gamemode.dm deleted file mode 100644 index 9bf79d8ca875..000000000000 --- a/mods/gamemodes/deity/gamemode.dm +++ /dev/null @@ -1,12 +0,0 @@ -/decl/game_mode/godmode - name = "Deity" - round_description = "An otherworldly beast has turned its attention to you and your fellow cremembers." - extended_round_description = "The station has been infiltrated by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" - uid = "god" - required_players = 10 - required_enemies = 3 - end_on_antag_death = FALSE - associated_antags = list( - /decl/special_role/deity, - /decl/special_role/godcultist - ) \ No newline at end of file diff --git a/mods/gamemodes/deity/god_cultist_role.dm b/mods/gamemodes/deity/god_cultist_role.dm deleted file mode 100644 index d1c5bced882a..000000000000 --- a/mods/gamemodes/deity/god_cultist_role.dm +++ /dev/null @@ -1,106 +0,0 @@ -/decl/special_role/godcultist - name = "God Cultist" - name_plural = "God Cultists" - blacklisted_jobs = list(/datum/job/submap) - antag_indicator = "hudcultist" - faction_verb = /mob/living/proc/dpray - welcome_text = "You are under the guidance of a powerful otherwordly being. Spread its will and keep your faith.
Use dpray to communicate directly with your master!
Ask your master for spells to start building!" - flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - hard_cap = 5 - hard_cap_round = 6 - initial_spawn_req = 3 - initial_spawn_target = 3 - antaghud_indicator = "hudcultist" - skill_setter = /datum/antag_skill_setter/station - blocked_job_event_categories = list(ASSIGNMENT_ROBOT, ASSIGNMENT_COMPUTER) - -/decl/special_role/godcultist/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg, var/mob/living/deity/specific_god) - if(!..()) - return 0 - - if(specific_god) - add_cultist(player, specific_god) - - return 1 - -/decl/special_role/godcultist/post_spawn() - var/decl/special_role/deity = GET_DECL(/decl/special_role/deity) - if(!deity.current_antagonists.len) - return - var/count = 1 - var/deity_count = 1 - while(count <= current_antagonists.len) - if(deity_count > deity.current_antagonists.len) - deity_count = 1 - var/datum/mind/deity_mind = deity.current_antagonists[deity_count] - var/datum/mind/mind = current_antagonists[count] - add_cultist(mind, deity_mind.current) - count++ - deity_count++ - - -/decl/special_role/godcultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) - var/mob/living/deity/god = get_deity(player) - if(!..()) - return 0 - remove_cultist(player, god) - return 1 - -/decl/special_role/godcultist/get_extra_panel_options(var/datum/mind/player) - return "\[Select Deity\]" - -/decl/special_role/godcultist/Topic(href, href_list) - if(..()) - return 1 - if(href_list["selectgod"]) - var/list/god_list = list() - var/decl/special_role/deity = GET_DECL(/decl/special_role/deity) - if(length(deity.current_antagonists)) - for(var/m in deity.current_antagonists) - var/datum/mind/mind = m - god_list += mind.current - else - for(var/mob/living/deity/specific_deity in global.player_list) - god_list += specific_deity - if(god_list.len) - var/mob/living/deity/D = input(usr, "Select a deity for this cultist.") in null|god_list - if(D) - var/datum/mind/player = locate(href_list["selectgod"]) - remove_cultist(player) //Remove him from any current deity. - add_cultist(player, D) - log_and_message_admins("has set [key_name(player.current)] to be a minion of [key_name(D)]") - else - to_chat(usr, SPAN_WARNING("There are no deities to be linked to.")) - return 1 - -/decl/special_role/godcultist/proc/add_cultist(var/datum/mind/player, var/mob/living/deity/deity) - deity.add_follower(player.current) - player.current.add_language(/decl/language/cultcommon) - -/decl/special_role/godcultist/proc/remove_cultist(var/datum/mind/player, var/mob/living/deity/god) - god.remove_follower(player.current) - player.current.remove_language(/decl/language/cultcommon) - -/decl/special_role/godcultist/proc/get_deity(var/datum/mind/player) - var/decl/special_role/deity = GET_DECL(/decl/special_role/deity) - for(var/m in deity.current_antagonists) - var/datum/mind/mind = m - var/mob/living/deity/god = mind.current - if(god && god.is_follower(player.current,1)) - return god - -/mob/living/proc/dpray(var/msg as text) - set category = "Abilities" - - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - if(!src.mind || !godcult.is_antagonist(mind)) - return - msg = sanitize(msg) - var/mob/living/deity/D = godcult.get_deity(mind) - if(!D || !msg) - return - - //Make em wait a few seconds. - src.visible_message("\The [src] bows their head down, muttering something.", SPAN_NOTICE("You send the message \"[msg]\" to your master.")) - to_chat(D, "\The [src] (J) prays, \"[msg]\"") - log_and_message_admins("dprayed, \"[msg]\" to \the [key_name(D)]") diff --git a/mods/gamemodes/deity/mobs/deity.dm b/mods/gamemodes/deity/mobs/deity.dm deleted file mode 100644 index 96fc8fb54da6..000000000000 --- a/mods/gamemodes/deity/mobs/deity.dm +++ /dev/null @@ -1,134 +0,0 @@ -/mob/living/deity - name = "shapeless creature" - desc = "A shape of otherworldly matter, not yet ready to be unleashed into this world." - icon = 'icons/mob/deity_big.dmi' - icon_state = "egg" - pixel_x = -128 - pixel_y = -128 - max_health = 100 - universal_understand = TRUE - mob_sort_value = 5 - is_spawnable_type = FALSE - butchery_data = null - - var/eye_type = /mob/observer/eye/freelook/cult - var/datum/visualnet/cultnet/eyenet - var/list/minions = list() //Minds of those who follow him - var/list/structures = list() //The objs that this dude controls. - var/list/feats = list() - var/datum/god_form/form - var/datum/current_boon - var/mob/living/following - -/mob/living/deity/Initialize() - . = ..() - eyenet = new() - eyeobj = new eye_type(get_turf(src), eyenet) - eyeobj.possess(src) - eyenet.add_source(src) - -/mob/living/deity/death(gibbed) - . = ..() - if(.) - for(var/m in minions) - var/datum/mind/M = m - remove_follower_spells(M) - to_chat(M.current, "Your connection has been severed! \The [src] is no more!") - sound_to(M.current, 'sound/hallucinations/far_noise.ogg') - SET_STATUS_MAX(M.current, STAT_WEAK, 10) - for(var/s in structures) - var/obj/structure/deity/S = s - S.linked_god = null - -/mob/living/deity/shared_nano_interaction() - if(stat == DEAD) - return STATUS_CLOSE - return STATUS_INTERACTIVE - -/mob/living/deity/Destroy() - - for(var/phenomenon in phenomena) - remove_phenomenon(phenomenon) - - if(length(items_by_category)) - for(var/cat in items_by_category) - var/list/L = items_by_category[cat] - L.Cut() - items_by_category.Cut() - - if(length(items)) - for(var/i in items) - qdel(items[i]) - items.Cut() - - death() - if(length(minions)) - minions.Cut() - if(length(structures)) - structures.Cut() - - if(eyeobj) - eyeobj.release() - QDEL_NULL(eyeobj) - QDEL_NULL(eyenet) //We do it here as some mobs have eyes that have access to the visualnet and we only want to destroy it when the deity is destroyed - - QDEL_NULL(form) - - return ..() - -/mob/living/deity/verb/return_to_plane() - set category = "Godhood" - - eyeobj.forceMove(get_turf(src)) - -/mob/living/deity/verb/choose_form() - set name = "Choose Form" - set category = "Godhood" - - var/dat = list() - dat += {"

Choose a Form

- This choice is permanent. Choose carefully, but quickly. - - - - - - "} - var/list/forms = subtypesof(/datum/god_form) - - for(var/form in forms) - var/datum/god_form/god = form - var/god_name = initial(god.name) - var/icon/god_icon = icon('icons/mob/mob.dmi', initial(god.pylon_icon_state)) - send_rsc(src,god_icon, "[god_name].png") - dat += {" - - - - "} - dat += "
NameThemeDescription
[god_name][initial(god.info)]
" - show_browser(src, JOINTEXT(dat), "window=godform;can_close=0") - -/mob/living/deity/proc/set_form(var/type) - form = new type(src) - to_chat(src, SPAN_NOTICE("You undergo a transformation into your new form!")) - spawn(1) - SetName(form.name) - var/newname = sanitize(input(src, "Choose a name for your new form.", "Name change", form.name) as text, MAX_NAME_LEN) - if(newname) - fully_replace_character_name(newname) - src.verbs -= /mob/living/deity/verb/choose_form - show_browser(src, null, "window=godform") - for(var/m in minions) - var/datum/mind/mind = m - var/mob/living/L = mind.current - L.faction = form.faction - -//Gets the name based on form, or if there is no form name, type. -/mob/living/deity/proc/get_type_name(var/type) - if(form && form.buildables[type]) - var/list/vars = form.buildables[type] - if(vars["name"]) - return vars["name"] - var/atom/movable/M = type - return initial(M.name) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_Stat.dm b/mods/gamemodes/deity/mobs/deity_Stat.dm deleted file mode 100644 index 6105b7f9af35..000000000000 --- a/mods/gamemodes/deity/mobs/deity_Stat.dm +++ /dev/null @@ -1,14 +0,0 @@ -/mob/living/deity/Stat() - . = ..() - if(statpanel("Status")) - stat("Structure Num", structures.len) - stat("Minion Num", minions.len) - var/boon_name = "None" - if(current_boon) - if(istype(current_boon, /spell)) - var/spell/S = current_boon - boon_name = S.name - else - var/obj/O = current_boon - boon_name = O.name - stat("Current Boon",boon_name) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_boons.dm b/mods/gamemodes/deity/mobs/deity_boons.dm deleted file mode 100644 index da05d9a5ff2b..000000000000 --- a/mods/gamemodes/deity/mobs/deity_boons.dm +++ /dev/null @@ -1,54 +0,0 @@ -/mob/living/deity/proc/set_boon(var/datum/boon) - if(current_boon) - qdel(current_boon) - current_boon = boon - to_chat(src, SPAN_NOTICE("You now have the boon [boon]")) - if(istype(boon, /atom/movable)) - var/atom/movable/A = boon - nano_data["boon_name"] = A.name - A.forceMove(src) - else if(istype(boon, /spell)) - var/spell/S = boon - nano_data["boon_name"] = S.name - -/mob/living/deity/proc/grant_boon(var/mob/living/L) - if(istype(current_boon, /spell) && !grant_spell(L, current_boon)) - return - else if(istype(current_boon, /obj/item)) - var/obj/item/I = current_boon - I.dropInto(L.loc) - var/origin_text = "on the floor" - if(L.equip_to_appropriate_slot(I)) - origin_text = "on your body" - else if(L.put_in_hands_or_del(I)) - origin_text = "in your hands" - else - var/obj/O = L.equip_to_storage(I) - if(O) - origin_text = "in \the [O]" - to_chat(L, SPAN_NOTICE("It appears [origin_text].")) - - to_chat(L, SPAN_OCCULT("\The [src] grants you a boon of [current_boon]!")) - to_chat(src, SPAN_NOTICE("You give \the [L] a boon of [current_boon].")) - log_and_message_admins("gave [key_name(L)] the boon [current_boon]") - current_boon = null - nano_data["boon_name"] = null - return - -/mob/living/deity/proc/grant_spell(var/mob/living/target, var/spell/spell) - var/datum/mind/M = target.mind - for(var/s in M.learned_spells) - var/spell/S = s - if(istype(S, spell.type)) - to_chat(src, SPAN_WARNING("They already know that spell!")) - return 0 - target.add_spell(spell) - spell.set_connected_god(src) - to_chat(target, SPAN_NOTICE("You feel a surge of power as you learn the art of [current_boon].")) - return 1 - -/* This is a generic proc used by the God to enact a sacrifice from somebody. Power is a value of magnitude. -*/ -/mob/living/deity/proc/take_charge(var/mob/living/L, var/power) - if(form) - form.take_charge(L, power) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_click.dm b/mods/gamemodes/deity/mobs/deity_click.dm deleted file mode 100644 index aae71fd6257d..000000000000 --- a/mods/gamemodes/deity/mobs/deity_click.dm +++ /dev/null @@ -1,24 +0,0 @@ -/mob/living/deity/ClickOn(var/atom/A, var/params) - if(A == src) - if(form) - ui_interact(src) - else - choose_form() - return - var/list/modifiers = params2list(params) - if(modifiers["shift"] || modifiers["ctrl"]) - if(silenced) - to_chat(src, SPAN_WARNING("You cannot do that as you are silenced!")) - else - var/datum/phenomenon/phenomenon = get_phenomenon(modifiers["shift"], modifiers["ctrl"]) - if(phenomenon) - phenomenon.Click(A) - return - if(current_boon && is_follower(A)) - grant_boon(A) - else if(istype(A, /obj/structure/deity)) - var/obj/structure/deity/D = A - if(D.linked_god == src) - D.attack_deity(src) - return - ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_hud.dm b/mods/gamemodes/deity/mobs/deity_hud.dm deleted file mode 100644 index 12824de99040..000000000000 --- a/mods/gamemodes/deity/mobs/deity_hud.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/deity - hud_used = /datum/hud/deity - -/datum/hud/deity/FinalizeInstantiation() - action_intent = new /obj/screen/intent/deity(null, mymob) - adding += action_intent - ..() - var/obj/screen/intent/deity/D = action_intent - D.sync_to_mob(mymob) diff --git a/mods/gamemodes/deity/mobs/deity_items.dm b/mods/gamemodes/deity/mobs/deity_items.dm deleted file mode 100644 index 3dfa6e4dc642..000000000000 --- a/mods/gamemodes/deity/mobs/deity_items.dm +++ /dev/null @@ -1,33 +0,0 @@ -/mob/living/deity - var/list/items - var/list/items_by_category - -/mob/living/deity/proc/set_items(var/list/_items) - items = _items - items_by_category = list() - for(var/i in items) - var/datum/deity_item/di = items[i] - if(!items_by_category[di.category]) - items_by_category[di.category] = list() - items_by_category[di.category] += di - -/mob/living/deity/proc/has_item(var/name, var/minimum_level = 1) - if(!(name in items)) - return FALSE - var/datum/deity_item/di = items[name] - . = di.level >= minimum_level - -/mob/living/deity/proc/upgrade_item(var/name) - if(!(name in items)) - return FALSE - var/datum/deity_item/di = items[name] - if(!di.can_buy(src)) - return FALSE - di.buy(src) - . = TRUE - -/mob/living/deity/proc/get_item_level(var/name) - . = 0 - if(items[name]) - var/datum/deity_item/di = items[name] - . = di.level diff --git a/mods/gamemodes/deity/mobs/deity_phenomena.dm b/mods/gamemodes/deity/mobs/deity_phenomena.dm deleted file mode 100644 index a5abe64946a2..000000000000 --- a/mods/gamemodes/deity/mobs/deity_phenomena.dm +++ /dev/null @@ -1,94 +0,0 @@ -/mob/living/deity - var/silenced = 0 - var/list/phenomena = list() - var/list/intent_phenomena = list() - var/static/list/control_types = list("control", "controlshift", "shift") - - -/mob/living/deity/Initialize() - . = ..() - for(var/decl/intent/intent as anything in decls_repository.get_decls_of_type_unassociated(/decl/intent)) //Just in case we somehow remove/add a new intent #futureproofing - populate_intent(intent) - set_phenomenon(add_phenomenon(/datum/phenomenon/communicate), GET_DECL(/decl/intent/disarm), "shift") - set_phenomenon(add_phenomenon(/datum/phenomenon/punish), GET_DECL(/decl/intent/help), "control") - set_phenomenon(add_phenomenon(/datum/phenomenon/point), GET_DECL(/decl/intent/help), "controlshift") - set_phenomenon(add_phenomenon(/datum/phenomenon/conversion), GET_DECL(/decl/intent/grab), "shift") - set_phenomenon(add_phenomenon(/datum/phenomenon/forced_conversion), GET_DECL(/decl/intent/grab), "control") - -/mob/living/deity/proc/silence(amount) - if(!silenced) - to_chat(src, SPAN_WARNING("You've been silenced! Your phenomena are disabled!")) - var/obj/screen/intent/deity/SD = istype(hud_used) && hud_used.action_intent - if(istype(SD)) - SD.color = "#ff0000" - silenced += amount - for(var/phenom in phenomena) //Also make it so that you don't do cooldowns. - var/datum/phenomenon/P = phenomena[phenom] - if(P.refresh_time) - P.refresh_time += amount - -/mob/living/deity/handle_regular_status_updates() - . = ..() - if(.) - if(silenced > 0) - silenced-- - if(!silenced) - to_chat(src, SPAN_NOTICE("You are no longer silenced.")) - var/obj/screen/intent/deity/SD = istype(hud_used) && hud_used.action_intent - if(istype(SD)) - SD.color = null - if(power_per_regen < 0 || power < power_min) - adjust_power(power_per_regen) - -/mob/living/deity/proc/add_phenomenon(phenomena_type) - LAZYINITLIST(phenomena) - for(var/P in phenomena) - if(istype(phenomena[P], phenomena_type)) - return - var/datum/phenomenon/P = new phenomena_type(src) - phenomena[P.name] = P - return P - -/mob/living/deity/proc/remove_phenomena_from_intent(decl/intent/intent, modifier, update = 1) - var/list/intent_list = intent_phenomena[intent] - intent_list[modifier] = null - if(update) - update_phenomena_bindings() - -/mob/living/deity/proc/remove_phenomenon(to_remove) - var/datum/phenomenon/P = phenomena[to_remove] - phenomena -= to_remove // this isn't going to work, is it? - for(var/intent in intent_phenomena) - var/list/intent_list = intent_phenomena[intent] - for(var/mod in intent_list) - if(intent_list[mod] == P) - intent_list[mod] = null - var/obj/screen/intent/deity/SD = istype(hud_used) && hud_used.action_intent - if(istype(SD)) - SD.update_text() - update_phenomena() - update_phenomena_bindings() - if(selected == to_remove) - selected = null - qdel(P) - -/mob/living/deity/proc/populate_intent(decl/intent/intent) - LAZYDISTINCTADD(intent_phenomena[intent], control_types) - -/mob/living/deity/proc/set_phenomenon(datum/phenomenon/phenomenon, decl/intent/intent, modifiers) - if(!LAZYACCESS(intent_phenomena, intent)) - populate_intent(intent) - var/list/intent_list = intent_phenomena[intent] - intent_list[modifiers] = phenomenon - -/mob/living/deity/proc/get_phenomenon(shift = 0, control = 0) - var/list/intent_list = intent_phenomena[get_intent()] - if(intent_list) - var/type = "" - if(shift) - type = "shift" - if(control) - type = "control[type]" - if(intent_list[type]) - return intent_list[type] - return null \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_power.dm b/mods/gamemodes/deity/mobs/deity_power.dm deleted file mode 100644 index ffe073b014a3..000000000000 --- a/mods/gamemodes/deity/mobs/deity_power.dm +++ /dev/null @@ -1,21 +0,0 @@ -/mob/living/deity - var/power = 0 - var/power_min = 10 - var/power_per_regen = 1 - -/mob/living/deity/proc/adjust_power(var/amount) - if(amount) - power = max(0, power + amount) - -/mob/living/deity/proc/adjust_power_min(var/amount, var/silent = 0, var/msg) - if(amount) - power_min = max(initial(power_min), power_min + amount) - if(!silent) - var/feel = "" - if(abs(amount) > 20) - feel = " immensely" - else if(abs(amount) > 10) - feel = " greatly" - if(abs(amount) >= 5) - var/class = amount > 0 ? "notice" : "warning" - to_chat(src, "You feel your power [amount > 0 ? "increase" : "decrease"][feel][msg ? " [msg]" : ""]") \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_pylon.dm b/mods/gamemodes/deity/mobs/deity_pylon.dm deleted file mode 100644 index 7f84dc5b339b..000000000000 --- a/mods/gamemodes/deity/mobs/deity_pylon.dm +++ /dev/null @@ -1,21 +0,0 @@ -/mob/living/deity - var/image/pylon_image - var/obj/structure/deity/pylon/pylon - -/mob/living/deity/set_form(var/type) - ..() - pylon_image = image('icons/mob/mob.dmi', icon_state = form.pylon_icon_state) - pylon_image.alpha = 180 - -/mob/living/deity/proc/possess_pylon(var/obj/structure/deity/pylon/P) - if(pylon) - leave_pylon() - pylon = P - pylon.overlays += pylon_image - playsound(pylon,'sound/effects/phasein.ogg',40,1) - -/mob/living/deity/proc/leave_pylon() - if(!pylon) - return - pylon.overlays -= pylon_image - pylon = null \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_sources.dm b/mods/gamemodes/deity/mobs/deity_sources.dm deleted file mode 100644 index a1ec947983d8..000000000000 --- a/mods/gamemodes/deity/mobs/deity_sources.dm +++ /dev/null @@ -1,84 +0,0 @@ -/mob/living/deity/proc/add_follower(var/mob/living/L) - if(is_follower(L, silent=1)) - return - - adjust_source(3, L) - minions += L.mind - var/spell/construction/C = new() - L.add_spell(C) - C.set_connected_god(src) - if(form) - L.faction = form.faction - update_followers() - events_repository.register(/decl/observ/destroyed, L,src, PROC_REF(dead_follower)) - events_repository.register(/decl/observ/death, L,src, PROC_REF(update_followers)) - -/mob/living/deity/proc/dead_follower(var/mob/living/L) - events_repository.unregister(/decl/observ/death, L,src) - events_repository.unregister(/decl/observ/destroyed, L,src) - -/mob/living/deity/proc/remove_follower_spells(var/datum/mind/M) - if(M.learned_spells) - for(var/s in M.learned_spells) - var/spell/S = s - if(S.connected_god == src) - M.current.remove_spell(S) - qdel(S) - -/mob/living/deity/proc/remove_follower(var/mob/living/L) - if(!is_follower(L, silent=1)) - return - - adjust_source(-3, L) - minions -= L.mind - L.faction = MOB_FACTION_NEUTRAL - if(L.mind) - remove_follower_spells(L.mind) - update_followers() - - -/mob/living/deity/proc/adjust_source(var/amount, var/atom/source, var/silent = 0, var/msg) - adjust_power_min(amount, silent, msg) - if(!ismovable(source)) - return - if(amount > 0) - eyenet.add_source(source) - if(istype(source, /obj/structure/deity)) - structures |= source - else - eyenet.remove_source(source) - if(istype(source, /obj/structure/deity)) - structures -= source - -/mob/living/deity/proc/is_follower(var/mob/living/L, var/silent = 0) - if(istype(L)) - if(L.mind) - if(L.mind in minions) - return 1 - if(!silent) - to_chat(src, SPAN_WARNING("You do not feel a malleable mind behind that frame.")) - return 0 - -/mob/living/deity/fully_replace_character_name(var/new_name, var/in_depth = TRUE) - if(!..()) - return 0 - for(var/m in minions) - var/datum/mind/minion = m - to_chat(minion.current, "Your master is now known as [new_name].") - minion.assigned_special_role = "Servant of [new_name]" - eyeobj.SetName("[src] ([eyeobj.name_sufix])") - nano_data["name"] = new_name - return 1 - -//Whether we are near an important structure. -/mob/living/deity/proc/near_structure(var/atom/A, var/all_structures = 0) - var/turf/T = get_turf(A) - for(var/s in structures) - if(!all_structures) - var/obj/structure/deity/D = s - if(D.deity_flags & DEITY_STRUCTURE_NEAR_IMPORTANT)//If it needs to be near an important structure, it isn't important. - continue - - if(get_dist(T, s) <= 3) - return 1 - return 0 \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_topic.dm b/mods/gamemodes/deity/mobs/deity_topic.dm deleted file mode 100644 index 4ff775043939..000000000000 --- a/mods/gamemodes/deity/mobs/deity_topic.dm +++ /dev/null @@ -1,56 +0,0 @@ -/mob/living/deity/OnSelfTopic(list/href_list) - if(href_list["form"]) - var/type = locate(href_list["form"]) in subtypesof(/datum/god_form) - if(type) - set_form(type) - return TOPIC_HANDLED - if(href_list["select_phenomenon"]) - nano_data["phenomenaMenu"] = 1 - selected = phenomena[href_list["select_phenomenon"]] - nano_data["selectedPhenomenaName"] = selected.name - return TOPIC_HANDLED - if(href_list["clear_selected"]) - nano_data["phenomenaMenu"] = 0 - selected = null - nano_data["selectedPhenomenaName"] = null - return TOPIC_HANDLED - if(href_list["select_intent"]) - var/decl/intent/intent = locate(href_list["select_intent"]) - if(!istype(intent)) - return TOPIC_NOACTION - var/binding = href_list["select_binding"] - var/list/phenomenon = intent_phenomena[intent] - if(phenomenon[binding]) - remove_phenomena_from_intent(intent, binding, 0) - if(selected) - set_phenomenon(selected, intent, binding) - update_phenomena_bindings() - return TOPIC_HANDLED - - if(href_list["jump"]) - var/atom/a = locate(href_list["jump"]) - var/follow = 0 - if(href_list["follow"]) - follow = 1 - if(a) - if(following) - stop_follow() - eyeobj.setLoc(get_turf(a)) - if(follow) - follow_follower(a) - to_chat(src, SPAN_NOTICE("[follow ? "Following" : "Jumping to"] \the [a]")) - return TOPIC_HANDLED - if(href_list["buy"]) - var/datum/deity_item/di = locate(href_list["buy"]) - if(di.can_buy(src)) - di.buy(src) - else - to_chat(di,SPAN_WARNING("You don't meet all the requirements for [di.name]!")) - return TOPIC_HANDLED - if(href_list["switchCategory"]) - set_nano_category(text2num(href_list["switchCategory"])) - return 1 - if(href_list["switchMenu"]) - nano_data[href_list["menu"]] = text2num(href_list["switchMenu"]) - return TOPIC_HANDLED - return ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/deity_tracking.dm b/mods/gamemodes/deity/mobs/deity_tracking.dm deleted file mode 100644 index 27e9d3b552d7..000000000000 --- a/mods/gamemodes/deity/mobs/deity_tracking.dm +++ /dev/null @@ -1,40 +0,0 @@ -/mob/living/deity/verb/jump_to_follower() - set category = "Godhood" - - if(!minions) - return - - var/list/could_follow = list() - for(var/m in minions) - var/datum/mind/M = m - if(M.current && M.current.stat != DEAD) - could_follow += M.current - - if(!could_follow.len) - return - - var/choice = input(src, "Jump to follower", "Teleport") as null|anything in could_follow - if(choice) - follow_follower(choice) - -/mob/living/deity/proc/follow_follower(var/mob/living/L) - if(!L || L.stat == DEAD || !is_follower(L, silent=1)) - return - if(following) - stop_follow() - eyeobj.setLoc(get_turf(L)) - to_chat(src, SPAN_NOTICE("You begin to follow \the [L].")) - following = L - events_repository.register(/decl/observ/moved, L, src, TYPE_PROC_REF(/mob/living/deity, keep_following)) - events_repository.register(/decl/observ/destroyed, L, src, TYPE_PROC_REF(/mob/living/deity, stop_follow)) - events_repository.register(/decl/observ/death, L, src, TYPE_PROC_REF(/mob/living/deity, stop_follow)) - -/mob/living/deity/proc/stop_follow() - events_repository.unregister(/decl/observ/moved, following, src) - events_repository.unregister(/decl/observ/destroyed, following, src) - events_repository.unregister(/decl/observ/death, following,src) - to_chat(src, SPAN_NOTICE("You stop following \the [following].")) - following = null - -/mob/living/deity/proc/keep_following(var/atom/movable/moving_instance, var/atom/old_loc, var/atom/new_loc) - eyeobj.setLoc(new_loc) diff --git a/mods/gamemodes/deity/mobs/freelook/cultnet.dm b/mods/gamemodes/deity/mobs/freelook/cultnet.dm deleted file mode 100644 index 86c718fa0f53..000000000000 --- a/mods/gamemodes/deity/mobs/freelook/cultnet.dm +++ /dev/null @@ -1,13 +0,0 @@ -/datum/visualnet/cultnet - valid_source_types = list(/mob/living/, /obj/structure/deity) - chunk_type = /datum/chunk/cultnet - -/datum/chunk/cultnet/acquire_visible_turfs(var/list/visible) - for(var/source in sources) - if(isliving(source)) - var/mob/living/L = source - if(L.stat == DEAD) - continue - - for(var/turf/t in seen_turfs_in_range(source, world.view)) - visible[t] = t \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/freelook/mask.dm b/mods/gamemodes/deity/mobs/freelook/mask.dm deleted file mode 100644 index 6310effcb1ca..000000000000 --- a/mods/gamemodes/deity/mobs/freelook/mask.dm +++ /dev/null @@ -1,11 +0,0 @@ -/mob/observer/eye/freelook/cult - name = "Mask of God" - desc = "A terrible fracture of reality coinciding into a mirror to another world." - living_eye = FALSE - -/mob/observer/eye/freelook/cult/EyeMove() - if(isdeity(owner)) - var/mob/living/deity/D = owner - if(D.following) - D.stop_follow() - return ..() diff --git a/mods/gamemodes/deity/mobs/items/blood_crafting.dm b/mods/gamemodes/deity/mobs/items/blood_crafting.dm deleted file mode 100644 index 3db0c0e161d2..000000000000 --- a/mods/gamemodes/deity/mobs/items/blood_crafting.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/deity_item/blood_crafting - abstract_type = /datum/deity_item/blood_crafting - name = DEITY_BLOOD_CRAFT - desc = "Unlocks the blood smithing structure which allows followers to forge unholy tools from blood and flesh." - category = DEITY_BLOOD_CRAFT - max_level = 1 - base_cost = 75 - var/forge_type = /obj/structure/deity/blood_forge - var/list/recipes = list() - -/datum/deity_item/blood_crafting/buy(var/mob/living/deity/user) - ..() - user.form.buildables |= forge_type //put structure here - var/list/L = user.feats[name] - if(!L) - L = list() - for(var/type in recipes) - L[type] = recipes[type] - user.feats[name] = L \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/items/deity_item.dm b/mods/gamemodes/deity/mobs/items/deity_item.dm deleted file mode 100644 index 7590bbb9037e..000000000000 --- a/mods/gamemodes/deity/mobs/items/deity_item.dm +++ /dev/null @@ -1,39 +0,0 @@ -// todo: declize /datum/deity_item -/datum/deity_item - var/name - var/desc - var/base_cost = 1 - var/category - var/level = 0 - var/max_level = 0 - var/list/requirements //Name of item = level of item - -/datum/deity_item/proc/can_buy(var/mob/living/deity/D) - if(max_level && level == max_level) - return FALSE - var/cost = get_cost(D) - if(cost && D.power < cost) - return FALSE - if(requirements && requirements.len) - for(var/name in requirements) - if(!D.has_item(name,requirements[name])) - return FALSE - return TRUE - -/datum/deity_item/proc/buy(var/mob/living/deity/D) - D.adjust_power(-get_cost(D)) - level++ - -/datum/deity_item/proc/get_cost(var/mob/living/deity/D) - return base_cost - - -/datum/deity_item/proc/print_level() - return "[level][max_level ? "/[max_level]" : ""]" - -/datum/deity_item/proc/print_requirements() - if(!requirements) - return "N/A" - . = "" - for(var/l in requirements) - . += "[l] [requirements[l]]
" \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/items/general.dm b/mods/gamemodes/deity/mobs/items/general.dm deleted file mode 100644 index d5c217565780..000000000000 --- a/mods/gamemodes/deity/mobs/items/general.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/deity_item/general - category = "General" - -/datum/deity_item/general/potential - name = "Increase Potential" - desc = "Increase the amount of natural power you regenerate." - base_cost = 10 - -/datum/deity_item/general/potential/buy(var/mob/living/deity/D) - ..() - D.adjust_power_min(5) - -/datum/deity_item/general/potential/get_cost(var/mob/living/deity/D) - return base_cost + base_cost * level**2 - -/datum/deity_item/general/regeneration - name = "Increase Power Syphon" - desc = "Decreases the time it takes to charge your power." - base_cost = 5 - -/datum/deity_item/general/regeneration/buy(var/mob/living/deity/D) - ..() - D.power_per_regen++ - -/datum/deity_item/general/regeneration/get_cost(var/mob/living/deity/D) - return base_cost + 10 * level \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/items/generic.dm b/mods/gamemodes/deity/mobs/items/generic.dm deleted file mode 100644 index 665814e0788b..000000000000 --- a/mods/gamemodes/deity/mobs/items/generic.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/deity_item/boon - var/boon_path - -/datum/deity_item/boon/buy(var/mob/living/deity/D) - ..() - if(boon_path) - . = new boon_path() - D.set_boon(.) - -/datum/deity_item/phenomenon - var/phenomenon_path - max_level = 1 - -/datum/deity_item/phenomenon/buy(var/mob/living/deity/D) - ..() - if(level == 1 && phenomenon_path) - D.add_phenomenon(phenomenon_path) - D.update_phenomena() - -/datum/deity_item/boon/single_charge/buy(var/mob/living/deity/D) - . = ..() - if(istype(.,/spell)) - var/spell/S = . - S.charge_counter = S.charge_max - S.charge_type = Sp_CHARGES \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/menu/deity_nano.dm b/mods/gamemodes/deity/mobs/menu/deity_nano.dm deleted file mode 100644 index 37f488f5b61b..000000000000 --- a/mods/gamemodes/deity/mobs/menu/deity_nano.dm +++ /dev/null @@ -1,81 +0,0 @@ -/mob/living/deity - var/list/nano_data = list() - var/datum/phenomenon/selected - -/mob/living/deity/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = global.self_topic_state) - if(!nano_data["categories"]) //If we don't have the categories set yet, we should populate our data. - var/list/categories = list() - for(var/cat in items_by_category) - categories += cat - nano_data["name"] = name - nano_data["form_name"] = form.name - nano_data["categories"] = categories - nano_data["menu"] = 0 //0 followers, 1 shop, 2 phenomena - nano_data["phenomenaMenu"] = 0 //0 Phenoms 1 Bindings - set_nano_category(0) - update_followers() - update_phenomena() - update_phenomena_bindings() - else - update_category() - nano_data["power"] = power - nano_data["power_min"] = power_min - nano_data["regen"] = power_per_regen - ui = SSnano.try_update_ui(user, src, ui_key, ui, nano_data, force_open) - if(!ui) - ui = new(user, src, ui_key, "deity.tmpl", "Deity Menu", 650, 600, state = uistate) - ui.set_initial_data(nano_data) - ui.open() - ui.set_auto_update(TRUE) - -/mob/living/deity/proc/set_nano_category(var/num) - nano_data["category"] = num - update_category() - -/mob/living/deity/proc/update_category() - var/actual_cat = nano_data["categories"][nano_data["category"] + 1] - var/list/cat_items = items_by_category[actual_cat] - var/list/item_data = list() - for(var/item in cat_items) - var/datum/deity_item/di = item - item_data[++item_data.len] = list("name" = di.name, "desc" = di.desc, "requirements" = di.print_requirements(), "level" = di.print_level(), "cost" = di.get_cost(), "ref" = "\ref[di]") - nano_data["item_data"] = item_data - -/mob/living/deity/proc/update_followers() - var/list/follower_data = list() - for(var/m in minions) - var/list/minion_data = list() - var/datum/mind/mind = m - if(mind.current) - if(mind.current.stat != DEAD && mind.current.loc) - minion_data["ref"] = "\ref[mind.current]" - minion_data["name"] = "[mind.current.name]" - else - minion_data["name"] = mind.name - follower_data[++follower_data.len] = minion_data - nano_data["followers"] = follower_data - -/mob/living/deity/proc/update_phenomena() - var/list/phenomena_data = list() - for(var/p in phenomena) - var/datum/phenomenon/phenomenon = phenomena[p] - phenomena_data[++phenomena_data.len] = list("name" = p, "description" = phenomenon.desc, "cost" = phenomenon.cost, "cooldown" = phenomenon.cooldown) - nano_data["phenomena"] = phenomena_data - -/mob/living/deity/proc/update_phenomena_bindings() - var/list/phenomena_bindings = list() - for(var/intent in intent_phenomena) - var/list/intent_data = list() - for(var/binding in intent_phenomena[intent]) - var/datum/phenomenon/P = intent_phenomena[intent][binding] - var/list/data = list() - if(P) - data["phenomena_name"] = P.name - data["binding"] = binding - intent_data[++intent_data.len] = data - phenomena_bindings[++phenomena_bindings.len] = list("intent" = "\ref[intent]", "intent_data" = intent_data) - nano_data["bindings"] = phenomena_bindings - //Update the hud as well. - var/obj/screen/intent/deity/SD = istype(hud_used) && hud_used.action_intent - if(istype(SD)) - SD.update_text() \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/_defines.dm b/mods/gamemodes/deity/mobs/phenomena/_defines.dm deleted file mode 100644 index e0268f37fa5c..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/_defines.dm +++ /dev/null @@ -1,4 +0,0 @@ -#define PHENOMENA_NEAR_STRUCTURE 1 //Must be done near a structure -#define PHENOMENA_FOLLOWER 2 //Can be done on a follower -#define PHENOMENA_NONFOLLOWER 4 //Can be done on a nonfollower. -#define PHENOMENA_MUNDANE 8 //Can affect mundane (no mind, no client) things. \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/communication.dm b/mods/gamemodes/deity/mobs/phenomena/communication.dm deleted file mode 100644 index 2b815ce00ede..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/communication.dm +++ /dev/null @@ -1,80 +0,0 @@ -/datum/phenomenon/communicate - name = "Direct Communication" - desc = "Communicate directly with a mortal being. You may communicate with non-followers, but they will find you easier to ignore." - cost = 0 - flags = PHENOMENA_FOLLOWER | PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/communicate/activate(var/mob/living/L) - var/text_to_send = sanitize(input(linked, "Subjugate a member to your will", "Message a Believer") as text) - if(text_to_send) - var/text_size = 4 - if(!linked.is_follower(L)) - text_size = 1 - to_chat(L, "[text_to_send]") //Note to self: make this go to ghosties - to_chat(linked, SPAN_NOTICE("You send the message [text_to_send] to \the [L]")) - log_and_message_admins("communicated the message \"[text_to_send]\" to [key_name(L)]", linked) - -/datum/phenomenon/point - name = "Point" - desc = "Attract your follower's attentions to something nearby." - cost = 0 - flags = PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - var/image/arrow - -/datum/phenomenon/point/activate(var/atom/a) - ..() - if(!arrow) - arrow = image('icons/effects/markers.dmi', icon_state = "arrow", layer = POINTER_LAYER) - var/turf/T = get_turf(a) - arrow.loc = T - var/list/view = view(7,T) - for(var/m in linked.minions) - var/datum/mind/mind = m - if(mind.current) - var/mob/M = mind.current - if((M in view) && M.client) - to_chat(M, SPAN_OCCULT("Your attention is eerily drawn to \the [a].")) - M.client.images += arrow - events_repository.register(/decl/observ/logged_out, M, src, TYPE_PROC_REF(/datum/phenomenon/point, remove_image)) - spawn(20) - if(M.client) - remove_image(M) - -/datum/phenomenon/point/proc/remove_image(var/mob/living/L) - L.client.images -= arrow - events_repository.unregister(/decl/observ/logged_out, L, src) - -/datum/phenomenon/punish - name = "Punish" - desc = "Punish your followers for insubordination, the cost to use this phenomenon is based on how deadly you choose the punishment to be." - cost = 0 - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living - var/static/list/punishment_list = list("Pain (0)" = 0, "Light Wound (5)" = 5, "Brain Damage (10)" = 10, "Heavy Wounds (20)" = 20) - -/datum/phenomenon/punish/activate(var/mob/living/L) - var/pain = input(linked, "Choose their punishment.", "Punishment") as null|anything in punishment_list - if(!pain) - return - if(punishment_list[pain] && linked.power < punishment_list[pain]) - to_chat(linked, SPAN_WARNING("[pain] costs too much power for you to use on \the [L]")) - return - ..() - linked.adjust_power(-punishment_list[pain]) - switch(pain) - if("Pain (0)") - L.take_damage(15, PAIN) - to_chat(L, SPAN_WARNING("You feel intense disappointment coming at you from beyond the veil.")) - if("Light Wound (5)") - L.take_damage(5) - to_chat(L, SPAN_WARNING("You feel an ethereal whip graze your very soul!")) - if("Brain Damage (10)") - L.take_damage(5, BRAIN) - to_chat(L, SPAN_DANGER("You feel your mind breaking under a otherwordly hammer...")) - if("Heavy Wounds (20)") - L.take_damage(25) - to_chat(L, SPAN_DANGER("You feel your master turn its destructive potential against you!")) - to_chat(linked, SPAN_NOTICE("You punish \the [L].")) - log_admin("[key_name(linked)] used Punishment [pain] on \the [key_name(L)]") \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/conjuration.dm b/mods/gamemodes/deity/mobs/phenomena/conjuration.dm deleted file mode 100644 index d7dd22f3e269..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/conjuration.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/phenomenon/movable_object/dimensional_locker - object_type = /obj/structure/closet - name = "Dimensional Locker" - cost = 10 - desc = "Summon a trans-dimensional locker anywhere within your influence. You may transport objects and things, but not people in it." - -/datum/phenomenon/movable_object/dimensional_locker/activate(var/atom/a, var/mob/living/deity/user) - var/list/mobs_inside = list() - recursive_content_check(object_to_move, mobs_inside, client_check = 0, sight_check = 0, include_objects = 0) - - for(var/i in mobs_inside) - var/mob/M = i - M.dropInto(object_to_move.loc) - to_chat(M,SPAN_WARNING("You are suddenly flung out of \the [object_to_move]!")) - ..() - -/datum/phenomenon/portals - name = "Portals" - desc = "Summon a portal linked to the last portal you've created. The portal will be destroyed if it is not linked when someone crosses it." - cost = 30 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - var/list/portals = list() - -/datum/phenomenon/portals/activate(var/atom/a, var/mob/living/deity/user) - ..() - var/obj/effect/portal/P = new(get_turf(a), null, 0) - P.failchance = 0 - portals += P - events_repository.register(/decl/observ/destroyed, P,src, TYPE_PROC_REF(/datum/phenomenon/portals, remove_portal)) - if(portals.len > 2) - var/removed = portals[1] - remove_portal(removed) - qdel(removed) - if(portals.len > 1) - var/obj/effect/portal/P1 = portals[1] - var/obj/effect/portal/P2 = portals[2] - P1.target = get_turf(P2) - P2.target = get_turf(P1) - -/datum/phenomenon/portals/proc/remove_portal(var/portal) - portals -= portal - events_repository.unregister(/decl/observ/destroyed, portal,src) - var/turf/T = get_turf(portal) - for(var/obj/effect/portal/P in portals) - if(P.target == T) - P.target = null - -/datum/phenomenon/banishing_smite - name = "Banishing Smite" - desc = "Deal a terrible blow to a mortal. If they are hurt enough ,they will find themselves trapped in a rift for 30 seconds." - cost = 70 - cooldown = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/banishing_smite/activate(var/mob/living/L, var/mob/living/deity/user) - ..() - L.take_overall_damage(rand(5,30),0,0,0,"blunt intrument") //Actual spell does 5d10 but maaaybe too much. - playsound(get_turf(L), 'sound/effects/bamf.ogg', 100, 1) - to_chat(L, SPAN_DANGER("Something hard hits you!")) - if(L.current_health < L.get_max_health()/2) //If it reduces past 50% - var/obj/effect/rift/R = new(get_turf(L)) - L.visible_message(SPAN_DANGER("\The [L] is quickly sucked into \a [R]!")) - L.forceMove(R) - spawn(300) - qdel(R) diff --git a/mods/gamemodes/deity/mobs/phenomena/conversion.dm b/mods/gamemodes/deity/mobs/phenomena/conversion.dm deleted file mode 100644 index 1f0954c91350..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/conversion.dm +++ /dev/null @@ -1,51 +0,0 @@ -/datum/phenomenon/conversion - name = "Conversion" - desc = "Ask a non-follower to convert to your cult. This is completely voluntary. Requires the subject to be close to an altar." - cost = 20 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/conversion/can_activate(var/atom/target) - if(!..()) - return 0 - var/is_good = 0 - for(var/obj/structure/deity/altar/A in linked.structures) - if(get_dist(target, A) < 2) - is_good = 1 - break - if(!is_good) - to_chat(linked,SPAN_WARNING("\The [target] needs to be near \a [linked.get_type_name(/obj/structure/deity/altar)].")) - return 0 - return 1 - -/datum/phenomenon/conversion/activate(var/mob/living/L) - to_chat(src,SPAN_NOTICE("You give \the [L] a chance to willingly convert. May they choose wisely.")) - var/choice = alert(L, "You feel a weak power enter your mind attempting to convert it.", "Conversion", "Allow Conversion", "Deny Conversion") - if(choice == "Allow Conversion") - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - godcult.add_antagonist_mind(L.mind,1, "Servant of [linked]", "You willingly give your mind to it, may it bring you fortune.", specific_god=linked) - else - to_chat(L, SPAN_WARNING("With little difficulty you force the intrusion out of your mind. May it stay that way.")) - to_chat(src, SPAN_WARNING("\The [L] decides not to convert.")) - -/datum/phenomenon/forced_conversion - name = "Forced Conversion" - desc = "Force a non-follower to join you. They need to be on top of an altar and conscious for this to work. They may resist, but that will hurt them." - cost = 100 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/forced_conversion/can_activate(var/mob/living/L) - if(!..()) - return 0 - var/obj/structure/deity/altar/A = locate() in get_turf(L) - if(!A || A.linked_god != linked) - to_chat(linked,SPAN_WARNING("\The [L] needs to be on \a [linked.get_type_name(/obj/structure/deity/altar)] to be forcefully converted.")) - return 0 - - return 1 - -/datum/phenomenon/forced_conversion/activate(var/mob/living/L) - var/obj/structure/deity/altar/A = locate() in get_turf(L) - A.set_target(L) - to_chat(linked, SPAN_NOTICE("You imbue \the [A] with your power, setting forth to force \the [L] to your will.")) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/generic.dm b/mods/gamemodes/deity/mobs/phenomena/generic.dm deleted file mode 100644 index 3163ea42ab54..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/generic.dm +++ /dev/null @@ -1,36 +0,0 @@ -/datum/phenomenon/movable_object - var/object_type - var/atom/movable/object_to_move - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - -/datum/phenomenon/movable_object/New() - ..() - add_object() - -/datum/phenomenon/movable_object/Destroy() - events_repository.unregister(/decl/observ/destroyed, object_to_move,src) - if(!object_to_move.loc) - QDEL_NULL(object_to_move) - . = ..() - -/datum/phenomenon/movable_object/proc/add_object() - if(object_to_move) - events_repository.unregister(/decl/observ/destroyed, object_to_move,src) - object_to_move = new object_type() - events_repository.register(/decl/observ/destroyed, object_to_move, src, PROC_REF(add_object)) - -/datum/phenomenon/movable_object/activate(var/atom/a, var/mob/living/deity/user) - ..() - if(object_to_move == a) - object_to_move.forceMove(null) //Move to null space - else - var/turf/T = get_turf(a) - //No dense turf/stuff - if(T.density) - return - for(var/i in T) - var/atom/A = i - if(A.density) - return - object_to_move.forceMove(T) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/narsie.dm b/mods/gamemodes/deity/mobs/phenomena/narsie.dm deleted file mode 100644 index 8a94ae441cbf..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/narsie.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/phenomenon/exude_blood - name = "Exhude Blood" - desc = "Take pity on a follower, converting a pitance of your power into blood. Don't let them forget your mercy." - cost = 20 - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living/human - -/datum/phenomenon/exude_blood/can_activate(var/mob/living/human/H) - if(!..()) - return 0 - - if(!H.should_have_organ(BP_HEART) || H.vessel.total_volume == H.species.blood_volume) - to_chat(linked, SPAN_WARNING("\The [H] doesn't require anymore blood.")) - return 0 - return 1 - -/datum/phenomenon/exude_blood/activate(var/mob/living/human/H, var/mob/living/deity/user) - H.adjust_blood(30) - to_chat(H,SPAN_NOTICE("You feel a rush as new blood enters your system.")) - - -/datum/phenomenon/hellscape - name = "Reveal Hellscape" - desc = "Show a non-follower what awaits their souls after you are through with them." - cost = 60 - cooldown = 450 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - var/static/list/creepy_notes = list("Your knees give out as an unnatural screaming rings your ears.", - "You breathe in ash and decay, your lungs gasping for air as your body gives way to the floor.", - "An extreme pressure comes over you, as if an unknown force has marked you.") - -/datum/phenomenon/hellscape/activate(var/mob/living/L) - to_chat(L, "[pick(creepy_notes)]") - L.damageoverlaytemp = 100 - sound_to(L, 'sound/hallucinations/far_noise.ogg') - SET_STATUS_MAX(L, STAT_WEAK, 2) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/phenomena.dm b/mods/gamemodes/deity/mobs/phenomena/phenomena.dm deleted file mode 100644 index 8d28ab5fc6e6..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/phenomena.dm +++ /dev/null @@ -1,75 +0,0 @@ -/datum/phenomenon - var/name = "Phenomena" - var/desc = "This has no desc." - var/cost = 0 - var/mob/living/deity/linked - var/flags = 0 - var/cooldown = 10 - var/refresh_time = 0 - var/expected_type - -/datum/phenomenon/New(var/master) - linked = master - ..() - -/datum/phenomenon/Destroy() - linked.remove_phenomenon(src) - return ..() - -/datum/phenomenon/proc/Click(var/atom/target) - if(can_activate(target)) - linked.adjust_power(-cost) - refresh_time = world.time + cooldown - activate(target) - -/datum/phenomenon/proc/can_activate(var/atom/target) - if(!linked) - return 0 - if(refresh_time > world.time) - to_chat(linked, SPAN_WARNING("\The [src] is still on cooldown for [round((refresh_time - world.time)/10)] more seconds!")) - return 0 - - if(!linked.form) - to_chat(linked, SPAN_WARNING("You must choose your form first!")) - return 0 - - if(expected_type && !istype(target,expected_type)) - return 0 - - if(flags & PHENOMENA_NEAR_STRUCTURE) - if(!linked.near_structure(target, 1)) - to_chat(linked, SPAN_WARNING("\The [target] needs to be near a holy structure for your powers to work!")) - return 0 - - if(isliving(target)) - var/mob/living/L = target - if(!L.mind || !L.client) - if(!(flags & PHENOMENA_MUNDANE)) - to_chat(linked, SPAN_WARNING("\The [L]'s mind is too mundane for you to influence.")) - return 0 - else - if(linked.is_follower(target, silent = 1)) - if(!(flags & PHENOMENA_FOLLOWER)) - to_chat(linked, SPAN_WARNING("You can't use [name] on the flock!")) - return 0 - else if(!(flags & PHENOMENA_NONFOLLOWER)) - to_chat(linked, SPAN_WARNING("You can't use [name] on non-believers.")) - return 0 - - if(cost > linked.power) - to_chat(linked, SPAN_WARNING("You need more power to use [name] (Need [cost] power, have [linked.power])!")) - return 0 - - return 1 - -/datum/phenomenon/proc/activate(var/target) - to_chat(linked, SPAN_NOTICE("You use the phenomenon [name] on \the [target]")) - log_and_message_admins("uses the phenomenon [name] on \the [target]", linked, get_turf(target)) - return - -/datum/phenomenon/proc/get_desc() - . = desc - if(cooldown) - . = "Cooldown: [cooldown/10] seconds. [.]" - if(cost) - . = "Cost: [cost] power. [.]" \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/starlight.dm b/mods/gamemodes/deity/mobs/phenomena/starlight.dm deleted file mode 100644 index 1351a50a8920..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/starlight.dm +++ /dev/null @@ -1,232 +0,0 @@ -/datum/phenomenon/herald - name = "Bestow Heraldry" - desc = "Turn one of your followers into a herald of your coming." - cost = 100 - cooldown = 60 SECONDS - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living/human - var/static/list/possible_forms = list( - "Champion" = list("description" = "A protector of the faith. Fully protected by knightly armor, a Champion can shoot fire from their hands.", - "armor" = /obj/item/clothing/suit/armor/sunsuit, - "helm" = /obj/item/clothing/head/helmet/sunhelm, - "extension" = /datum/extension/deity_be_near/champion, - "spells" = list(/spell/hand/duration/sunwrath) - ), - "Oracle" = list("description" = "A preacher of the faith, the Oracle gives off heavenly light that they can use to heal followers and stun enemies.", - "armor" = /obj/item/clothing/suit/armor/sunrobe, - "extension" = /datum/extension/deity_be_near/oracle, - "spells" = list(/spell/targeted/glimpse_of_eternity) - ), - "Traitor" = list("description" = "Believers that reject the sun god's blessings, instead reveling in the shadows. Can turn invisible when its dark, and can move unprotected in space.", - "armor" = /obj/item/clothing/suit/space/shadowsuit, - "helm" = /obj/item/clothing/head/helmet/space/shadowhood, - "extension" = /datum/extension/deity_be_near/traitor, - "spells" = list(/spell/veil_of_shadows) - ) - ) - -/datum/phenomenon/herald/can_activate(var/a) - if(!..()) - return FALSE - return valid_for_herald(a) - -/datum/phenomenon/herald/proc/valid_for_herald(var/a) - var/mob/living/human/H = a - if(!istype(H)) - return FALSE - var/obj/item/I = H.get_equipped_item(slot_wear_suit_str) - if(I) - var/datum/extension/deity_be_near/dbn = get_extension(I, /datum/extension/deity_be_near) - if(dbn) - return FALSE - return TRUE - -/datum/phenomenon/herald/proc/equip_slot(var/mob/living/L, var/slot_id, var/new_item) - var/equipped = L.get_equipped_slot_for_item(slot_id) - if(equipped) - L.try_unequip(equipped, get_turf(L)) - L.equip_to_slot_if_possible(new_item, slot_id) - -/datum/phenomenon/herald/Topic(var/href, var/list/href_list) - if(..()) - return 1 - if(usr != linked) - return 1 - - if(href_list["herald"]) - var/list/form = possible_forms[href_list["herald"]] - var/mob/living/L = locate(href_list["target"]) - var/turf/T = get_turf(L) - if(!L || !valid_for_herald(L) || !form) - return 1 - var/type = form["armor"] - var/obj/item/I = new type(T) - var/datum/extension/deity_be_near/extension = set_extension(I, form["extension"], linked) - L.equip_to_slot_or_store_or_drop(I, slot_wear_suit_str) - if(form["helm"]) - var/h_type = form["helm"] - var/obj/item/helm = new h_type(T) - L.equip_to_slot_or_store_or_drop(helm, slot_head_str) - extension.expected_helmet = helm.type //We only do by type because A. its easier to manage and B the chances of it being non-unique in a normal game is very small - if(form["weapon"]) - var/w_type = form["weapon"] - L.put_in_hands_or_store_or_drop(new w_type(T)) - if(form["spells"]) - for(var/s in form["spells"]) - var/spell/boon = new s - boon.set_connected_god(linked) - L.add_spell(boon) - to_chat(L, "You have been chosen by your master to lead your fellow followers into the next age of rebirth.
You have been granted powerful armor and a powerful spell. Don't lose them, as they are your key to your divinity and leadership.
You also have particular sway over your deity's structures.
") - to_chat(linked, SPAN_NOTICE("\The [L] is now your herald!")) - linked.remove_phenomenon(name) - show_browser(linked, null, "window=herald") - -/datum/phenomenon/herald/activate(var/mob/living/human/H) - var/list/html = list() - html += "

Heralds

" - html += "
Pick the type of herald you want.
" - html += "" - for(var/type in possible_forms) - var/list/form = possible_forms[type] - html += "" - html += "
NameDescription
[type][form["description"]]
" - show_browser(linked, jointext(html,null), "window=herald") - -/datum/phenomenon/create_gateway - name = "Create Gateway" - desc = "Creates a gateway from this world to the next. Gateways syphon absurd amounts of power but can be sacrificed to summon powerful minions." - cost = 200 - flags = PHENOMENA_NEAR_STRUCTURE - expected_type = /atom - -/datum/phenomenon/create_gateway/can_activate(var/atom/a) - if(!..()) - return 0 - if(istype(a, /obj/structure/deity/gateway)) - var/obj/structure/deity/gateway/G = a - if(G.linked_god == linked) - return 1 - var/turf/T = get_turf(a) - if(!T || T.density) - return 0 - for(var/i in T) - var/atom/at = i - if(at.density) - return 0 - return 1 - -/datum/phenomenon/create_gateway/activate(var/atom/a) - ..() - if(istype(a, /obj/structure/deity/gateway)) - qdel(a) - else - new /obj/structure/deity/gateway(get_turf(a), linked) - -/datum/phenomenon/flickering_whisper - name = "Flickering Whisper" - desc = "Whisper to a non-believer, allowing you to intrude on their thoughts and see what they see." - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/flickering_whisper/activate(var/mob/living/L) - var/atom/whisper_from - for(var/obj/structure/deity/radiant_statue/rs in view(3, L)) - whisper_from = rs - break - var/message = sanitize(input(linked, "What is your message?", null) as null|text) - if(!linked || !message || QDELETED(src)) - return - to_chat(L, SPAN_OCCULT("[whisper_from ? "The [whisper_from] speaks to you" : "You hear a whisper say"] \"[message]\"")) - - linked.eyenet.add_source(L) - events_repository.register(/decl/observ/destroyed, L, src, PROC_REF(deactivate_look)) - addtimer(CALLBACK(src, PROC_REF(deactivate_look), L), 30 SECONDS) - -/datum/phenomenon/flickering_whisper/proc/deactivate_look(var/mob/viewer) - if(!linked.is_follower(viewer)) //Don't remove if they are follower - linked.eyenet.remove_source(viewer) - events_repository.unregister(/decl/observ/destroyed, viewer, src) - -/datum/phenomenon/burning_glare - name = "Burning Glare" - desc = "Burn a victim. If they are burnt enough, you'll set them ablaze." - cost = 100 - flags = PHENOMENA_NONFOLLOWER|PHENOMENA_NEAR_STRUCTURE - cooldown = 30 SECONDS - expected_type = /mob/living - -/datum/phenomenon/burning_glare/activate(var/mob/living/L) - ..() - to_chat(L, SPAN_DANGER("You feel yourself burn!")) - L.take_damage(10, BURN) - if(L.get_damage(BURN) > 60) - L.fire_stacks += 50 - L.IgniteMob() - -/datum/phenomenon/divine_right - name = "Divine Right" - desc = "Trigger your rebirth into the body of someone wearing a herald's uniform. This takes time, requires 3 open gateways, and if the body is destroyed during the ritual... so are you. But once complete, you become an unstoppable demigod of unnatural power." - cost = 300 - cooldown = 180 SECONDS - flags = PHENOMENA_FOLLOWER|PHENOMENA_NEAR_STRUCTURE - expected_type = /mob/living - -/datum/phenomenon/divine_right/can_activate(var/mob/living/L) - if(!..()) - return FALSE - var/active_gateways = 0 - for(var/obj/structure/deity/gateway/G in linked.structures) - active_gateways += 1 - - if(active_gateways < 3) - to_chat(linked, SPAN_WARNING("You do not have enough gateways activated.")) - return FALSE - - var/obj/O = L.get_equipped_item(slot_wear_suit_str) - if(O && has_extension(O, /datum/extension/deity_be_near)) - var/datum/extension/deity_be_near/dbn = get_extension(O, /datum/extension/deity_be_near) - if(dbn.wearing_full()) - return TRUE - to_chat(linked, SPAN_WARNING("\The [L] is not wearing a herald's uniform.")) - return FALSE - -/datum/phenomenon/divine_right/activate(var/mob/living/L) - ..() - to_chat(L, SPAN_OCCULT("Your soul is ripped from your body as your master prepares to possess it.")) - to_chat(linked, SPAN_OCCULT("You prepare the body for possession. Keep it safe. If it is totally destroyed, you will die.")) - L.ghostize() - SET_STATUS_MAX(L, STAT_WEAK, 1) - new /obj/aura/starborn(L) - L.status_flags |= GODMODE - events_repository.register(/decl/observ/destroyed, L,src,PROC_REF(fail_ritual)) - addtimer(CALLBACK(src, PROC_REF(succeed_ritual), L), 600 SECONDS) //6 minutes - for(var/mob/living/player in global.player_list) - sound_to(player, 'sound/effects/cascade.ogg') - if(player?.mind?.assigned_job?.is_holy) - to_chat(player, SPAN_OCCULT("Something bad is coming.... you know you don't have much time. Find and destroy the vessel, before its too late.")) - else if(player != linked && !linked.is_follower(player, silent = 1)) - to_chat(player, SPAN_WARNING("The world swims around you for just a moment... something is wrong. Very wrong.")) - else - to_chat(player, SPAN_NOTICE("Your Master is being reborn into the body of \the [L]. Protect it at all costs.")) - -/datum/phenomenon/divine_right/proc/fail_ritual(var/mob/living/L) - qdel(linked) - -/datum/phenomenon/divine_right/proc/succeed_ritual(var/mob/living/L) - to_chat(linked, SPAN_OCCULT("You have been reborn! Your power is limited here, focused on your body, but in return you are both eternal and physical.")) - for(var/mob/living/player in global.player_list) - sound_to(player, 'sound/effects/cascade.ogg') - to_chat(player, SPAN_OCCULT("\The [linked] has been born into flesh. Kneel to its authority or else.")) - linked.mind.transfer_to(L) - L.SetName("[linked] Incarnate") - L.real_name = "[linked] Incarnate" - -/datum/phenomenon/movable_object/wisp - name = "Wisp" - desc = "Creates or moves a small ball of light for your followers to use." - cost = 30 - object_type = /obj/item/flashlight/slime - -/datum/phenomenon/movable_object/wisp/add_object() - ..() - object_to_move.SetName("wisp") \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/phenomena/transmutation.dm b/mods/gamemodes/deity/mobs/phenomena/transmutation.dm deleted file mode 100644 index 381e885d3187..000000000000 --- a/mods/gamemodes/deity/mobs/phenomena/transmutation.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/phenomenon/warp - name = "Warp Body" - desc = "Corrupt a mortal being, causing their DNA to break and their body to fail on them." - cost = 90 - cooldown = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomenon/warp/activate(var/mob/living/L) - ..() - L.take_damage(20, CLONE) - SET_STATUS_MAX(L, STAT_WEAK, 2) - to_chat(L, SPAN_DANGER("You feel your body warp and change underneath you!")) - -/datum/phenomenon/rock_form - name = "Rock Form" - desc = "Convert your mortal followers into immortal stone beings." - cost = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_FOLLOWER - expected_type = /mob/living/human - -/datum/phenomenon/rock_form/activate(var/mob/living/human/H) - ..() - to_chat(H, SPAN_DANGER("You feel your body harden as it rapidly is transformed into living crystal!")) - H.change_species(SPECIES_GOLEM) - SET_STATUS_MAX(H, STAT_WEAK, 5) \ No newline at end of file diff --git a/mods/gamemodes/deity/mobs/say.dm b/mods/gamemodes/deity/mobs/say.dm deleted file mode 100644 index 1dab1a38aa3b..000000000000 --- a/mods/gamemodes/deity/mobs/say.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/deity/say(var/message, var/decl/language/speaking = null, var/verb="says") - if(!..()) - return 0 - if(pylon) - pylon.audible_message("\The [pylon] reverberates, \"[message]\"") - else - for(var/m in minions) - var/datum/mind/mind = m - to_chat(mind.current, "[message]") \ No newline at end of file diff --git a/mods/gamemodes/deity/overrides.dm b/mods/gamemodes/deity/overrides.dm deleted file mode 100644 index c052abdf9a24..000000000000 --- a/mods/gamemodes/deity/overrides.dm +++ /dev/null @@ -1,27 +0,0 @@ -/obj/item/sword/cultblade/can_use_safely(mob/living/user) - var/decl/special_role/godcult = GET_DECL(/decl/special_role/godcultist) - return ..() || (user.mind in godcult.current_antagonists) - -/datum/reagents/Topic(href, href_list) - . = ..() - if(!. && href_list["deconvert"]) - var/list/data = REAGENT_DATA(src, /decl/material/liquid/water) - if(LAZYACCESS(data, "holy")) - var/mob/living/target = locate(href_list["deconvert"]) - if(istype(target) && !QDELETED(target) && target.mind) - var/decl/special_role/godcult = GET_DECL(/decl/special_role/godcultist) - godcult.remove_antagonist(target.mind, TRUE) - -/decl/material/liquid/water/affect_holy(mob/living/M, removed, datum/reagents/holder) - . = ..() - if(.) - return . - var/decl/special_role/godcult = GET_DECL(/decl/special_role/godcultist) - if(M.mind && godcult.is_antagonist(M.mind)) - if(REAGENT_VOLUME(holder, type) > 5) - M.take_damage(5, PAIN, do_update_health = FALSE) - M.take_damage(1, BRUTE) - if(prob(10)) //Only annoy them a /bit/ - to_chat(M, SPAN_DANGER("You feel your insides curdle and burn! \[Give Into Purity\]")) - return TRUE - return FALSE \ No newline at end of file diff --git a/mods/gamemodes/deity/screen/intent.dm b/mods/gamemodes/deity/screen/intent.dm deleted file mode 100644 index 9f5b18b6aaa8..000000000000 --- a/mods/gamemodes/deity/screen/intent.dm +++ /dev/null @@ -1,45 +0,0 @@ -/obj/screen/intent/deity - var/list/desc_screens = list() - screen_loc = "RIGHT-5:122,BOTTOM:8" - -/obj/screen/intent/deity/on_update_icon() - . = ..() - cut_overlays() - add_overlay(image('icons/mob/screen/phenomena.dmi', icon_state = "hud", pixel_x = -138, pixel_y = -1)) - compile_overlays() - -/obj/screen/intent/deity/proc/sync_to_mob(var/mob) - var/mob/living/deity/deity = mob - for(var/i in 1 to deity.control_types.len) - var/obj/screen/deity_marker/S = new(null, deity) - desc_screens[deity.control_types[i]] = S - S.screen_loc = screen_loc - //This sets it up right. Trust me. - S.maptext_y = 33/2*i - i*i/2 - 10 - deity.client.screen += S - update_text() - -/obj/screen/intent/deity/proc/update_text() - var/mob/living/deity/deity = usr - var/mob/owner = owner_ref?.resolve() - if(!istype(deity) || !istype(owner) || owner != deity) - return - var/decl/intent/intent = owner.get_intent() - for(var/i in deity.control_types) - var/obj/screen/deity_marker/S = desc_screens[i] - var/datum/phenomenon/P = deity.intent_phenomena[intent][i] - if(P) - S.maptext = "[P.name]" - else - S.maptext = null - -/obj/screen/intent/deity/handle_click(mob/user, params) - ..() - update_text() - -/obj/screen/deity_marker - name = "" //Don't want them to be able to actually right click it. - mouse_opacity = MOUSE_OPACITY_UNCLICKABLE - icon_state = "blank" - maptext_width = 128 - maptext_x = -125 \ No newline at end of file diff --git a/mods/gamemodes/deity/spells/boon.dm b/mods/gamemodes/deity/spells/boon.dm deleted file mode 100644 index 269a0b4bc4cf..000000000000 --- a/mods/gamemodes/deity/spells/boon.dm +++ /dev/null @@ -1,11 +0,0 @@ -/spell - var/mob/living/deity/connected_god //Do we have this spell based off a boon from a god? - -/spell/proc/set_connected_god(var/mob/living/deity/god) - connected_god = god - -// todo: godform check_charge to parallel take_charge. currently a boon always succeeds -/spell/take_charge(mob/user, skipcharge) - if(connected_god) - return connected_god.take_charge(user, max(1, charge_max/10)) - return ..() \ No newline at end of file diff --git a/mods/gamemodes/deity/spells/construction.dm b/mods/gamemodes/deity/spells/construction.dm deleted file mode 100644 index 0005154ad6ea..000000000000 --- a/mods/gamemodes/deity/spells/construction.dm +++ /dev/null @@ -1,55 +0,0 @@ -#define CONSTRUCT_SPELL_COST 1 -#define CONSTRUCT_SPELL_TYPE 2 - -/spell/construction - name = "Basic Construction" - desc = "This ability will let you summon a structure of your choosing." - - cast_delay = 10 - charge_max = 100 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - hud_state = "const_wall" - cast_sound = 'sound/effects/meteorimpact.ogg' - -/spell/construction/choose_targets() - var/list/possible_targets = list() - if(connected_god && connected_god.form) - for(var/type in connected_god.form.buildables) - var/cost = 10 - if(ispath(type, /obj/structure/deity)) - var/obj/structure/deity/D = type - cost = initial(D.build_cost) - possible_targets["[connected_god.get_type_name(type)] - [cost]"] = list(cost, type) - var/choice = input("Construct to build.", "Construction") as null|anything in possible_targets - if(!choice) - return - if(locate(/obj/structure/deity) in get_turf(holder)) - return - - return possible_targets[choice] - else - return - -/spell/construction/cast_check(var/skipcharge, var/mob/user, var/list/targets) - if(!..()) - return 0 - var/turf/T = get_turf(user) - if(skipcharge && !valid_deity_structure_spot(targets[CONSTRUCT_SPELL_TYPE], T, connected_god, user)) - return 0 - else - for(var/obj/O in T) - if(O.density) - to_chat(user, SPAN_WARNING("Something here is blocking your construction!")) - return 0 - return 1 - -/spell/construction/cast(var/target, mob/user) - charge_max = target[CONSTRUCT_SPELL_COST] - target = target[CONSTRUCT_SPELL_TYPE] - var/turf/T = get_turf(user) - new target(T, connected_god) -#undef CONSTRUCT_SPELL_COST -#undef CONSTRUCT_SPELL_TYPE \ No newline at end of file diff --git a/mods/gamemodes/deity/spells/open_gateway.dm b/mods/gamemodes/deity/spells/open_gateway.dm deleted file mode 100644 index db83a05c8917..000000000000 --- a/mods/gamemodes/deity/spells/open_gateway.dm +++ /dev/null @@ -1,34 +0,0 @@ -/spell/open_gateway - name = "Open Gateway" - desc = "Open a gateway for your master. Don't do it for too long, or you will die." - - charge_max = 600 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "const_wall" - cast_sound = 'sound/effects/meteorimpact.ogg' - -/spell/open_gateway/choose_targets() - var/mob/living/spellcaster = holder - var/turf/source_turf = get_turf(spellcaster) - holder.visible_message(SPAN_NOTICE("A gateway opens up underneath \the [spellcaster]!")) - var/deity - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - if(spellcaster.mind && (spellcaster.mind in godcult.current_antagonists)) - deity = godcult.get_deity(spellcaster.mind) - return list(new /obj/structure/deity/gateway(source_turf, deity)) - -/spell/open_gateway/cast(var/list/targets, var/mob/holder, var/channel_count) - if(prob((channel_count / 5) * 100)) - to_chat(holder, SPAN_DANGER("If you hold the portal open for much longer you'll be ripped apart!")) - if(channel_count == 6) - to_chat(holder, SPAN_DANGER("The gateway consumes you... leaving nothing but dust.")) - holder.dust() - - -/spell/open_gateway/after_spell(var/list/targets) - QDEL_NULL_LIST(targets) \ No newline at end of file diff --git a/mods/gamemodes/deity/spells/vision.dm b/mods/gamemodes/deity/spells/vision.dm deleted file mode 100644 index dabe6cf4fcaf..000000000000 --- a/mods/gamemodes/deity/spells/vision.dm +++ /dev/null @@ -1,21 +0,0 @@ -/spell/camera_connection/god_vision - name = "All Seeing Eye" - desc = "See what your master sees." - - charge_max = 10 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - extension_type = /datum/extension/eye/freelook - - hud_state = "gen_mind" - -/spell/camera_connection/god_vision/set_connected_god(var/mob/living/deity/god) - ..() - - var/datum/extension/eye/freelook/fl = get_extension(src, /datum/extension/eye) - if(!fl) - return - fl.set_visualnet(god.eyenet) - diff --git a/mods/gamemodes/deity/structures/altar.dm b/mods/gamemodes/deity/structures/altar.dm deleted file mode 100644 index 888e4c935a9d..000000000000 --- a/mods/gamemodes/deity/structures/altar.dm +++ /dev/null @@ -1,106 +0,0 @@ -/obj/structure/deity/altar - name = "altar" - desc = "A structure made for the express purpose of religion." - current_health = 50 - power_adjustment = 5 - deity_flags = DEITY_STRUCTURE_ALONE - build_cost = 1000 - var/mob/living/target - var/cycles_before_converted = 5 - var/next_cycle = 0 - -/obj/structure/deity/altar/Destroy() - if(target) - remove_target() - if(linked_god) - to_chat(src, SPAN_DANGER("You've lost an altar!")) - return ..() - -/obj/structure/deity/altar/grab_attack(obj/item/grab/grab, mob/user) - var/mob/living/victim = grab.get_affecting_mob() - if(grab.force_danger() && istype(victim)) - victim.dropInto(loc) - SET_STATUS_MAX(victim, STAT_WEAK, 1) - user.visible_message(SPAN_WARNING("\The [user] throws \the [victim] onto \the [src]!")) - qdel(grab) - return TRUE - return ..() - -/obj/structure/deity/altar/Process() - if(!target || world.time < next_cycle) - return - if(!linked_god || target.stat) - to_chat(linked_god, SPAN_WARNING("\The [target] has lost consciousness, breaking \the [src]'s hold on their mind!")) - remove_target() - return - - next_cycle = world.time + 10 SECONDS - cycles_before_converted-- - if(!cycles_before_converted) - src.visible_message("For one thundering moment, \the [target] cries out in pain before going limp and broken.") - var/decl/special_role/godcultist/godcult = GET_DECL(/decl/special_role/godcultist) - godcult.add_antagonist_mind(target.mind,1, "Servant of [linked_god]","Your loyalty may be faulty, but you know that it now has control over you...", specific_god=linked_god) - remove_target() - return - - switch(cycles_before_converted) - if(4) - text = "You can't think straight..." - if(3) - text = "You feel like your thought are being overriden..." - if(2) - text = "You can't... concentrate... must... resist!" - if(1) - text = "Can't... resist... anymore." - to_chat(linked_god, SPAN_WARNING("\The [target] is getting close to conversion!")) - to_chat(target, "[text]. Resist Conversion") - - -//Used for force conversion. -/obj/structure/deity/altar/proc/set_target(var/mob/living/L) - if(target || !linked_god) - return - cycles_before_converted = initial(cycles_before_converted) - START_PROCESSING(SSobj, src) - target = L - update_icon() - events_repository.register(/decl/observ/destroyed, L,src, TYPE_PROC_REF(/obj/structure/deity/altar, remove_target)) - events_repository.register(/decl/observ/moved, L, src, TYPE_PROC_REF(/obj/structure/deity/altar, remove_target)) - events_repository.register(/decl/observ/death, L, src, TYPE_PROC_REF(/obj/structure/deity/altar, remove_target)) - -/obj/structure/deity/altar/proc/remove_target() - STOP_PROCESSING(SSobj, src) - events_repository.unregister(/decl/observ/destroyed, target, src) - events_repository.unregister(/decl/observ/moved, target, src) - events_repository.unregister(/decl/observ/death, target, src) - target = null - update_icon() - -/obj/structure/deity/altar/OnTopic(var/user, var/list/href_list) - if(href_list["resist"]) - var/mob/living/M = locate(href_list["resist"]) - if(!istype(M) || target != M || M.stat || M.is_on_special_ability_cooldown()) - return TOPIC_HANDLED - - M.set_special_ability_cooldown(10 SECONDS) - M.visible_message(SPAN_WARNING("\The [M] writhes on top of \the [src]!"), SPAN_NOTICE("You struggle against the intruding thoughts, keeping them at bay!")) - to_chat(linked_god, SPAN_WARNING("\The [M] slows its conversion through willpower!")) - cycles_before_converted++ - if(prob(50)) - to_chat(M, SPAN_DANGER("The mental strain is too much for you! You feel your body weakening!")) - M.take_damage(15, TOX, do_update_health = FALSE) - M.take_damage(30, PAIN) - return TOPIC_REFRESH - -/obj/structure/deity/altar/on_update_icon() - ..() - if(target) - add_overlay(image('icons/effects/effects.dmi', icon_state = "summoning")) - -/obj/structure/deity/altar/nullrod_act(mob/user, obj/item/nullrod/rod) - if(!linked_god.silenced) //Don't want them to infinity spam it. - linked_god.silence(10) - new /obj/effect/temporary(get_turf(src),'icons/effects/effects.dmi',"purple_electricity_constant", 10) - visible_message(SPAN_NOTICE("\The [src] groans in protest as reality settles around \the [rod].")) - return TRUE - return FALSE \ No newline at end of file diff --git a/mods/gamemodes/deity/structures/blood_forge.dm b/mods/gamemodes/deity/structures/blood_forge.dm deleted file mode 100644 index 3b23da40630e..000000000000 --- a/mods/gamemodes/deity/structures/blood_forge.dm +++ /dev/null @@ -1,66 +0,0 @@ -/obj/structure/deity/blood_forge - name = "unholy forge" - desc = "This forge gives off no heat, no light, its flames look almost unnatural." - icon_state = "forge" - build_cost = 1000 - current_health = 50 - var/busy = 0 - var/recipe_feat_list = "Blood Crafting" - var/text_modifications = list( - "Cost" = "Blood", - "Dip" = "fire. Pain envelops you as blood seeps out of your hands and you begin to shape it into something more useful", - "Shape" = "You shape the fire as more and more blood comes out.", - "Out" = "flames" - ) - - power_adjustment = 2 - -/obj/structure/deity/blood_forge/attack_hand(var/mob/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return ..() - var/list/recipes = linked_god.feats[recipe_feat_list] - if(!recipes) - return TRUE - var/dat = "
Recipes


Item - [text_modifications["Cost"]] Cost
" - for(var/type in recipes) - var/atom/a = type - var/cost = recipes[type] - dat += "[initial(a.name)] - [cost]
[initial(a.desc)]

" - show_browser(user, dat, "window=forge") - return TRUE - -/obj/structure/deity/blood_forge/CanUseTopic(var/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return STATUS_CLOSE - return ..() - -/obj/structure/deity/blood_forge/OnTopic(var/user, var/list/href_list) - if(href_list["make_recipe"]) - var/list/recipes = linked_god.feats[recipe_feat_list] - var/type = locate(href_list["make_recipe"]) in recipes - if(type) - var/cost = recipes[type] - craft_item(type, cost, user) - return TOPIC_REFRESH - -/obj/structure/deity/blood_forge/proc/craft_item(var/path, var/blood_cost, var/mob/user) - if(busy) - to_chat(user, SPAN_WARNING("Someone is already using \the [src]!")) - return - - busy = 1 - to_chat(user, SPAN_NOTICE("You dip your hands into \the [src]'s [text_modifications["Dip"]]")) - for(var/count = 0, count < blood_cost/10, count++) - if(!do_after(user, 50,src)) - busy = 0 - return - user.visible_message("\The [user] swirls their hands in \the [src].", text_modifications["Shape"]) - if(linked_god) - linked_god.take_charge(user, 10) - var/obj/item/I = new path(get_turf(src)) - user.visible_message("\The [user] pull out \the [I] from the [text_modifications["Out"]].", "You pull out the completed [I] from the [text_modifications["Out"]].") - busy = 0 - -/obj/structure/deity/blood_forge/proc/take_charge(var/mob/living/user, var/charge) - if(linked_god) - linked_god.take_charge(user, charge) \ No newline at end of file diff --git a/mods/gamemodes/deity/structures/pylon.dm b/mods/gamemodes/deity/structures/pylon.dm deleted file mode 100644 index 4b977e2726d6..000000000000 --- a/mods/gamemodes/deity/structures/pylon.dm +++ /dev/null @@ -1,75 +0,0 @@ - -/obj/structure/deity/pylon - name = "pylon" - desc = "A crystal platform used to communicate with the deity." - build_cost = 400 - icon = 'icons/obj/structures/pylon.dmi' - icon_state = "pylon" - var/list/intuned = list() - -/obj/structure/deity/pylon/attack_deity(var/mob/living/deity/D) - if(D.pylon == src) - D.leave_pylon() - else - D.possess_pylon(src) - -/obj/structure/deity/pylon/Destroy() - if(linked_god && linked_god.pylon == src) - linked_god.leave_pylon() - return ..() - -/obj/structure/deity/pylon/attack_hand(var/mob/L) - SHOULD_CALL_PARENT(FALSE) - if(!linked_god) - return FALSE - if(L in intuned) - remove_intuned(L) - else - add_intuned(L) - return TRUE - -/obj/structure/deity/pylon/proc/add_intuned(var/mob/living/L) - if(L in intuned) - return - to_chat(L, SPAN_NOTICE("You place your hands on \the [src], feeling yourself intune to its vibrations.")) - intuned += L - events_repository.register(/decl/observ/destroyed, L,src, TYPE_PROC_REF(/obj/structure/deity/pylon, remove_intuned)) - -/obj/structure/deity/pylon/proc/remove_intuned(var/mob/living/L) - if(!(L in intuned)) - return - to_chat(L, SPAN_WARNING("You no longer feel intuned to \the [src].")) - intuned -= L - events_repository.unregister(/decl/observ/destroyed, L, src) - -/obj/structure/deity/pylon/OnTopic(var/mob/living/human/user, var/href_list) - if(href_list["vision_jump"]) - if(istype(user)) - to_chat(user,SPAN_WARNING("You feel your body lurch uncomfortably as your consciousness jumps to \the [src]")) - if(prob(5)) - user.vomit() - else - to_chat(user, SPAN_NOTICE("You jump to \the [src]")) - if(user.eyeobj) - user.eyeobj.setLoc(locate(href_list["vision_jump"])) - else - CRASH("[user] does not have an eyeobj") - . = TOPIC_REFRESH - . = ..() - -/obj/structure/deity/pylon/hear_talk(mob/M, text, verb, decl/language/speaking) - if(!linked_god) - return - if(linked_god.pylon != src) - if(!(M in intuned)) - return - for(var/obj/structure/deity/pylon/P in linked_god.structures) - if(P == src || linked_god.pylon == P) - continue - P.audible_message("\The [P] resonates, \"[text]\"") - to_chat(linked_god, "[html_icon(src)] [M] (P) [verb], [linked_god.pylon == src ? "" : ""]\"[text]\"[linked_god.pylon == src ? "" : ""]") - if(linked_god.minions.len) - for(var/minion in linked_god.minions) - var/datum/mind/mind = minion - if(mind.current && mind.current.eyeobj) //If it is currently having a vision of some sort - to_chat(mind.current,"[html_icon(src)] [M] (J) [verb], \"[text]\"") diff --git a/mods/gamemodes/deity/structures/structures.dm b/mods/gamemodes/deity/structures/structures.dm deleted file mode 100644 index c3d9ea65b30b..000000000000 --- a/mods/gamemodes/deity/structures/structures.dm +++ /dev/null @@ -1,68 +0,0 @@ -/proc/valid_deity_structure_spot(var/type, var/turf/target, var/mob/living/deity/deity, var/mob/living/user) - var/obj/structure/deity/D = type - var/flags = initial(D.deity_flags) - - if(flags & DEITY_STRUCTURE_NEAR_IMPORTANT && !deity.near_structure(target)) - if(user) - to_chat(user, SPAN_WARNING("You need to be near \a [deity.get_type_name(/obj/structure/deity/altar)] to build this!")) - return 0 - - if(flags & DEITY_STRUCTURE_ALONE) - for(var/structure in deity.structures) - if(istype(structure,type) && get_dist(target,structure) <= 3) - if(user) - to_chat(user, SPAN_WARNING("You are too close to another [deity.get_type_name(type)]!")) - return 0 - return 1 - -/obj/structure/deity - icon = 'icons/obj/cult.dmi' - max_health = 10 - density = TRUE - anchored = TRUE - icon_state = "tomealtar" - is_spawnable_type = FALSE // will usually runtime without a linked god - - var/mob/living/deity/linked_god - var/power_adjustment = 1 //How much power we get/lose - var/build_cost = 0 //How much it costs to build this item. - var/deity_flags = DEITY_STRUCTURE_NEAR_IMPORTANT - -/obj/structure/deity/Initialize(mapload, var/god) - . = ..(mapload) - if(god) - linked_god = god - linked_god.form.sync_structure(src) - linked_god.adjust_source(power_adjustment, src) - -/obj/structure/deity/Destroy() - if(linked_god) - linked_god.adjust_source(-power_adjustment, src) - linked_god = null - return ..() - -/obj/structure/deity/attackby(obj/item/W, mob/user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 50, 1) - user.visible_message( - SPAN_DANGER("[user] hits \the [src] with \the [W]!"), - SPAN_DANGER("You hit \the [src] with \the [W]!"), - SPAN_DANGER("You hear something breaking!") - ) - take_damage(W.get_attack_force(user), W.atom_damage_type) - -/obj/structure/deity/physically_destroyed(mob/user) - SHOULD_CALL_PARENT(FALSE) - qdel(src) - . = TRUE - -/obj/structure/deity/physically_destroyed(var/skip_qdel) - visible_message(SPAN_DANGER("\The [src] crumbles!")) - . = ..() - -/obj/structure/deity/bullet_act(var/obj/item/projectile/P) - take_damage(P.damage, P.atom_damage_type) - -/obj/structure/deity/proc/attack_deity(var/mob/living/deity/deity) - return \ No newline at end of file diff --git a/mods/gamemodes/deity/structures/trap.dm b/mods/gamemodes/deity/structures/trap.dm deleted file mode 100644 index 240050d33b9c..000000000000 --- a/mods/gamemodes/deity/structures/trap.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/structure/deity/trap - density = FALSE - current_health = 1 - var/triggered = 0 - -/obj/structure/deity/trap/Initialize() - . = ..() - events_repository.register(/decl/observ/entered, get_turf(src),src, TYPE_PROC_REF(/obj/structure/deity/trap, trigger)) - -/obj/structure/deity/trap/Destroy() - events_repository.unregister(/decl/observ/entered, get_turf(src),src) - return ..() - -/obj/structure/deity/trap/Move() - events_repository.unregister(/decl/observ/entered, get_turf(src),src) - . = ..() - events_repository.register(/decl/observ/entered, get_turf(src), src, TYPE_PROC_REF(/obj/structure/deity/trap, trigger)) - -/obj/structure/deity/trap/attackby(obj/item/W, mob/user) - trigger(user) - return ..() - -/obj/structure/deity/trap/bullet_act() - return - -/obj/structure/deity/trap/proc/trigger(var/atom/entered, var/atom/movable/enterer) - if(triggered > world.time || !isliving(enterer)) - return - - triggered = world.time + 30 SECONDS \ No newline at end of file diff --git a/nano/templates/deity.tmpl b/nano/templates/deity.tmpl deleted file mode 100644 index 5d1148e300e2..000000000000 --- a/nano/templates/deity.tmpl +++ /dev/null @@ -1,116 +0,0 @@ - -
-

Deity Menu

-
- {{:data.name}} the {{:data.form_name}} -
-
- Current Boon: - {{if data.boon_name}} - {{:data.boon_name}} - {{else}} - N/A - {{/if}} -
-
- Power: {{:data.power}} Power Minimum: {{:data.power_min}} Regen: {{:data.regen}} -
-
- {{:helper.link('Followers', 'person', {'switchMenu' : 0, 'menu' : 'menu'}, data.menu == 0 ? 'disabled' : null)}} - {{:helper.link('Shop', 'suitcase', {'switchMenu' : 1, 'menu' : 'menu'}, data.menu == 1 ? 'disabled' : null)}} - {{:helper.link('Phenomena', 'star', {'switchMenu' : 2, 'menu' : 'menu'}, data.menu == 2 ? 'disabled' : null)}} -
-
-{{if data.menu == 0}} -

Followers

- {{for data.followers}} -
- {{:value.name}} -
-
- {{:helper.link('Jump', 'zoomin', {'jump' : value.ref}, value.ref ? null : 'disabled')}} - {{:helper.link('Follow', 'zoomout', {'jump' : value.ref, 'follow' : 1}, value.ref ? null : 'disabled')}} -
- {{empty}} - You have no minions! - {{/for}} -{{else data.menu == 1}} -

Shop

-
- {{for data.categories}} - {{:helper.link(value, null, {'switchCategory' : index}, index == data.category ? 'disabled' : null)}} - {{/for}} -
-
- {{for data.item_data}} -
-
- {{:helper.link(value.name, null, {'buy' : value.ref})}} (Level {{:value.level}}) -
-
- Costs: {{:value.cost}} Requires: {{:value.requirements}} -
-
- {{:value.desc}} -
-
- {{empty}} - There is nothing there! - {{/for}} -{{else data.menu == 2}} -

Phenomena

-
-
- Selected Phenomena: -
-
- {{if data.selectedPhenomenaName}} - {{:helper.link(data.selectedPhenomenaName, null, {'clear_selected' : 1})}} - {{else}} - N/A - {{/if}} -
-
-
- {{:helper.link('Phenomena', 'star', {'switchMenu' : 0, 'menu' : 'phenomenaMenu'}, data.phenomenaMenu == 0 ? 'disabled' : null)}} - {{:helper.link('Bindings', 'key', {'switchMenu' : 1, 'menu' : 'phenomenaMenu'}, data.phenomenaMenu == 1 ? 'disabled' : null)}} -
- {{if data.phenomenaMenu == 0}} - {{for data.phenomena}} -
-
- {{:helper.link(value.name, null, {'select_phenomena' : value.name})}} -
-
- Use Cost: {{:value.cost}} - {{if value.cooldown}} - Cooldown: {{:value.cooldown}} - {{/if}} -
-
- {{:value.description}} -
-
- {{empty}} - You don't have any phenomena! - {{/for}} - {{else data.phenomenaMenu == 1}} - {{for data.bindings}} -

{{:value.intent}}

- {{for value.intent_data :intentValue:intentKey}} -
-
- {{:intentValue.binding}} -
-
- {{:helper.link(intentValue.phenomena_name ? intentValue.phenomena_name : 'N/A', null, {'select_intent' : value.intent, 'select_binding' : intentValue.binding})}} -
-
- {{/for}} -
- {{/for}} - {{/if}} -{{/if}} -
\ No newline at end of file diff --git a/nebula.dme b/nebula.dme index 44929d112015..b8ec27833411 100644 --- a/nebula.dme +++ b/nebula.dme @@ -3763,8 +3763,6 @@ #include "code\modules\species\species_shapeshifter.dm" #include "code\modules\species\species_shapeshifter_bodytypes.dm" #include "code\modules\species\outsider\random.dm" -#include "code\modules\species\outsider\shadow.dm" -#include "code\modules\species\outsider\starlight.dm" #include "code\modules\species\station\golem.dm" #include "code\modules\species\station\human.dm" #include "code\modules\species\station\human_bodytypes.dm" diff --git a/test/check-paths.sh b/test/check-paths.sh index 161216458247..77f46145433e 100755 --- a/test/check-paths.sh +++ b/test/check-paths.sh @@ -47,7 +47,7 @@ exactly 3 "unmarked globally scoped variables" '^(/|)var/(?!global)' -P exactly 0 "global-marked member variables" '\t(/|)var.*/global/.+' -P exactly 0 "static-marked globally scoped variables" '^(/|)var.*/static/.+' -P exactly 1 "direct usage of decls_repository.get_decl()" 'decls_repository\.get_decl\(' -P -exactly 20 "direct loc set" '(\t|;|\.)loc\s*=(?!=)' -P +exactly 19 "direct loc set" '(\t|;|\.)loc\s*=(?!=)' -P exactly 0 "magic number mouse opacity set" 'mouse_opacity\s*=\s*[0-2]' -P exactly 1 "magic number density set" '\bdensity\s*=\s*[01]' -P exactly 0 "magic number anchored set" '\banchored\s*=\s*[01]' -P From 88d1e5722de79d1c0ecc210e95f758bb04f59b76 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Wed, 4 Dec 2024 17:21:27 +1100 Subject: [PATCH 16/90] Adding Doe's room dividers. --- code/game/objects/structures/divider.dm | 48 ++++++++++++++++++ .../crafting/stack_recipes/recipes_planks.dm | 5 ++ icons/obj/structures/divider.dmi | Bin 0 -> 545 bytes nebula.dme | 1 + 4 files changed, 54 insertions(+) create mode 100644 code/game/objects/structures/divider.dm create mode 100644 icons/obj/structures/divider.dmi diff --git a/code/game/objects/structures/divider.dm b/code/game/objects/structures/divider.dm new file mode 100644 index 000000000000..d0cb78e85dfd --- /dev/null +++ b/code/game/objects/structures/divider.dm @@ -0,0 +1,48 @@ +/obj/structure/divider + name = "room divider" + desc = "A thin, somewhat flimsy folding room divider." + icon = 'icons/obj/structures/divider.dmi' + icon_state = ICON_STATE_WORLD + "-closed" + material = /decl/material/solid/organic/wood/bamboo + color = /decl/material/solid/organic/wood/bamboo::color + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + var/extended = FALSE + +/obj/structure/divider/extended + icon_state = ICON_STATE_WORLD + extended = TRUE + +/obj/structure/divider/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/divider/extended/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/divider/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HELP) && user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, silent = TRUE)) + extended = !extended + if(material.dooropen_noise) + playsound(loc, material.dooropen_noise, 50, 1) + update_divider() + visible_message(SPAN_NOTICE("\The [user] [extended ? "extends" : "collapses"] \the [src].")) + return TRUE + . = ..() + +/obj/structure/divider/Initialize() + . = ..() + update_divider() + +/obj/structure/divider/proc/update_divider() + anchored = extended + density = extended + opacity = extended || (material.opacity < 0.5) + update_icon() + +/obj/structure/divider/on_update_icon() + . = ..() + if(extended) + icon_state = ICON_STATE_WORLD + else + icon_state = ICON_STATE_WORLD + "-closed" diff --git a/code/modules/crafting/stack_recipes/recipes_planks.dm b/code/modules/crafting/stack_recipes/recipes_planks.dm index f8a750754998..f58f931cf5bb 100644 --- a/code/modules/crafting/stack_recipes/recipes_planks.dm +++ b/code/modules/crafting/stack_recipes/recipes_planks.dm @@ -222,3 +222,8 @@ /decl/stack_recipe/planks/furniture/gravemarker result_type = /obj/item/gravemarker difficulty = MAT_VALUE_NORMAL_DIY + +/decl/stack_recipe/planks/furniture/divider + result_type = /obj/structure/divider + difficulty = MAT_VALUE_HARD_DIY + diff --git a/icons/obj/structures/divider.dmi b/icons/obj/structures/divider.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5016482a2a1a740de5245e13695a1c7006702be2 GIT binary patch literal 545 zcmV++0^a?JP)p8x;sVP5=M^0d!JMQvg8b*k%9#0Csv*Sad{Xb7OL8aCB*J zZU6vyoKseCa&`CgQ*iP1D@x2wg|Jao=_cpo7pEdAHbGIWtl;YB0(Juc zO!z0Gl`RsA0003vNkl^!8U}@2U1G7cTS7iVkAW? z0#k7An1Zh6XjTNa)7!M2rmm@35eRFsCaegUW-xMeu_MHE`1GElN?f{OebOzFr0smPX zc%^2?Rs_E2-$r2t5x8)jNmyqQprJCi$uhH*#?0eGeh+R!eh>aWAif8;arcK3r^E|* jRzRE*FW^~$hrb8ksLQZ5vNt~K00000NkvXXu0mjf`5Eii literal 0 HcmV?d00001 diff --git a/nebula.dme b/nebula.dme index 44929d112015..d3da872dbb52 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1440,6 +1440,7 @@ #include "code\game\objects\structures\curtains.dm" #include "code\game\objects\structures\defensive_barrier.dm" #include "code\game\objects\structures\displaycase.dm" +#include "code\game\objects\structures\divider.dm" #include "code\game\objects\structures\dogbed.dm" #include "code\game\objects\structures\door_assembly.dm" #include "code\game\objects\structures\double_sign.dm" From 9e4b0f9c631f73600fd5e7fb4032d9c96cd82faa Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sat, 7 Dec 2024 12:10:36 -0500 Subject: [PATCH 17/90] Fix banner merge skew --- code/modules/banners/__banner.dm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/code/modules/banners/__banner.dm b/code/modules/banners/__banner.dm index 647f3adc73a3..34727eaa11b7 100644 --- a/code/modules/banners/__banner.dm +++ b/code/modules/banners/__banner.dm @@ -1,5 +1,6 @@ /obj/item/banner name = "banner" + base_name = "banner" // necessary for premapped subtypes desc = "A furled-up banner." icon = 'icons/obj/items/banners/banner.dmi' icon_state = ICON_STATE_WORLD @@ -12,7 +13,6 @@ var/hung_desc = "The banner is rather unremarkable." var/banner_type = /obj/item/banner var/embroiderable = TRUE - var/name_prefix var/list/decals var/trim_color @@ -66,11 +66,6 @@ var/global/list/banner_type_to_symbols = list() . = ..() -// 'woven grass banner', 'forked linen banner' -/obj/item/banner/update_name() - . = ..() - SetName("[name_prefix] [name]") - /obj/item/banner/examine(mob/user, distance, infix, suffix) . = ..() var/decorations = get_decal_string() From e6d6c44c4d9bc36ecbc534c552b34208d9cd72e6 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Wed, 27 Nov 2024 20:49:12 -0500 Subject: [PATCH 18/90] Make cables use paint_color --- code/_global_vars/lists/flavor.dm | 8 +++---- code/modules/power/cable.dm | 37 ++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/code/_global_vars/lists/flavor.dm b/code/_global_vars/lists/flavor.dm index ccf00b40b7e2..b2096edc0a4f 100644 --- a/code/_global_vars/lists/flavor.dm +++ b/code/_global_vars/lists/flavor.dm @@ -115,15 +115,13 @@ GLOBAL_GETTER(cable_colors, /list, SetupCableColors()) /proc/SetupCableColors() . = list() - var/list/valid_cable_coils = typesof(/obj/item/stack/cable_coil) - for(var/ctype in list( + var/list/valid_cable_coils = typesof(/obj/item/stack/cable_coil) - typesof( /obj/item/stack/cable_coil/single, /obj/item/stack/cable_coil/cut, /obj/item/stack/cable_coil/cyborg, /obj/item/stack/cable_coil/fabricator, /obj/item/stack/cable_coil/random - )) - valid_cable_coils -= typesof(ctype) + ) var/special_name_mappings = list(/obj/item/stack/cable_coil = "Red") for(var/coil_type in valid_cable_coils) @@ -132,6 +130,6 @@ GLOBAL_GETTER(cable_colors, /list, SetupCableColors()) var/obj/item/stack/cable_coil/C = coil_type if(!initial(C.can_have_color)) continue - var/color = initial(C.color) + var/color = initial(C.paint_color) || initial(C.color) .[name] = color . = sortTim(., /proc/cmp_text_asc) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 4cc7b4d07516..29c71764deb5 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -26,9 +26,10 @@ By design, d1 is the smallest direction and d2 is the highest name = "power cable" desc = "A flexible superconducting cable for heavy-duty power transfer." icon = 'icons/obj/power_cond_white.dmi' - icon_state = "0-1" - layer = EXPOSED_WIRE_LAYER - color = COLOR_MAROON + icon_state = "0-1" + layer = EXPOSED_WIRE_LAYER + color = COLOR_MAROON + paint_color = COLOR_MAROON anchored = TRUE obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED level = LEVEL_BELOW_PLATING @@ -55,24 +56,31 @@ By design, d1 is the smallest direction and d2 is the highest /obj/structure/cable/yellow color = COLOR_AMBER + paint_color = COLOR_AMBER /obj/structure/cable/green color = COLOR_GREEN + paint_color = COLOR_GREEN /obj/structure/cable/blue color = COLOR_CYAN_BLUE + paint_color = COLOR_CYAN_BLUE /obj/structure/cable/pink color = COLOR_PURPLE + paint_color = COLOR_PURPLE /obj/structure/cable/orange color = COLOR_ORANGE + paint_color = COLOR_ORANGE /obj/structure/cable/cyan color = COLOR_SKY_BLUE + paint_color = COLOR_SKY_BLUE /obj/structure/cable/white color = COLOR_SILVER + paint_color = COLOR_SILVER /obj/structure/cable/Initialize(var/ml) // ensure d1 & d2 reflect the icon_state for entering and exiting cable @@ -264,7 +272,7 @@ By design, d1 is the smallest direction and d2 is the highest var/color_n = "#dd0000" if(colorC) color_n = colorC - color = color_n + set_color(color_n) ///////////////////////////////////////////////// // Cable laying helpers @@ -502,6 +510,7 @@ By design, d1 is the smallest direction and d2 is the highest amount = MAXCOIL max_amount = MAXCOIL color = COLOR_MAROON + paint_color = COLOR_MAROON desc = "A coil of wiring, suitable for both delicate electronics and heavy duty power supply." singular_name = "length" w_class = ITEM_SIZE_NORMAL @@ -544,7 +553,7 @@ By design, d1 is the smallest direction and d2 is the highest TOOL_SUTURES = TOOL_QUALITY_MEDIOCRE )) if (can_have_color && param_color) // It should be red by default, so only recolor it if parameter was specified. - color = param_color + set_color(param_color) update_icon() update_wclass() @@ -569,9 +578,9 @@ By design, d1 is the smallest direction and d2 is the highest /obj/item/stack/cable_coil/on_update_icon() . = ..() - if (!color && can_have_color) + if (!paint_color && can_have_color) var/list/possible_cable_colours = get_global_cable_colors() - color = possible_cable_colours[pick(possible_cable_colours)] + set_color(possible_cable_colours[pick(possible_cable_colours)]) if(amount == 1) icon_state = "coil1" SetName("cable piece") @@ -594,7 +603,7 @@ By design, d1 is the smallest direction and d2 is the highest if(!final_color) selected_color = "Red" final_color = possible_cable_colours[selected_color] - color = final_color + set_color(final_color) to_chat(user, SPAN_NOTICE("You change \the [src]'s color to [lowertext(selected_color)].")) /obj/item/stack/cable_coil/proc/update_wclass() @@ -627,7 +636,7 @@ By design, d1 is the smallest direction and d2 is the highest to_chat(usr, SPAN_WARNING("You need at least 15 [plural_name] of cable to make restraints!")) return var/obj/item/handcuffs/cable/B = new /obj/item/handcuffs/cable(usr.loc) - B.color = color + B.set_color(color) to_chat(usr, SPAN_NOTICE("You wind some [plural_name] of cable together to make some restraints.")) else to_chat(usr, SPAN_NOTICE("You cannot do that.")) @@ -842,31 +851,39 @@ By design, d1 is the smallest direction and d2 is the highest /obj/item/stack/cable_coil/yellow color = COLOR_AMBER + paint_color = COLOR_AMBER /obj/item/stack/cable_coil/blue color = COLOR_CYAN_BLUE + paint_color = COLOR_CYAN_BLUE /obj/item/stack/cable_coil/green color = COLOR_GREEN + paint_color = COLOR_GREEN /obj/item/stack/cable_coil/pink color = COLOR_PURPLE + paint_color = COLOR_PURPLE /obj/item/stack/cable_coil/orange color = COLOR_ORANGE + paint_color = COLOR_ORANGE /obj/item/stack/cable_coil/cyan color = COLOR_SKY_BLUE + paint_color = COLOR_SKY_BLUE /obj/item/stack/cable_coil/white color = COLOR_SILVER + paint_color = COLOR_SILVER /obj/item/stack/cable_coil/lime color = COLOR_LIME + paint_color = COLOR_LIME /obj/item/stack/cable_coil/random/Initialize(mapload, c_length, param_color) var/list/possible_cable_colours = get_global_cable_colors() - color = possible_cable_colours[pick(possible_cable_colours)] + set_color(possible_cable_colours[pick(possible_cable_colours)]) . = ..() // Produces cable coil from a rig power cell. From 7eb2d72c2d6438854f615dd1b739d4df293ed6f5 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Wed, 27 Nov 2024 20:49:32 -0500 Subject: [PATCH 19/90] Simplify shard alpha calculation --- code/game/objects/items/weapons/material/shards.dm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index 0f7ba375f552..dd248df7bb77 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -51,12 +51,8 @@ /obj/item/shard/on_update_icon() . = ..() - if(material) - // 1-(1-x)^2, so that glass shards with 0.3 opacity end up somewhat visible at 0.51 opacity - alpha = 255 * (1 - (1 - material.opacity)*(1 - material.opacity)) - else - color = "#ffffff" - alpha = 255 + // 1-(1-x)^2, so that glass shards with 0.3 opacity end up somewhat visible at 0.51 opacity + alpha = 255 * (material ? (1 - (1 - material.opacity)**2) : 1) /obj/item/shard/attackby(obj/item/W, mob/user) if(IS_WELDER(W) && material.shard_can_repair) From 7a9febd36f718e0220dbb5d1935a11c0d0c5cbb8 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Wed, 27 Nov 2024 20:50:05 -0500 Subject: [PATCH 20/90] Rewrite table icon code --- code/game/objects/structures/tables.dm | 141 +++++++++++++------------ 1 file changed, 75 insertions(+), 66 deletions(-) diff --git a/code/game/objects/structures/tables.dm b/code/game/objects/structures/tables.dm index c66281e59f21..0f6a48c2a6be 100644 --- a/code/game/objects/structures/tables.dm +++ b/code/game/objects/structures/tables.dm @@ -59,8 +59,11 @@ // We do this because need to make sure adjacent tables init their material before we try and merge. /obj/structure/table/LateInitialize() ..() - update_connections(TRUE) - update_icon() + if(is_flipped) + flip(dir, TRUE) + else + update_connections(TRUE) + update_icon() /obj/structure/table/get_material_health_modifier() . = additional_reinf_material ? 0.75 : 0.5 @@ -290,80 +293,78 @@ if(additional_reinf_material) desc = "[desc] It has been reinforced with [additional_reinf_material.solid_name]." -/obj/structure/table/on_update_icon() - - color = "#ffffff" +/obj/structure/table/update_material_colour() + if(is_flipped) + return ..() alpha = 255 - ..() - - if(!handle_generic_blending) - return + reset_color() +/obj/structure/table/proc/handle_normal_icon() icon_state = "blank" - if(!is_flipped) - mob_offset = initial(mob_offset) - var/image/I - // Base frame shape. + var/image/I + // Base frame shape. + for(var/i = 1 to 4) + I = image(icon, dir = BITFLAG(i-1), icon_state = connections ? connections[i] : "0") + I.color = material.color + I.alpha = 255 * material.opacity + add_overlay(I) + // Tabletop + if(reinf_material) for(var/i = 1 to 4) - I = image(icon, dir = BITFLAG(i-1), icon_state = connections ? connections[i] : "0") - I.color = material.color - I.alpha = 255 * material.opacity - add_overlay(I) - // Tabletop - if(reinf_material) - for(var/i = 1 to 4) - I = image(icon, "[reinf_material.table_icon_base]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) - I.color = reinf_material.color - I.alpha = 255 * reinf_material.opacity - add_overlay(I) - if(additional_reinf_material) - for(var/i = 1 to 4) - I = image(icon, "[additional_reinf_material.table_icon_reinforced]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) - I.color = additional_reinf_material.color - I.alpha = 255 * additional_reinf_material.opacity - add_overlay(I) - - if(felted) - for(var/i = 1 to 4) - add_overlay(image(icon, "carpet_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1))) - else - - mob_offset = 0 - - var/obj/structure/table/left_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, -90)) - var/obj/structure/table/right_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, 90)) - var/left_neighbor_blend = istype(left_neighbor) && blend_with(left_neighbor) && left_neighbor.is_flipped == is_flipped && left_neighbor.dir == dir - var/right_neighbor_blend = istype(right_neighbor) && blend_with(right_neighbor) && right_neighbor.is_flipped == is_flipped && right_neighbor.dir == dir - - var/flip_type = 0 - var/flip_mod = "" - if(left_neighbor_blend && right_neighbor_blend) - flip_type = 2 - icon_state = "flip[flip_type]" - else if(left_neighbor_blend || right_neighbor_blend) - flip_type = 1 - flip_mod = (left_neighbor_blend ? "+" : "-") - icon_state = "flip[flip_type][flip_mod]" - - color = material.color - alpha = 255 * material.opacity - - var/image/I - if(reinf_material) - I = image(icon, "[reinf_material.table_icon_base]_flip[flip_type][flip_mod]") + I = image(icon, "[reinf_material.table_icon_base]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) I.color = reinf_material.color I.alpha = 255 * reinf_material.opacity - I.appearance_flags |= RESET_COLOR|RESET_ALPHA add_overlay(I) - if(additional_reinf_material) - I = image(icon, "[reinf_material.table_icon_reinforced]_flip[flip_type][flip_mod]") + if(additional_reinf_material) + for(var/i = 1 to 4) + I = image(icon, "[additional_reinf_material.table_icon_reinforced]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) I.color = additional_reinf_material.color I.alpha = 255 * additional_reinf_material.opacity - I.appearance_flags |= RESET_COLOR|RESET_ALPHA add_overlay(I) - if(felted) - add_overlay("carpet_flip[flip_type][flip_mod]") + if(felted) + for(var/i = 1 to 4) + add_overlay(image(icon, "carpet_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1))) + +/obj/structure/table/proc/handle_flipped_icon() + var/obj/structure/table/left_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, -90)) + var/obj/structure/table/right_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, 90)) + var/left_neighbor_blend = istype(left_neighbor) && blend_with(left_neighbor) && left_neighbor.is_flipped == is_flipped && left_neighbor.dir == dir + var/right_neighbor_blend = istype(right_neighbor) && blend_with(right_neighbor) && right_neighbor.is_flipped == is_flipped && right_neighbor.dir == dir + + var/flip_type = 0 + var/flip_mod = "" + if(left_neighbor_blend && right_neighbor_blend) + flip_type = 2 + icon_state = "flip[flip_type]" + else if(left_neighbor_blend || right_neighbor_blend) + flip_type = 1 + flip_mod = (left_neighbor_blend ? "+" : "-") + icon_state = "flip[flip_type][flip_mod]" + + var/image/I + if(reinf_material) + I = image(icon, "[reinf_material.table_icon_base]_flip[flip_type][flip_mod]") + I.color = reinf_material.color + I.alpha = 255 * reinf_material.opacity + I.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(I) + if(additional_reinf_material) + I = image(icon, "[reinf_material.table_icon_reinforced]_flip[flip_type][flip_mod]") + I.color = additional_reinf_material.color + I.alpha = 255 * additional_reinf_material.opacity + I.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(I) + + if(felted) + add_overlay("carpet_flip[flip_type][flip_mod]") + +/obj/structure/table/on_update_icon() + . = ..() + if(is_flipped) + handle_flipped_icon() + else + handle_normal_icon() /obj/structure/table/proc/blend_with(var/obj/structure/table/other) if(!istype(other) || !istype(material) || !istype(other.material) || material.type != other.material.type) @@ -585,7 +586,8 @@ if(dir != NORTH) layer = ABOVE_HUMAN_LAYER atom_flags &= ~ATOM_FLAG_CLIMBABLE //flipping tables allows them to be used as makeshift barriers - is_flipped = 1 + is_flipped = TRUE + mob_offset = 0 atom_flags |= ATOM_FLAG_CHECKS_BORDER for(var/D in list(turn(direction, 90), turn(direction, -90))) @@ -617,6 +619,7 @@ reset_plane_and_layer() atom_flags |= ATOM_FLAG_CLIMBABLE is_flipped = FALSE + mob_offset = initial(mob_offset) atom_flags &= ~ATOM_FLAG_CHECKS_BORDER for(var/D in list(turn(dir, 90), turn(dir, -90))) var/obj/structure/table/T = locate() in get_step(src.loc,D) @@ -792,6 +795,9 @@ material_alteration = MAT_FLAG_ALTERATION_ALL can_flip = FALSE +/obj/structure/table/end/handle_normal_icon() + icon_state = initial(icon_state) + /obj/structure/table/end/alt icon_state = "end_table_2" @@ -838,6 +844,9 @@ // we don't do frames or anything, just skip right to decon tool_interaction_flags |= TOOL_INTERACTION_DECONSTRUCT +/obj/structure/table/desk/handle_normal_icon() + return // logic is handled in on_update_icon + /obj/structure/table/desk/right icon_state = "desk_right" From e11012aac57394bd645064206cef1b6f720ca68b Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sat, 7 Dec 2024 16:20:02 -0500 Subject: [PATCH 21/90] Fix cable uniqueness test output --- code/unit_tests/unique_tests.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/unit_tests/unique_tests.dm b/code/unit_tests/unique_tests.dm index 2d23719ea302..88579d331327 100644 --- a/code/unit_tests/unique_tests.dm +++ b/code/unit_tests/unique_tests.dm @@ -9,7 +9,7 @@ var/list/possible_cable_colours = get_global_cable_colors() for(var/color_name in possible_cable_colours) group_by(names, color_name, index) - group_by(colors, possible_cable_colours[color_name], index) + group_by(colors, possible_cable_colours[color_name], color_name) index++ var/number_of_issues = number_of_issues(names, "Names") From 1a62c5dbcb9d2ec4d893ead791d96aef67f74d6a Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Thu, 5 Dec 2024 14:53:07 +1100 Subject: [PATCH 22/90] Removing wizard. --- code/__defines/gamemode.dm | 23 +- code/_onclick/hud/screen/screen_abilities.dm | 6 +- .../datums/config/config_types/config_mode.dm | 7 +- code/datums/mind/mind.dm | 1 - code/datums/outfits/wizardry.dm | 6 +- code/datums/supplypacks/nonessent.dm | 8 +- code/datums/trading/traders/ai.dm | 1 - code/datums/trading/traders/goods.dm | 1 - code/datums/trading/traders/misc.dm | 4 +- code/datums/trading/traders/unique.dm | 48 - code/game/antagonist/outsider/wizard.dm | 115 -- .../wizard/servant_items/caretaker.dm | 34 - .../wizard/servant_items/champion.dm | 85 - .../wizard/servant_items/familiar.dm | 15 - .../gamemodes/wizard/servant_items/fiend.dm | 49 - .../wizard/servant_items/infiltrator.dm | 42 - .../wizard/servant_items/overseer.dm | 40 - code/game/gamemodes/wizard/wizard.dm | 10 - code/game/gamemodes/wizard/wizard_props.dm | 21 - code/game/jobs/access_datum.dm | 6 - code/game/objects/effects/landmarks.dm | 12 +- .../objects/items/devices/radio/intercom.dm | 4 - code/game/objects/items/hourglass.dm | 6 +- code/game/objects/items/weapons/scrolls.dm | 50 - code/game/objects/items/weapons/staff.dm | 3 +- code/modules/clothing/_clothing.dm | 1 - code/modules/clothing/head/wizard.dm | 32 + code/modules/clothing/masks/miscellaneous.dm | 10 +- code/modules/clothing/shoes/miscellaneous.dm | 1 - .../clothing/spacesuits/void/wizard.dm | 66 - code/modules/clothing/suits/misc.dm | 5 + code/modules/clothing/suits/wiz_robe.dm | 113 -- code/modules/clothing/suits/wizard.dm | 25 + code/modules/ghosttrap/trap.dm | 12 - code/modules/mob/death.dm | 2 +- .../simple_animal/familiars/familiars.dm | 133 -- code/modules/organs/internal/species/golem.dm | 5 +- .../modules/projectiles/guns/energy/staves.dm | 12 +- code/modules/spells/aoe_turf/aoe_turf.dm | 4 +- code/modules/spells/aoe_turf/blink.dm | 44 - code/modules/spells/aoe_turf/charge.dm | 72 - .../spells/aoe_turf/conjure/conjure.dm | 5 +- .../spells/aoe_turf/conjure/druidic_spells.dm | 113 -- .../spells/aoe_turf/conjure/faithful_hound.dm | 28 - .../spells/aoe_turf/conjure/force_portal.dm | 12 - .../spells/aoe_turf/conjure/forcewall.dm | 48 - code/modules/spells/aoe_turf/conjure/grove.dm | 75 - code/modules/spells/aoe_turf/disable_tech.dm | 33 - code/modules/spells/aoe_turf/drain_blood.dm | 66 - .../spells/aoe_turf/exchange_wounds.dm | 43 - code/modules/spells/aoe_turf/knock.dm | 37 - code/modules/spells/aoe_turf/smoke.dm | 26 - code/modules/spells/aoe_turf/summons.dm | 72 - code/modules/spells/artifacts.dm | 41 - .../spells/artifacts/spellbound_servants.dm | 284 --- code/modules/spells/artifacts/storage.dm | 30 - code/modules/spells/contracts.dm | 142 -- code/modules/spells/general/acid_spray.dm | 26 - code/modules/spells/general/area_teleport.dm | 60 - code/modules/spells/general/camera_vision.dm | 36 - .../modules/spells/general/contract_spells.dm | 68 - code/modules/spells/general/create_air.dm | 24 - code/modules/spells/general/invisibility.dm | 24 - code/modules/spells/general/mark_recall.dm | 88 - .../modules/spells/general/portal_teleport.dm | 67 - code/modules/spells/general/radiant_aura.dm | 21 - code/modules/spells/general/return_master.dm | 23 - code/modules/spells/general/toggle_armor.dm | 121 -- code/modules/spells/hand/blood_shards.dm | 39 - code/modules/spells/hand/burning_grip.dm | 39 - code/modules/spells/hand/entangle.dm | 51 - code/modules/spells/hand/hand.dm | 83 - code/modules/spells/hand/hand_item.dm | 68 - code/modules/spells/hand/slippery_surface.dm | 19 - code/modules/spells/hand/sunwrath.dm | 32 - code/modules/spells/no_clothes.dm | 5 - code/modules/spells/racial_wizard.dm | 81 - code/modules/spells/spell_code.dm | 28 +- code/modules/spells/spell_projectile.dm | 56 - code/modules/spells/spellbook.dm | 322 --- code/modules/spells/spellbook/battlemage.dm | 44 - code/modules/spells/spellbook/cleric.dm | 50 - code/modules/spells/spellbook/druid.dm | 43 - code/modules/spells/spellbook/spatial.dm | 48 - code/modules/spells/spellbook/standard.dm | 54 - code/modules/spells/spellbook/student.dm | 28 - code/modules/spells/targeted/analyze.dm | 19 - code/modules/spells/targeted/blood_boil.dm | 25 - code/modules/spells/targeted/cleric_spells.dm | 248 --- .../spells/targeted/equip/burning_touch.dm | 69 - code/modules/spells/targeted/equip/dyrnwyn.dm | 37 - code/modules/spells/targeted/equip/equip.dm | 38 - .../spells/targeted/equip/holy_relic.dm | 34 - .../spells/targeted/equip/horsemask.dm | 48 - .../spells/targeted/equip/party_hardy.dm | 36 - code/modules/spells/targeted/equip/seed.dm | 21 - code/modules/spells/targeted/equip/shield.dm | 41 - .../modules/spells/targeted/ethereal_jaunt.dm | 2 +- .../spells/targeted/exude_pleasantness.dm | 19 - code/modules/spells/targeted/genetic.dm | 73 - .../spells/targeted/glimpse_of_eternity.dm | 26 - .../spells/targeted/projectile/dumbfire.dm | 13 - .../spells/targeted/projectile/fireball.dm | 66 - .../targeted/projectile/magic_missile.dm | 56 - .../spells/targeted/projectile/passage.dm | 46 - .../spells/targeted/projectile/projectile.dm | 45 - .../spells/targeted/projectile/stuncuff.dm | 47 - code/modules/spells/targeted/shapeshift.dm | 203 -- code/modules/spells/targeted/shatter_mind.dm | 29 - code/modules/spells/targeted/shift.dm | 2 +- code/modules/spells/targeted/subjugate.dm | 35 - code/modules/spells/targeted/swap.dm | 41 - code/modules/spells/targeted/targeted.dm | 45 +- code/modules/spells/targeted/torment.dm | 34 - config/example/configuration.txt | 39 +- maps/antag_spawn/wizard/wizard.dm | 13 - maps/antag_spawn/wizard/wizard_base.dmm | 1747 ----------------- mods/content/corporate/items/stamps.dm | 4 +- mods/content/psionics/_psionics.dme | 1 + .../psionics/datum/antagonists/paramount.dm | 2 +- mods/content/psionics/datum/chems.dm | 8 +- mods/content/psionics/items/clothing.dm | 16 + mods/gamemodes/cult/_cult.dme | 1 - mods/gamemodes/cult/items.dm | 6 +- mods/gamemodes/cult/overrides.dm | 13 - mods/gamemodes/cult/wizard.dm | 47 - .../bayliens/tajaran/machinery/suit_cycler.dm | 3 - mods/species/vox/_vox.dme | 1 - mods/species/vox/datum/antagonism.dm | 4 - mods/species/vox/gear/gun.dm | 24 - nebula.dme | 87 +- 131 files changed, 171 insertions(+), 7080 deletions(-) delete mode 100644 code/game/antagonist/outsider/wizard.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/caretaker.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/champion.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/familiar.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/fiend.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/infiltrator.dm delete mode 100644 code/game/gamemodes/wizard/servant_items/overseer.dm delete mode 100644 code/game/gamemodes/wizard/wizard.dm delete mode 100644 code/game/gamemodes/wizard/wizard_props.dm delete mode 100644 code/game/objects/items/weapons/scrolls.dm create mode 100644 code/modules/clothing/head/wizard.dm delete mode 100644 code/modules/clothing/spacesuits/void/wizard.dm create mode 100644 code/modules/clothing/suits/misc.dm delete mode 100644 code/modules/clothing/suits/wiz_robe.dm create mode 100644 code/modules/clothing/suits/wizard.dm delete mode 100644 code/modules/mob/living/simple_animal/familiars/familiars.dm delete mode 100644 code/modules/spells/aoe_turf/blink.dm delete mode 100644 code/modules/spells/aoe_turf/charge.dm delete mode 100644 code/modules/spells/aoe_turf/conjure/druidic_spells.dm delete mode 100644 code/modules/spells/aoe_turf/conjure/faithful_hound.dm delete mode 100644 code/modules/spells/aoe_turf/conjure/force_portal.dm delete mode 100644 code/modules/spells/aoe_turf/conjure/forcewall.dm delete mode 100644 code/modules/spells/aoe_turf/conjure/grove.dm delete mode 100644 code/modules/spells/aoe_turf/disable_tech.dm delete mode 100644 code/modules/spells/aoe_turf/drain_blood.dm delete mode 100644 code/modules/spells/aoe_turf/exchange_wounds.dm delete mode 100644 code/modules/spells/aoe_turf/knock.dm delete mode 100644 code/modules/spells/aoe_turf/smoke.dm delete mode 100644 code/modules/spells/aoe_turf/summons.dm delete mode 100644 code/modules/spells/artifacts.dm delete mode 100644 code/modules/spells/artifacts/spellbound_servants.dm delete mode 100644 code/modules/spells/artifacts/storage.dm delete mode 100644 code/modules/spells/contracts.dm delete mode 100644 code/modules/spells/general/acid_spray.dm delete mode 100644 code/modules/spells/general/area_teleport.dm delete mode 100644 code/modules/spells/general/camera_vision.dm delete mode 100644 code/modules/spells/general/contract_spells.dm delete mode 100644 code/modules/spells/general/create_air.dm delete mode 100644 code/modules/spells/general/invisibility.dm delete mode 100644 code/modules/spells/general/mark_recall.dm delete mode 100644 code/modules/spells/general/portal_teleport.dm delete mode 100644 code/modules/spells/general/radiant_aura.dm delete mode 100644 code/modules/spells/general/return_master.dm delete mode 100644 code/modules/spells/general/toggle_armor.dm delete mode 100644 code/modules/spells/hand/blood_shards.dm delete mode 100644 code/modules/spells/hand/burning_grip.dm delete mode 100644 code/modules/spells/hand/entangle.dm delete mode 100644 code/modules/spells/hand/hand.dm delete mode 100644 code/modules/spells/hand/hand_item.dm delete mode 100644 code/modules/spells/hand/slippery_surface.dm delete mode 100644 code/modules/spells/hand/sunwrath.dm delete mode 100644 code/modules/spells/no_clothes.dm delete mode 100644 code/modules/spells/racial_wizard.dm delete mode 100644 code/modules/spells/spell_projectile.dm delete mode 100644 code/modules/spells/spellbook.dm delete mode 100644 code/modules/spells/spellbook/battlemage.dm delete mode 100644 code/modules/spells/spellbook/cleric.dm delete mode 100644 code/modules/spells/spellbook/druid.dm delete mode 100644 code/modules/spells/spellbook/spatial.dm delete mode 100644 code/modules/spells/spellbook/standard.dm delete mode 100644 code/modules/spells/spellbook/student.dm delete mode 100644 code/modules/spells/targeted/analyze.dm delete mode 100644 code/modules/spells/targeted/blood_boil.dm delete mode 100644 code/modules/spells/targeted/cleric_spells.dm delete mode 100644 code/modules/spells/targeted/equip/burning_touch.dm delete mode 100644 code/modules/spells/targeted/equip/dyrnwyn.dm delete mode 100644 code/modules/spells/targeted/equip/equip.dm delete mode 100644 code/modules/spells/targeted/equip/holy_relic.dm delete mode 100644 code/modules/spells/targeted/equip/horsemask.dm delete mode 100644 code/modules/spells/targeted/equip/party_hardy.dm delete mode 100644 code/modules/spells/targeted/equip/seed.dm delete mode 100644 code/modules/spells/targeted/equip/shield.dm delete mode 100644 code/modules/spells/targeted/exude_pleasantness.dm delete mode 100644 code/modules/spells/targeted/genetic.dm delete mode 100644 code/modules/spells/targeted/glimpse_of_eternity.dm delete mode 100644 code/modules/spells/targeted/projectile/dumbfire.dm delete mode 100644 code/modules/spells/targeted/projectile/fireball.dm delete mode 100644 code/modules/spells/targeted/projectile/magic_missile.dm delete mode 100644 code/modules/spells/targeted/projectile/passage.dm delete mode 100644 code/modules/spells/targeted/projectile/projectile.dm delete mode 100644 code/modules/spells/targeted/projectile/stuncuff.dm delete mode 100644 code/modules/spells/targeted/shapeshift.dm delete mode 100644 code/modules/spells/targeted/shatter_mind.dm delete mode 100644 code/modules/spells/targeted/subjugate.dm delete mode 100644 code/modules/spells/targeted/swap.dm delete mode 100644 code/modules/spells/targeted/torment.dm delete mode 100644 maps/antag_spawn/wizard/wizard.dm delete mode 100644 maps/antag_spawn/wizard/wizard_base.dmm create mode 100644 mods/content/psionics/items/clothing.dm delete mode 100644 mods/gamemodes/cult/wizard.dm delete mode 100644 mods/species/vox/datum/antagonism.dm diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm index 9493ae7aa125..94c9d41639ae 100644 --- a/code/__defines/gamemode.dm +++ b/code/__defines/gamemode.dm @@ -33,26 +33,11 @@ #define DEFAULT_TELECRYSTAL_AMOUNT 130 #define IMPLANT_TELECRYSTAL_AMOUNT(x) (round(x * 0.49)) // If this cost is ever greater than half of DEFAULT_TELECRYSTAL_AMOUNT then it is possible to buy more TC than you spend -///////////////// -////WIZARD ////// -///////////////// +// SPELL FLAGS +#define Z2NOCAST BITFLAG(0) //if this is added, the spell can't be cast at centcomm +#define INCLUDEUSER BITFLAG(1) //does the spell include the caster in its target selection? +#define IGNOREDENSE BITFLAG(2) //are dense turfs ignored in selection? -/* WIZARD SPELL FLAGS */ -#define GHOSTCAST BITFLAG(0) //can a ghost cast it? -#define NEEDSCLOTHES BITFLAG(1) //does it need the wizard garb to cast? Nonwizard spells should not have this -#define NEEDSHUMAN BITFLAG(2) //does it require the caster to be human? -#define Z2NOCAST BITFLAG(3) //if this is added, the spell can't be cast at centcomm -#define NO_SOMATIC BITFLAG(4) //spell will go off if the person is incapacitated or stunned -#define IGNOREPREV BITFLAG(5) //if set, each new target does not overlap with the previous one -//The following flags only affect different types of spell, and therefore overlap -//Targeted spells -#define INCLUDEUSER BITFLAG(6) //does the spell include the caster in its target selection? -#define SELECTABLE BITFLAG(7) //can you select each target for the spell? -#define NOFACTION BITFLAG(8) //Don't do the same as our faction -#define NONONFACTION BITFLAG(9) //Don't do people other than our faction -//AOE spells -#define IGNOREDENSE BITFLAG(10) //are dense turfs ignored in selection? -#define IGNORESPACE BITFLAG(11) //are space turfs ignored in selection? //End split flags #define CONSTRUCT_CHECK BITFLAG(12) //used by construct spells - checks for nullrods #define NO_BUTTON BITFLAG(13) //spell won't show up in the HUD with this diff --git a/code/_onclick/hud/screen/screen_abilities.dm b/code/_onclick/hud/screen/screen_abilities.dm index 03961a964233..414458af058e 100644 --- a/code/_onclick/hud/screen/screen_abilities.dm +++ b/code/_onclick/hud/screen/screen_abilities.dm @@ -195,7 +195,6 @@ if(object) object.Click() -// Wizard /obj/screen/ability/spell var/spell/spell var/spell_base @@ -223,10 +222,7 @@ A.SetName(spell.name) if(!spell.override_base) //if it's not set, we do basic checks - if(spell.spell_flags & CONSTRUCT_CHECK) - A.spell_base = "const" //construct spells - else - A.spell_base = "wiz" //wizard spells + A.spell_base = "const" //construct spells else A.spell_base = spell.override_base A.update_charge(1) diff --git a/code/datums/config/config_types/config_mode.dm b/code/datums/config/config_types/config_mode.dm index 7db16b2ca346..975b84ebca92 100644 --- a/code/datums/config/config_types/config_mode.dm +++ b/code/datums/config/config_types/config_mode.dm @@ -6,7 +6,6 @@ /decl/config/lists/mode_allowed, /decl/config/lists/mode_votable, /decl/config/lists/mode_probabilities, - /decl/config/toggle/feature_object_spell_system, /decl/config/toggle/traitor_scaling, /decl/config/toggle/protect_roles_from_antagonist, /decl/config/toggle/continuous_rounds, @@ -78,10 +77,6 @@ var/decl/game_mode/game_mode = all_modes[mode_type] game_mode.probability = max(0, value[game_mode.uid]) -/decl/config/toggle/feature_object_spell_system - uid = "feature_object_spell_system" - desc = "Spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard." - /decl/config/toggle/traitor_scaling uid = "traitor_scaling" desc = "If amount of traitors scales or not." @@ -93,7 +88,7 @@ /decl/config/toggle/continuous_rounds uid = "continuous_rounds" desc = list( - "Remove the # to make rounds which end instantly (Rev, Wizard, Malf) to continue until the shuttle is called or the station is nuked.", + "Remove the # to make rounds which end instantly to continue until the shuttle is called or the station is nuked.", "Malf and Rev will let the shuttle be called when the antags/protags are dead." ) diff --git a/code/datums/mind/mind.dm b/code/datums/mind/mind.dm index 355cd25efdc7..377c2dced75d 100644 --- a/code/datums/mind/mind.dm +++ b/code/datums/mind/mind.dm @@ -78,7 +78,6 @@ /datum/mind/proc/handle_mob_deletion(mob/living/deleted_mob) if (current == deleted_mob) - current.spellremove() current = null if (original == deleted_mob) diff --git a/code/datums/outfits/wizardry.dm b/code/datums/outfits/wizardry.dm index a0f1a5881950..b3da295036d5 100644 --- a/code/datums/outfits/wizardry.dm +++ b/code/datums/outfits/wizardry.dm @@ -2,10 +2,8 @@ uniform = /obj/item/clothing/jumpsuit/lightpurple shoes = /obj/item/clothing/shoes/sandal l_ear = /obj/item/radio/headset - r_pocket = /obj/item/paper/scroll/teleportation hands = list( - /obj/item/staff/crystal, - /obj/item/book/spell + /obj/item/staff/crystal ) back = /obj/item/backpack backpack_contents = list(/obj/item/box = 1) @@ -26,4 +24,4 @@ name = "Wizard - Marisa" head = /obj/item/clothing/head/wizard/marisa suit = /obj/item/clothing/suit/wizrobe/marisa - shoes = /obj/item/clothing/shoes/sandal/marisa + shoes = /obj/item/clothing/shoes/sandal/marisa \ No newline at end of file diff --git a/code/datums/supplypacks/nonessent.dm b/code/datums/supplypacks/nonessent.dm index 6575ca30fd0c..cee09fc29b68 100644 --- a/code/datums/supplypacks/nonessent.dm +++ b/code/datums/supplypacks/nonessent.dm @@ -74,9 +74,9 @@ /decl/hierarchy/supply_pack/nonessent/wizard name = "Costume - Wizard" contains = list(/obj/item/staff/crystal, - /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/suit/wizrobe, /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/fake) + /obj/item/clothing/head/wizard/beard) containername = "wizard costume crate" /decl/hierarchy/supply_pack/nonessent/costume @@ -170,9 +170,9 @@ /decl/hierarchy/supply_pack/nonessent/witch name = "Costume - Witch" - contains = list(/obj/item/clothing/suit/wizrobe/marisa/fake, + contains = list(/obj/item/clothing/suit/wizrobe/marisa, /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/marisa/fake, + /obj/item/clothing/head/wizard/marisa, /obj/item/staff/broom) containername = "witch costume crate" containertype = /obj/structure/closet diff --git a/code/datums/trading/traders/ai.dm b/code/datums/trading/traders/ai.dm index ca86637d32d7..05b15422e1d8 100644 --- a/code/datums/trading/traders/ai.dm +++ b/code/datums/trading/traders/ai.dm @@ -37,7 +37,6 @@ They sell generic supplies and ask for generic supplies. ) possible_trading_items = list( /obj/item/bag = TRADER_SUBTYPES_ONLY, - /obj/item/bag/cash/infinite = TRADER_BLACKLIST, /obj/item/backpack = TRADER_ALL, /obj/item/backpack/cultpack = TRADER_BLACKLIST, /obj/item/backpack/holding = TRADER_BLACKLIST, diff --git a/code/datums/trading/traders/goods.dm b/code/datums/trading/traders/goods.dm index d260685de193..81d294268dcd 100644 --- a/code/datums/trading/traders/goods.dm +++ b/code/datums/trading/traders/goods.dm @@ -47,7 +47,6 @@ /obj/item/deck = TRADER_SUBTYPES_ONLY, /obj/item/pack = TRADER_SUBTYPES_ONLY, /obj/item/dice = TRADER_ALL, - /obj/item/dice/d20/cursed = TRADER_BLACKLIST, /obj/item/gun/launcher/money = TRADER_THIS_TYPE ) diff --git a/code/datums/trading/traders/misc.dm b/code/datums/trading/traders/misc.dm index 4366e0fede48..dd3e0df898f1 100644 --- a/code/datums/trading/traders/misc.dm +++ b/code/datums/trading/traders/misc.dm @@ -167,8 +167,8 @@ /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE, /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE, /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE, - /obj/item/clothing/suit/wizrobe/magusred = TRADER_THIS_TYPE, - /obj/item/clothing/suit/wizrobe/magusblue = TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magus = TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magus/red = TRADER_THIS_TYPE, /obj/item/clothing/costume/gladiator = TRADER_THIS_TYPE, /obj/item/clothing/costume/kilt = TRADER_THIS_TYPE, /obj/item/clothing/costume/redcoat = TRADER_THIS_TYPE, diff --git a/code/datums/trading/traders/unique.dm b/code/datums/trading/traders/unique.dm index d5c98f8e392d..e71995049218 100644 --- a/code/datums/trading/traders/unique.dm +++ b/code/datums/trading/traders/unique.dm @@ -90,51 +90,3 @@ TRADER_BRIBE_ACCEPT = "Blub will stay for " + TRADER_TOKEN_TIME + " binutes bonger.", TRADER_BRIBE_REFUSAL = "Blub must go. Blub's beople beed blem." ) - -//probably could stick soem Howl references in here but like, eh. Haven't seen it in years. -/datum/trader/ship/unique/wizard - name = "Sorcerer" - origin = "A moving castle" - possible_origins = list( - "An indistinct location", - "Unknown location", - "The Diamond Sphere", - "Beyond the Veil", - "Deadverse" - ) - - possible_wanted_items = list( - /mob/living/simple_animal/familiar = TRADER_SUBTYPES_ONLY, - /mob/living/simple_animal/familiar/pet = TRADER_BLACKLIST, - /mob/living/simple_animal/hostile/mimic = TRADER_ALL - ) - possible_trading_items = list( - /obj/item/clothing/gloves/wizard = TRADER_THIS_TYPE, - /obj/item/clothing/head/helmet/space/void/wizard = TRADER_THIS_TYPE, - /obj/item/clothing/head/wizard = TRADER_ALL, - /obj/item/clothing/suit/space/void/wizard = TRADER_THIS_TYPE, - /obj/item/toy/figure/wizard = TRADER_THIS_TYPE, - /obj/item/staff = TRADER_ALL, - ) //Probably see about getting some more wizard based shit - - speech = list( - TRADER_HAIL_GENERIC = "Hello! Are you here on pleasure or business?", - TRADER_HAIL_DENY = "I'm sorry, but I REALLY don't want to speak to you.", - TRADER_TRADE_COMPLETE = "Pleasure doing business with you!", - TRADER_NO_MONEY = "Cash? Ha! What's cash to a man like me?", - TRADER_NOT_ENOUGH = "Hm, well I do enjoy what you're offering, I prefer a fair trade.", - TRADER_FOUND_UNWANTED = "What? I want oddities! Don't you understand?", - TRADER_HOW_MUCH = "I want dark things, brooding things... things that go bump in the night. Things that bleed wrong, live wrong, are wrong.", - TRADER_WHAT_WANT = "Have anything from a broodish cult?", - TRADER_COMPLIMENT_DENY = "Like I haven't heard that one before!", - TRADER_COMPLIMENT_ACCEPT = "Haha! Aren't you nice.", - TRADER_INSULT_GOOD = "Naughty naughty.", - TRADER_INSULT_BAD = "Now where do you get off talking to me like that?", - TRADER_BRIBE_ACCEPT = "Well, if you're not pulling the knob on my staff, I can stay for another " + TRADER_TOKEN_TIME + " minutes.", - TRADER_BRIBE_REFUSAL = "A wizard does not depart early or late, but precisely when they intend to. No.", - TRADER_NO_BLACKLISTED = "I cannot accept such a thing. No trade." - ) - -/datum/trader/ship/unique/wizard/New() - speech[TRADER_HAIL_START + SPECIES_GOLEM] = "Interesting... how incredibly interesting... come! Let us do business!" - ..() diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm deleted file mode 100644 index 9aa819de8431..000000000000 --- a/code/game/antagonist/outsider/wizard.dm +++ /dev/null @@ -1,115 +0,0 @@ -/decl/special_role/wizard - name = "Wizard" - name_plural = "Wizards" - landmark_id = "wizard" - welcome_text = "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.
In your pockets you will find a teleport scroll. Use it as needed." - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE - antaghud_indicator = "hudwizard" - default_access = list(access_wizard) - hard_cap = 1 - hard_cap_round = 3 - initial_spawn_req = 1 - initial_spawn_target = 1 - min_player_age = 18 - - faction = "wizard" - base_to_load = "Wizard Base" - -/decl/special_role/wizard/create_objectives(var/datum/mind/wizard) - - if(!..()) - return - - var/kill - var/escape - var/steal - var/hijack - - switch(rand(1,100)) - if(1 to 30) - escape = 1 - kill = 1 - if(31 to 60) - escape = 1 - steal = 1 - if(61 to 99) - kill = 1 - steal = 1 - else - hijack = 1 - - if(kill) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = wizard - kill_objective.find_target() - wizard.objectives |= kill_objective - if(steal) - var/datum/objective/steal/steal_objective = new - steal_objective.owner = wizard - steal_objective.find_target() - wizard.objectives |= steal_objective - if(escape) - var/datum/objective/survive/survive_objective = new - survive_objective.owner = wizard - wizard.objectives |= survive_objective - if(hijack) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = wizard - wizard.objectives |= hijack_objective - return - -/decl/special_role/wizard/update_antag_mob(var/datum/mind/wizard) - ..() - wizard.StoreMemory("Remember: do not forget to prepare your spells.", /decl/memory_options/system) - wizard.current.real_name = "[pick(global.wizard_first)] [pick(global.wizard_second)]" - wizard.current.SetName(wizard.current.real_name) - -/decl/special_role/wizard/equip_role(var/mob/living/human/wizard_mob) - default_outfit = pick(decls_repository.get_decl_paths_of_subtype(/decl/outfit/wizard)) - . = ..() - -/decl/special_role/wizard/print_player_summary() - ..() - for(var/p in current_antagonists) - var/datum/mind/player = p - var/text = "[player.name]'s spells were:" - if(!player.learned_spells || !player.learned_spells.len) - text += "
None!" - else - for(var/s in player.learned_spells) - var/spell/spell = s - text += "
[spell.name] - " - text += "Speed: [spell.spell_levels["speed"]] Power: [spell.spell_levels["power"]]" - text += "
" - to_world(text) - - -//To batch-remove wizard spells. Linked to mind.dm. -/mob/proc/spellremove() - if(!mind || !mind.learned_spells) - return - for(var/spell/spell_to_remove in mind.learned_spells) - remove_spell(spell_to_remove) - -// Does this clothing slot count as wizard garb? (Combines a few checks) -/proc/is_wiz_garb(var/obj/item/clothing/C) - return istype(C) && C.wizard_garb - -/*Checks if the wizard is wearing the proper attire. -Made a proc so this is not repeated 14 (or more) times.*/ -/mob/proc/wearing_wiz_garb() - to_chat(src, "Silly creature, you're not a human. Only humans can cast this spell.") - return 0 - -// Humans can wear clothes. -/mob/living/human/wearing_wiz_garb() - if(!is_wiz_garb(get_equipped_item(slot_wear_suit_str)) && (!istype(species.species_hud) || (slot_wear_suit_str in species.species_hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my robe.") - return 0 - if(!is_wiz_garb(get_equipped_item(slot_shoes_str)) && (!istype(species.species_hud) || (slot_shoes_str in species.species_hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my sandals.") - return 0 - if(!is_wiz_garb(get_equipped_item(slot_head_str)) && (!istype(species.species_hud) || (slot_head_str in species.species_hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my hat.") - return 0 - return 1 diff --git a/code/game/gamemodes/wizard/servant_items/caretaker.dm b/code/game/gamemodes/wizard/servant_items/caretaker.dm deleted file mode 100644 index c5adb272efec..000000000000 --- a/code/game/gamemodes/wizard/servant_items/caretaker.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/item/clothing/head/caretakerhood - name = "holy hood" - desc = "The hood of a shining white robe, with blue trim. Who would possess this robe and still want to hide themself away?" - icon = 'icons/clothing/head/caretaker.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_KNIVES, - ARMOR_BULLET = ARMOR_BALLISTIC_MINOR, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_RAD = ARMOR_RAD_SHIELDED - ) - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - flags_inv = HIDEEARS | BLOCK_HEAD_HAIR - -/obj/item/clothing/suit/caretakercloak - name = "holy cloak" - desc = "A shining white and blue robe. For some reason, it reminds you of the holidays." - icon = 'icons/clothing/suits/wizard/servant/caretaker.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, - ARMOR_RAD = ARMOR_RAD_SHIELDED - ) - -/obj/item/clothing/shoes/dress/caretakershoes - name = "black leather shoes" - desc = "Dress shoes. These aren't as shiny as usual." - inset_color = COLOR_SKY_BLUE - shine = 30 - armor = list( - ARMOR_RAD = ARMOR_RAD_SHIELDED - ) \ No newline at end of file diff --git a/code/game/gamemodes/wizard/servant_items/champion.dm b/code/game/gamemodes/wizard/servant_items/champion.dm deleted file mode 100644 index 80e04ee1bfdc..000000000000 --- a/code/game/gamemodes/wizard/servant_items/champion.dm +++ /dev/null @@ -1,85 +0,0 @@ -/obj/item/clothing/head/champhelm - name = "champion's crown" - desc = "A spiky, golden crown. It's probably worth more than your bank account." - - icon = 'icons/clothing/head/champion.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, - ARMOR_BULLET = ARMOR_BALLISTIC_AP, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_RESISTANT, - ARMOR_BIO = ARMOR_BIO_MINOR - ) - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - -/obj/item/clothing/suit/champarmor - name = "champion's armor" - desc = "A mighty suit of silver and gold armor, with a gleaming blue crystal inlaid into its left gaunlet." - icon = 'icons/clothing/suits/wizard/servant/champion.dmi' - siemens_coefficient = 0.5 - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL - armor = list( - ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, - ARMOR_BULLET = ARMOR_BALLISTIC_AP, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_RESISTANT, - ARMOR_BIO = ARMOR_BIO_MINOR - ) - -/obj/item/clothing/pants/champion - name = "champion's garb" - desc = "Some dark, archaic leggings." - icon = 'icons/clothing/pants/leggings/leggings_champion.dmi' - siemens_coefficient = 0.8 - armor = list( - ARMOR_MELEE = ARMOR_MELEE_MINOR - ) - starting_accessories = list( - /obj/item/clothing/shirt/tunic/blue/champion - ) - -/obj/item/clothing/shoes/jackboots/medievalboots - name = "leather boots" - desc = "Old-fashioned leather boots. Probably not something you want to get kicked with." - material = /decl/material/solid/organic/leather - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_MINOR, - ARMOR_LASER = ARMOR_LASER_MINOR, - ARMOR_ENERGY = ARMOR_ENERGY_MINOR, - ARMOR_BOMB = ARMOR_BOMB_PADDED - ) - artificail_shine = 0 - -/obj/item/sword/excalibur - name = "champion's blade" - desc = "For at his belt hung Excalibur, the finest sword that there was, which sliced through iron as through wood." - icon = 'icons/obj/items/weapon/swords/excalibur.dmi' - attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cleaved", "sundered") - material_alteration = MAT_FLAG_ALTERATION_NONE - -/obj/item/sword/excalibur/on_picked_up(var/mob/living/user) - if(user.mind) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if(!wizards.is_antagonist(user.mind) || user.mind.assigned_special_role != "Spellbound Servant") - START_PROCESSING(SSobj, src) - to_chat(user,"\The [src] heats up in your hands, burning you!") - -/obj/item/sword/excalibur/Process() - if(isliving(loc)) - if(ishuman(loc)) - var/mob/living/human/H = loc - var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, H.get_active_held_item_slot()) - E?.take_external_damage(burn=2,used_weapon="stovetop") - else - var/mob/living/M = loc - M.take_damage(2, BURN) - if(prob(2)) - to_chat(loc,"\The [src] is burning you!") - return 1 - -/obj/item/sword/excalibur/dropped() - . = ..() - STOP_PROCESSING(SSobj, src) \ No newline at end of file diff --git a/code/game/gamemodes/wizard/servant_items/familiar.dm b/code/game/gamemodes/wizard/servant_items/familiar.dm deleted file mode 100644 index 05cc8cdf9610..000000000000 --- a/code/game/gamemodes/wizard/servant_items/familiar.dm +++ /dev/null @@ -1,15 +0,0 @@ -/obj/item/clothing/head/bandana/familiarband - name = "familiar's headband" - desc = "It's a simple headband made of leather." - icon = 'icons/clothing/head/familiar.dmi' - -/obj/item/clothing/pants/familiar - name = "familiar's garb" - desc = "Some rough leather leggings, reinforced here and there. A hasty job." - starting_accessories = list( - /obj/item/clothing/shirt/tunic/green/familiar - ) - -/obj/item/clothing/pants/familiar/Initialize() - . = ..() - LAZYSET(slowdown_per_slot, slot_w_uniform_str, -3) diff --git a/code/game/gamemodes/wizard/servant_items/fiend.dm b/code/game/gamemodes/wizard/servant_items/fiend.dm deleted file mode 100644 index e52606eb62f8..000000000000 --- a/code/game/gamemodes/wizard/servant_items/fiend.dm +++ /dev/null @@ -1,49 +0,0 @@ -/obj/item/clothing/head/fiendhood - name = "fiend's hood" - desc = "A dark hood with blood-red trim. Something about the fabric blocks more light than it should." - icon = 'icons/clothing/head/fiend_hood.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_KNIVES, - ARMOR_BULLET = ARMOR_BALLISTIC_MINOR, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_RAD = ARMOR_RAD_SHIELDED - ) - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - flags_inv = HIDEEARS | BLOCK_HEAD_HAIR - -/obj/item/clothing/suit/fiendcowl - name = "fiend's cowl" - desc = "A charred black duster with red trim. In its fabric, you can see the faint outline of millions of eyes." - icon = 'icons/clothing/suits/wizard/servant/fiend_cowl.dmi' - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS|SLOT_TAIL - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_HANDGUNS, - ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, - ARMOR_RAD = ARMOR_RAD_SHIELDED - ) - -/obj/item/clothing/costume/fiendsuit - name = "black suit" - desc = "A snappy black suit with red trim. The undershirt's stained with something, though..." - icon = 'icons/clothing/suits/suit_fiend.dmi' - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - -/obj/item/clothing/shoes/dress/devilshoes - desc = "Off-colour leather dress shoes. Their footsteps are silent." - inset_color = COLOR_MAROON - item_flags = ITEM_FLAG_SILENT - color = "#2e1e1e" - -/obj/item/clothing/head/fiendhood/fem - name = "fiend's visage" - desc = "To gaze upon this is to gaze into an inferno. Look away, before it looks back of its own accord." - icon = 'icons/clothing/head/fiend_visage.dmi' - flags_inv = HIDEEARS | BLOCK_ALL_HAIR - -/obj/item/clothing/suit/fiendcowl/fem - name = "fiend's robe" - icon = 'icons/clothing/suits/wizard/servant/fiend_robe.dmi' - desc = "A tattered, black and red robe. Nothing is visible through the holes in its fabric, except for a strange, inky blackness. It looks as if it was stitched together with other clothing..." diff --git a/code/game/gamemodes/wizard/servant_items/infiltrator.dm b/code/game/gamemodes/wizard/servant_items/infiltrator.dm deleted file mode 100644 index 846addc5b7c3..000000000000 --- a/code/game/gamemodes/wizard/servant_items/infiltrator.dm +++ /dev/null @@ -1,42 +0,0 @@ -/obj/item/clothing/head/infilhat - name = "immaculate fedora" - desc = "Whoever owns this hat means business. Hopefully, it's just good business." - color = COLOR_SILVER - icon = 'icons/clothing/head/detective.dmi' - markings_state_modifier = "band" - markings_color = COLOR_DARK_GRAY - armor = list( - ARMOR_MELEE = ARMOR_MELEE_MINOR, - ARMOR_BULLET = ARMOR_BALLISTIC_MINOR, - ARMOR_LASER = ARMOR_LASER_MINOR, - ARMOR_ENERGY = ARMOR_ENERGY_MINOR - ) - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - -/obj/item/clothing/suit/infilsuit - name = "immaculate suit" - desc = "The clothes of an impeccable diplomat. Or perhaps a businessman. Let's not consider the horrors that might arise if it belongs to a lawyer." - icon = 'icons/clothing/suits/wizard/servant/inf_suit.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_MINOR, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_MINOR, - ARMOR_ENERGY = ARMOR_ENERGY_MINOR - ) - -/obj/item/clothing/shoes/dress/infilshoes - name = "black leather shoes" - desc = "Dress shoes. Their footsteps are dead silent." - inset_color = COLOR_INDIGO - item_flags = ITEM_FLAG_SILENT - -/obj/item/clothing/head/infilhat/fem - name = "maid's headband" - desc = "This dainty, frilled thing is apparently meant to go on your head." - icon = 'icons/clothing/head/inf_hat.dmi' - markings_state_modifier = null - -/obj/item/clothing/suit/infilsuit/fem - name = "maid's uniform" - desc = "The uniform of someone you'd expect to see dusting off the Antique Gun's display case." - icon = 'icons/clothing/suits/wizard/servant/inf_dress.dmi' diff --git a/code/game/gamemodes/wizard/servant_items/overseer.dm b/code/game/gamemodes/wizard/servant_items/overseer.dm deleted file mode 100644 index f8676e0440d6..000000000000 --- a/code/game/gamemodes/wizard/servant_items/overseer.dm +++ /dev/null @@ -1,40 +0,0 @@ -/obj/item/clothing/head/overseerhood - name = "grim hood" - desc = "Darker than dark. What... what is this made of?" - armor = list( - ARMOR_MELEE = ARMOR_MELEE_SHIELDED, - ARMOR_BULLET = ARMOR_BALLISTIC_HEAVY, - ARMOR_LASER = ARMOR_LASER_HEAVY, - ARMOR_ENERGY = ARMOR_ENERGY_SHIELDED, - ARMOR_BOMB = ARMOR_BOMB_SHIELDED - ) - icon = 'icons/clothing/head/necromancer.dmi' - item_flags = ITEM_FLAG_AIRTIGHT - max_pressure_protection = FIRESUIT_MAX_PRESSURE - min_pressure_protection = 0 - bodytype_equip_flags = BODY_EQUIP_FLAG_HUMANOID - flags_inv = HIDEEARS | BLOCK_HEAD_HAIR - -/obj/item/clothing/suit/straight_jacket/overseercloak - name = "grim cloak" - desc = "The void of space woven into fabric. It's hard to tell where its edges are." - icon = 'icons/clothing/suits/wizard/servant/overseer.dmi' - armor = list( - ARMOR_MELEE = ARMOR_MELEE_SHIELDED, - ARMOR_BULLET = ARMOR_BALLISTIC_HEAVY, - ARMOR_LASER = ARMOR_LASER_HEAVY, - ARMOR_ENERGY = ARMOR_ENERGY_SHIELDED, - ARMOR_BOMB = ARMOR_BOMB_SHIELDED - ) - item_flags = ITEM_FLAG_AIRTIGHT - max_pressure_protection = FIRESUIT_MAX_PRESSURE - min_pressure_protection = 0 - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL - -//These are the ones that it gets when they toggle it off -/obj/item/clothing/shoes/sandal/grimboots - name = "stained boots" - desc = "These boots are stained with blood so dry that it's turned black..." - color = COLOR_BLACK - shine = 10 - item_flags = ITEM_FLAG_SILENT \ No newline at end of file diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm deleted file mode 100644 index 72792403db14..000000000000 --- a/code/game/gamemodes/wizard/wizard.dm +++ /dev/null @@ -1,10 +0,0 @@ -/decl/game_mode/wizard - name = "Wizard" - round_description = "There is a SPACE WIZARD onboard. You can't let the magician achieve their objectives!" - extended_round_description = "A powerful space wizard has made their way on board. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows devastation." - uid = "wizard" - required_players = 5 - required_enemies = 1 - end_on_antag_death = FALSE - associated_antags = list(/decl/special_role/wizard) - probability = 1 diff --git a/code/game/gamemodes/wizard/wizard_props.dm b/code/game/gamemodes/wizard/wizard_props.dm deleted file mode 100644 index b8b834679db1..000000000000 --- a/code/game/gamemodes/wizard/wizard_props.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/structure/talisman_altar - name = "Altar" - desc = "A bloodstained altar dedicated to the worship of some unknown dark entity." - icon = 'icons/obj/cult.dmi' - icon_state = "talismanaltar" - density = TRUE - anchored = TRUE - -/obj/structure/fake_pylon - name = "\improper Pylon" - desc = "A floating crystal that hums with an unearthly energy." - icon = 'icons/obj/structures/pylon.dmi' - icon_state = "pylon" - light_power = 0.5 - light_range = 13 - light_color = "#3e0000" - -// A de-culted version of the cult gateway, for the wizard base map. -/obj/effect/gateway/active/spooky - light_range=5 - light_color="#ff0000" \ No newline at end of file diff --git a/code/game/jobs/access_datum.dm b/code/game/jobs/access_datum.dm index 979f91bd0349..0d6369221804 100644 --- a/code/game/jobs/access_datum.dm +++ b/code/game/jobs/access_datum.dm @@ -460,12 +460,6 @@ var/global/const/access_mercenary = "ACCESS_MERCENARY" desc = "Mercenary" access_type = ACCESS_TYPE_ANTAG -var/global/const/access_wizard = "ACCESS_WIZARD" -/datum/access/wizard - id = access_wizard - desc = "Wizard" - access_type = ACCESS_TYPE_ANTAG - /******* * Misc * *******/ diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 7d695e1f75d0..e2e87ae2470e 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -132,18 +132,18 @@ /obj/abstract/landmark/costume/holiday_priest/make_costumes() new /obj/item/clothing/suit/holidaypriest(loc) -/obj/abstract/landmark/costume/marisawizard/fake/make_costumes() - new /obj/item/clothing/head/wizard/marisa/fake(loc) - new/obj/item/clothing/suit/wizrobe/marisa/fake(loc) +/obj/abstract/landmark/costume/marisawizard/make_costumes() + new /obj/item/clothing/head/wizard/marisa(loc) + new/obj/item/clothing/suit/wizrobe/marisa(loc) /obj/abstract/landmark/costume/cutewitch/make_costumes() new /obj/item/clothing/dress/sun(loc) new /obj/item/clothing/head/witchwig(loc) new /obj/item/staff/broom(loc) -/obj/abstract/landmark/costume/fakewizard/make_costumes() - new /obj/item/clothing/suit/wizrobe/fake(loc) - new /obj/item/clothing/head/wizard/fake(loc) +/obj/abstract/landmark/costume/wizard/make_costumes() + new /obj/item/clothing/suit/wizrobe(loc) + new /obj/item/clothing/head/wizard/beard(loc) new /obj/item/staff/(loc) /obj/abstract/landmark/costume/sexyclown/make_costumes() diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 882706ebc6f8..0726d380a410 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -25,10 +25,6 @@ START_PROCESSING(SSobj, src) update_icon() -/obj/item/radio/intercom/wizard - name = "enchanted intercom" - desc = "Talk into this while you ponder your orb." - /obj/item/radio/intercom/raider name = "piratical intercom" desc = "Pirate radio, but not in the usual sense of the word." diff --git a/code/game/objects/items/hourglass.dm b/code/game/objects/items/hourglass.dm index f12a51077f56..98bb75f12811 100644 --- a/code/game/objects/items/hourglass.dm +++ b/code/game/objects/items/hourglass.dm @@ -1,7 +1,5 @@ -// I considered just putting this in the fantasy modpack, -// but it's probably better in core code, since at the very least -// the Wizard gamemode might want to use the item or icon for something. -// Also, I think it could just be a neat prop. +// I considered just putting this in the fantasy modpack, but +// it's probably better in core code, since it's a nice prop. /obj/item/hourglass name = "hourglass" icon = 'icons/obj/items/hourglass.dmi' diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm deleted file mode 100644 index 0b513dc546ac..000000000000 --- a/code/game/objects/items/weapons/scrolls.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/item/paper/scroll/teleportation - name = "scroll of teleportation" - desc = "A scroll for moving around." - origin_tech = @'{"wormholes":4}' - info = {" - Teleportation Scroll:
-
- Comes with four charges! Use them wisely.
- Kind regards,
Wizards Federation

P.S. Don't forget to bring your gear, you'll need it to cast most spells. - "} - var/uses = 4 - -/obj/item/paper/scroll/teleportation/examine(mob/user, distance) - . = ..() - if(distance <= 1) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if(wizards.is_antagonist(user.mind)) - to_chat(user, SPAN_NOTICE("\The [src] has [uses] charge\s remaining.")) - -/obj/item/paper/scroll/teleportation/attack_self(mob/user) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if((user.mind && !wizards.is_antagonist(user.mind))) - to_chat(user, SPAN_WARNING("You stare at \the [src], but cannot make sense of the markings!")) - return TRUE - if(alert(user, "Do you wish to teleport using \the [src]? It has [uses] charge\s remaining.", "Scroll of Teleportation", "No", "Yes") == "Yes") - teleportscroll(user) - return TRUE - -/obj/item/paper/scroll/teleportation/proc/teleportscroll(var/mob/user) - if(uses <= 0) - return - - var/area/thearea = input(user, "Select an area to jump to.", "Scroll of Teleportation") as null|anything in wizteleportlocs - if(!thearea || QDELETED(src) || QDELETED(user) || user.get_active_held_item() != src || CanUseTopic(user) != STATUS_INTERACTIVE) - return - - thearea = thearea ? wizteleportlocs[thearea] : thearea - if(!thearea) - return - - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(5, 0, user.loc) - smoke.attach(user) - smoke.start() - var/turf/end = user.try_teleport(thearea) - if(!end) - to_chat(user, SPAN_WARNING("The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry!")) - return - smoke.start() - src.uses -= 1 diff --git a/code/game/objects/items/weapons/staff.dm b/code/game/objects/items/weapons/staff.dm index 41ce83c34304..f355815734bd 100644 --- a/code/game/objects/items/weapons/staff.dm +++ b/code/game/objects/items/weapons/staff.dm @@ -42,9 +42,8 @@ return TRUE return ..() -// TODO: move back into wizard modpack when the timelines converge. /obj/item/staff/crystal - name = "wizard's staff" + name = "crystal staff" icon = 'icons/obj/items/staff_crystal.dmi' /obj/item/staff/crystal/can_make_broom_with(mob/user, obj/item/thing) diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm index 4c2a1259995f..744bcdb78135 100644 --- a/code/modules/clothing/_clothing.dm +++ b/code/modules/clothing/_clothing.dm @@ -9,7 +9,6 @@ icon_state = ICON_STATE_WORLD _base_attack_force = 3 - var/wizard_garb = 0 var/flash_protection = FLASH_PROTECTION_NONE // Sets the item's level of flash protection. var/tint = TINT_NONE // Sets the item's level of visual impairment tint. var/bodytype_equip_flags // Bitfields; if null, checking is skipped. Determine if a given mob can equip this item or not. diff --git a/code/modules/clothing/head/wizard.dm b/code/modules/clothing/head/wizard.dm new file mode 100644 index 000000000000..e4de99269e10 --- /dev/null +++ b/code/modules/clothing/head/wizard.dm @@ -0,0 +1,32 @@ +// Props from wizard mode, preserved as costume pieces. +/obj/item/clothing/head/wizard + name = "wizard hat" + desc = "It has WIZZARD written across it in sequins." + icon = 'icons/clothing/head/wizard/wizard.dmi' + body_parts_covered = 0 + +/obj/item/clothing/head/wizard/red + name = "red wizard hat" + icon = 'icons/clothing/head/wizard/red.dmi' + +/obj/item/clothing/head/wizard/beard + name = "wizard hat" + desc = "It has WIZZARD written across it in sequins. Comes with a cool beard." + icon = 'icons/clothing/head/wizard/fake.dmi' + body_parts_covered = SLOT_HEAD|SLOT_FACE + +/obj/item/clothing/head/wizard/marisa + name = "witch hat" + desc = "Strange-looking hat-wear. Makes you want to cast fireballs." + icon = 'icons/clothing/head/wizard/marisa.dmi' + +/obj/item/clothing/head/wizard/magus + name = "magus helm" + desc = "A mysterious helmet. Hard to see out of." + icon = 'icons/clothing/head/wizard/magus.dmi' + body_parts_covered = SLOT_HEAD|SLOT_FACE|SLOT_EYES + +/obj/item/clothing/head/wizard/cap + name = "gentleman's cap" + desc = "A checkered gray flat cap." + icon = 'icons/clothing/head/flatcap.dmi' diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index e74903d380b7..7ceb955904cb 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -93,12 +93,16 @@ w_class = ITEM_SIZE_SMALL siemens_coefficient = 0.9 -/obj/item/clothing/mask/horsehead/Initialize() - . = ..() - // The horse mask doesn't cause voice changes by default, the wizard spell changes the flag as necessary +/obj/item/clothing/mask/horsehead/cursed + voicechange = TRUE say_messages = list("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") say_verbs = list("whinnies", "neighs", "says") +/obj/item/clothing/mask/horsehead/cursed/equipped(mob/user, slot) + . = ..() + if(slot == slot_wear_mask_str) + canremove = FALSE + /obj/item/clothing/mask/ai name = "camera MIU" desc = "Allows for direct mental connection to accessible camera channels." diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 9466eb0709aa..53579e0dd79a 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -84,7 +84,6 @@ icon = 'icons/clothing/feet/sandals.dmi' bodytype_equip_flags = null body_parts_covered = 0 - wizard_garb = 1 can_add_hidden_item = FALSE can_add_cuffs = FALSE diff --git a/code/modules/clothing/spacesuits/void/wizard.dm b/code/modules/clothing/spacesuits/void/wizard.dm deleted file mode 100644 index 48dfc6d852a3..000000000000 --- a/code/modules/clothing/spacesuits/void/wizard.dm +++ /dev/null @@ -1,66 +0,0 @@ -//Wizard Rig -/obj/item/clothing/head/helmet/space/void/wizard - name = "gem-encrusted voidsuit helmet" - desc = "A bizarre gem-encrusted helmet that radiates magical energies." - icon = 'icons/clothing/spacesuit/void/wizard/helmet.dmi' - material = /decl/material/solid/gemstone/crystal - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_SHIELDED, - ARMOR_RAD = ARMOR_RAD_SMALL - ) - siemens_coefficient = 0.7 - wizard_garb = 1 - -/obj/item/clothing/suit/space/void/wizard - name = "gem-encrusted voidsuit" - desc = "A bizarre gem-encrusted suit that radiates magical energies." - icon = 'icons/clothing/spacesuit/void/wizard/suit.dmi' - w_class = ITEM_SIZE_LARGE //normally voidsuits are bulky but this one is magic I suppose - material = /decl/material/solid/gemstone/crystal - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_SHIELDED, - ARMOR_RAD = ARMOR_RAD_SMALL - ) - siemens_coefficient = 0.7 - wizard_garb = 1 - flags_inv = HIDESHOES|HIDEJUMPSUIT|HIDETAIL //For gloves. - body_parts_covered = SLOT_UPPER_BODY | SLOT_LOWER_BODY | SLOT_LEGS | SLOT_FEET | SLOT_ARMS | SLOT_TAIL - cold_protection = SLOT_UPPER_BODY | SLOT_LOWER_BODY | SLOT_LEGS | SLOT_FEET | SLOT_ARMS | SLOT_TAIL - -/obj/item/clothing/suit/space/void/wizard/Initialize() - . = ..() - LAZYSET(slowdown_per_slot, slot_wear_suit_str, 1) - -/obj/item/clothing/gloves/wizard - name = "mystical gloves" - desc = "Reinforced, gem-studded gloves that radiate energy. They look like they go along with a matching voidsuit." - color = COLOR_VIOLET - item_flags = ITEM_FLAG_THICKMATERIAL - body_parts_covered = SLOT_HANDS - cold_protection = SLOT_HANDS - min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE - bodytype_equip_flags = null - gender = PLURAL - gas_transfer_coefficient = 0.01 - permeability_coefficient = 0.02 - material = /decl/material/solid/gemstone/crystal - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_SHIELDED, - ARMOR_RAD = ARMOR_RAD_SMALL - ) - siemens_coefficient = 0.7 diff --git a/code/modules/clothing/suits/misc.dm b/code/modules/clothing/suits/misc.dm new file mode 100644 index 000000000000..eb58d81b67eb --- /dev/null +++ b/code/modules/clothing/suits/misc.dm @@ -0,0 +1,5 @@ +/obj/item/clothing/suit/gentlecoat + name = "gentleman's coat" + desc = "A heavy-threaded gray tweed jacket." + icon = 'icons/clothing/suits/wizard/gentleman.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm deleted file mode 100644 index 16dd6386ebb9..000000000000 --- a/code/modules/clothing/suits/wiz_robe.dm +++ /dev/null @@ -1,113 +0,0 @@ -/obj/item/clothing/head/wizard - name = "wizard hat" - desc = "Strange-looking hat-wear that most certainly belongs to a real magic user." - icon = 'icons/clothing/head/wizard/wizard.dmi' - //Not given any special protective value since the magic robes are full-body protection --NEO - siemens_coefficient = 0.8 - body_parts_covered = 0 - wizard_garb = 1 - -/obj/item/clothing/head/wizard/red - name = "red wizard hat" - desc = "Strange-looking, red, hat-wear that most certainly belongs to a real magic user." - icon = 'icons/clothing/head/wizard/red.dmi' - siemens_coefficient = 0.8 - -/obj/item/clothing/head/wizard/fake - name = "wizard hat" - desc = "It has WIZZARD written across it in sequins. Comes with a cool beard." - icon = 'icons/clothing/head/wizard/fake.dmi' - body_parts_covered = SLOT_HEAD|SLOT_FACE - -/obj/item/clothing/head/wizard/marisa - name = "witch hat" - desc = "Strange-looking hat-wear, makes you want to cast fireballs." - icon = 'icons/clothing/head/wizard/marisa.dmi' - siemens_coefficient = 0.8 - -/obj/item/clothing/head/wizard/magus - name = "magus helm" - desc = "A mysterious helmet that hums with an unearthly power." - icon = 'icons/clothing/head/wizard/magus.dmi' - siemens_coefficient = 0.8 - body_parts_covered = SLOT_HEAD|SLOT_FACE|SLOT_EYES - -/obj/item/clothing/head/wizard/cap - name = "gentleman's cap" - desc = "A checkered gray flat cap woven together with the rarest of threads." - icon = 'icons/clothing/head/flatcap.dmi' - siemens_coefficient = 0.8 - -/obj/item/clothing/suit/wizrobe - name = "wizard robe" - desc = "A magnificant, gem-lined robe that seems to radiate power." - icon = 'icons/clothing/suits/wizard/wizard.dmi' - gas_transfer_coefficient = 0.01 // IT'S MAGICAL OKAY JEEZ +1 TO NOT DIE - permeability_coefficient = 0.01 - armor = list( - ARMOR_MELEE = ARMOR_MELEE_RESISTANT, - ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, - ARMOR_LASER = ARMOR_LASER_SMALL, - ARMOR_ENERGY = ARMOR_ENERGY_SMALL, - ARMOR_BOMB = ARMOR_BOMB_PADDED, - ARMOR_BIO = ARMOR_BIO_MINOR, - ARMOR_RAD = ARMOR_RAD_MINOR - ) - allowed = list(/obj/item/paper/scroll) - siemens_coefficient = 0.8 - wizard_garb = 1 - -/obj/item/clothing/suit/wizrobe/red - name = "red wizard robe" - desc = "A magnificant, red, gem-lined robe that seems to radiate power." - icon = 'icons/clothing/suits/wizard/red.dmi' - -/obj/item/clothing/suit/wizrobe/marisa - name = "witch robe" - desc = "Magic is all about the spell power, ZE!" - icon = 'icons/clothing/suits/wizard/marisa.dmi' - -/obj/item/clothing/suit/wizrobe/magusblue - name = "magus robe" - desc = "A set of armoured robes that seem to radiate a dark power." - icon = 'icons/clothing/suits/wizard/magusblue.dmi' - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_HANDS|SLOT_LEGS|SLOT_FEET - -/obj/item/clothing/suit/wizrobe/magusred - name = "magus robe" - desc = "A set of armoured robes that seem to radiate a dark power." - icon = 'icons/clothing/suits/wizard/magusred.dmi' - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_HANDS|SLOT_LEGS|SLOT_FEET - -/obj/item/clothing/suit/wizrobe/psypurple - name = "purple robes" - desc = "Heavy, royal purple robes threaded with psychic amplifiers and weird, bulbous lenses. Do not machine wash." - icon = 'icons/clothing/suits/wizard/psy.dmi' - gender = PLURAL - -/obj/item/clothing/suit/wizrobe/gentlecoat - name = "gentleman's coat" - desc = "A heavy threaded tweed gray jacket. For a different sort of Gentleman." - icon = 'icons/clothing/suits/wizard/gentleman.dmi' - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS - -/obj/item/clothing/suit/wizrobe/fake - name = "wizard robe" - desc = "A rather dull, blue robe meant to mimick real wizard robes." - icon = 'icons/clothing/suits/wizard/fake.dmi' - armor = null - siemens_coefficient = 1.0 - -/obj/item/clothing/head/wizard/marisa/fake - name = "witch hat" - desc = "Strange-looking hat-wear, makes you want to cast fireballs." - armor = null - siemens_coefficient = 1.0 - -/obj/item/clothing/suit/wizrobe/marisa/fake - name = "witch robe" - desc = "Magic is all about the spell power, ZE!" - body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_LEGS - armor = null - siemens_coefficient = 1.0 - diff --git a/code/modules/clothing/suits/wizard.dm b/code/modules/clothing/suits/wizard.dm new file mode 100644 index 000000000000..c8f0208fb4d5 --- /dev/null +++ b/code/modules/clothing/suits/wizard.dm @@ -0,0 +1,25 @@ +// Props from wizard mode, preserved as costume pieces. +/obj/item/clothing/suit/wizrobe + name = "wizard robe" + desc = "A rather ratty blue robe." + icon = 'icons/clothing/suits/wizard/wizard.dmi' + allowed = list(/obj/item/paper/scroll) + +/obj/item/clothing/suit/wizrobe/red + name = "red wizard robe" + desc = "A rather ratty red robe." + icon = 'icons/clothing/suits/wizard/red.dmi' + +/obj/item/clothing/suit/wizrobe/marisa + name = "witch robe" + desc = "Magic is all about the spell power, ZE!" + icon = 'icons/clothing/suits/wizard/marisa.dmi' + +/obj/item/clothing/suit/wizrobe/magus + name = "magus robe" + desc = "A set of mysterious armoured robes." + icon = 'icons/clothing/suits/wizard/magusblue.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_HANDS|SLOT_LEGS|SLOT_FEET + +/obj/item/clothing/suit/wizrobe/magus/red + icon = 'icons/clothing/suits/wizard/magusred.dmi' diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm index da2c66433b4b..1f450a9aadff 100644 --- a/code/modules/ghosttrap/trap.dm +++ b/code/modules/ghosttrap/trap.dm @@ -176,18 +176,6 @@ if(istype(drone)) drone.transfer_personality(candidate.client) -/****************** -* Wizard Familiar * -******************/ -/decl/ghosttrap/wizard_familiar - name = "wizard familiar" - pref_check = "ghost_wizard" - ghost_trap_message = "They are occupying a familiar now." - ban_checks = list(/decl/special_role/wizard) - -/decl/ghosttrap/wizard_familiar/welcome_candidate(var/mob/target) - return 0 - // Stub PAI ghost trap so that PAI shows up in the ghost role list. // Actually invoking this ghost trap as normal will not do anything. /decl/ghosttrap/personal_ai diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 1b7d470abc8a..4986952e1305 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -51,7 +51,7 @@ spawn_gibber(lastloc) //This is the proc for turning a mob into ash. Mostly a copy of gib code (above). -//Originally created for wizard disintegrate. I've removed the virus code since it's irrelevant here. +//Originally created for Disintegrate. I've removed the virus code since it's irrelevant here. //Dusting robots does not eject the brain, so it's a bit more powerful than gib() /N /mob/proc/dust() SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/mob/living/simple_animal/familiars/familiars.dm b/code/modules/mob/living/simple_animal/familiars/familiars.dm deleted file mode 100644 index 8cefee06d93a..000000000000 --- a/code/modules/mob/living/simple_animal/familiars/familiars.dm +++ /dev/null @@ -1,133 +0,0 @@ -/mob/living/simple_animal/familiar - name = "familiar" - desc = "No wizard is complete without a mystical sidekick." - supernatural = 1 - universal_speak = FALSE - universal_understand = TRUE - - min_gas = list(/decl/material/gas/oxygen = 1) - max_gas = null - unsuitable_atmos_damage = 1 - gene_damage = -1 - base_animal_type = /mob/living/simple_animal/familiar - - var/list/wizardy_spells = list() - -/mob/living/simple_animal/familiar/Initialize() - . = ..() - add_language(/decl/language/human/common) - for(var/spell in wizardy_spells) - src.add_spell(new spell, "const_spell_ready") - -/mob/living/simple_animal/familiar/carcinus - name = "carcinus" - desc = "A small crab said to be made of stone and starlight." - icon = 'icons/mob/simple_animal/evilcrab.dmi' - speak_emote = list("chitters","clicks") - max_health = 200 - natural_weapon = /obj/item/natural_weapon/pincers/strong - resistance = 9 - ai = /datum/mob_controller/familiar_crab - -/datum/mob_controller/familiar_crab - can_escape_buckles = TRUE - -/obj/item/natural_weapon/pincers/strong - _base_attack_force = 15 - -/*familiar version of the Pike w/o all the other hostile/carp stuff getting in the way (namely life) -*/ - -/mob/living/simple_animal/familiar/pike - name = "space pike" - desc = "A bigger, more magical cousin of the space carp." - icon = 'icons/mob/simple_animal/spaceshark.dmi' - pixel_x = -16 - offset_overhead_text_x = 16 - - speak_emote = list("gnashes") - max_health = 100 - natural_weapon = /obj/item/natural_weapon/bite - min_gas = null - wizardy_spells = list(/spell/aoe_turf/conjure/forcewall) - ai = /datum/mob_controller/familiar_pike - -/datum/mob_controller/familiar_pike - can_escape_buckles = TRUE - -/mob/living/simple_animal/familiar/pike/Process_Spacemove() - return 1 //No drifting in space for space carp! //original comments do not steal - -/mob/living/simple_animal/familiar/horror - name = "horror" - desc = "Looking at it fills you with dread." - icon = 'icons/mob/simple_animal/horror.dmi' - speak_emote = list("moans", "groans") - response_help_1p = "You think better of touching $TARGET$." - response_help_3p = "$USER$ thinks better of touching $TARGET$." - max_health = 150 - natural_weapon = /obj/item/natural_weapon/horror - wizardy_spells = list(/spell/targeted/torment) - -/obj/item/natural_weapon/horror - name = "foul touch" - _base_attack_force = 10 - atom_damage_type = BURN - attack_verb = list("touched") - -/mob/living/simple_animal/familiar/horror/get_death_message(gibbed) - return "rapidly deteriorates" -/mob/living/simple_animal/familiar/horror/get_self_death_message(gibbed) - return "The bonds tying you to this mortal plane have been severed." - -/mob/living/simple_animal/familiar/horror/death(gibbed) - . = ..() - if(. && !gibbed) - spawn_gibber(loc) - qdel(src) - -/mob/living/simple_animal/familiar/minor_amaros - name = "minor amaros" - desc = "A small fluffy alien creature." - icon = 'icons/mob/simple_animal/amaros.dmi' - speak_emote = list("entones") - mob_size = MOB_SIZE_SMALL - max_health = 25 - wizardy_spells = list( - /spell/targeted/heal_target, - /spell/targeted/heal_target/area - ) - -/mob/living/simple_animal/familiar/pet/mouse - name = "elderly mouse" - desc = "A small rodent. It looks very old." - icon = 'icons/mob/simple_animal/mouse_gray.dmi' - speak_emote = list("squeeks") - holder_type = /obj/item/holder - pass_flags = PASS_FLAG_TABLE - mob_size = MOB_SIZE_MINISCULE - response_harm = "stamps on" - max_health = 15 - natural_weapon = /obj/item/natural_weapon/bite/mouse - wizardy_spells = list(/spell/aoe_turf/smoke) - ai = /datum/mob_controller/familiar_mouse - -/datum/mob_controller/familiar_mouse - can_escape_buckles = TRUE - -/mob/living/simple_animal/familiar/pet/mouse/Initialize() - . = ..() - - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - -/mob/living/simple_animal/familiar/pet/cat - name = "black cat" - desc = "A pitch black cat. Said to be especially unlucky." - icon = 'icons/mob/simple_animal/cat_black.dmi' - speak_emote = list("meows", "purrs") - holder_type = /obj/item/holder - mob_size = MOB_SIZE_SMALL - max_health = 25 - natural_weapon = /obj/item/natural_weapon/claws/weak - wizardy_spells = list(/spell/targeted/subjugation) diff --git a/code/modules/organs/internal/species/golem.dm b/code/modules/organs/internal/species/golem.dm index 93e368c2e646..cbf569bebab9 100644 --- a/code/modules/organs/internal/species/golem.dm +++ b/code/modules/organs/internal/species/golem.dm @@ -1,8 +1,9 @@ /obj/item/organ/internal/brain/golem name = "chem" desc = "A tightly furled roll of paper, covered with indecipherable runes." - icon = 'icons/obj/wizard.dmi' + icon = 'icons/obj/items/paperwork/scroll.dmi' icon_state = "scroll" + color = COLOR_BEIGE /obj/item/organ/internal/brain/golem/can_recover() - return 0 + return FALSE diff --git a/code/modules/projectiles/guns/energy/staves.dm b/code/modules/projectiles/guns/energy/staves.dm index 45ab5f71b6f3..965c8f208e07 100644 --- a/code/modules/projectiles/guns/energy/staves.dm +++ b/code/modules/projectiles/guns/energy/staves.dm @@ -13,15 +13,13 @@ self_recharge = 1 charge_meter = 0 has_safety = FALSE - var/required_antag_type = /decl/special_role/wizard + var/required_antag_type /obj/item/gun/energy/staff/special_check(var/mob/user) - if(required_antag_type) - var/decl/special_role/antag = GET_DECL(required_antag_type) - if(user.mind && !antag.is_antagonist(user.mind)) - to_chat(usr, "You focus your mind on \the [src], but nothing happens!") - return 0 - + var/decl/special_role/antag = GET_DECL(required_antag_type) + if(user.mind && (!antag?.is_antagonist(user.mind))) + to_chat(user, SPAN_WARNING("You focus your mind on \the [src], but nothing happens!")) + return FALSE return ..() /obj/item/gun/energy/staff/handle_click_empty(mob/user = null) diff --git a/code/modules/spells/aoe_turf/aoe_turf.dm b/code/modules/spells/aoe_turf/aoe_turf.dm index 46febbfbe5fd..0f7a721de803 100644 --- a/code/modules/spells/aoe_turf/aoe_turf.dm +++ b/code/modules/spells/aoe_turf/aoe_turf.dm @@ -1,7 +1,7 @@ /* Aoe turf spells target a ring of tiles around the user This ring has an outer radius (range) and an inner radius (inner_radius) -Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm +Aoe turf spells have a useful flag: IGNOREDENSE. It is explained in setup.dm */ /spell/aoe_turf //affects all turfs in view or range (depends) @@ -15,8 +15,6 @@ Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are ex if(!(target in view_or_range(inner_radius, holder, selection_type))) if(target.density && (spell_flags & IGNOREDENSE)) continue - if(isspaceturf(target) && (spell_flags & IGNORESPACE)) - continue targets += target if(!targets.len) //doesn't waste the spell diff --git a/code/modules/spells/aoe_turf/blink.dm b/code/modules/spells/aoe_turf/blink.dm deleted file mode 100644 index 3fd742aec243..000000000000 --- a/code/modules/spells/aoe_turf/blink.dm +++ /dev/null @@ -1,44 +0,0 @@ -/spell/aoe_turf/blink - name = "Blink" - desc = "This spell randomly teleports you a short distance." - feedback = "BL" - school = "conjuration" - charge_max = 20 - spell_flags = Z2NOCAST | IGNOREDENSE | IGNORESPACE - invocation = "none" - invocation_type = SpI_NONE - range = 7 - inner_radius = 1 - - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 4) - cooldown_min = 5 //4 deciseconds reduction per rank - hud_state = "wiz_blink" - cast_sound = 'sound/magic/blink.ogg' - -/spell/aoe_turf/blink/cast(var/list/targets, mob/user) - if(!targets.len) - return - - var/turf/T = pick(targets) - var/turf/starting = get_turf(user) - if(T) - if(user.buckled) - user.buckled = null - user.forceMove(T) - - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(3, 0, starting) - smoke.start() - - smoke = new() - smoke.set_up(3, 0, T) - smoke.start() - - return - -/spell/aoe_turf/blink/empower_spell() - if(!..()) - return 0 - inner_radius += 1 - - return "You've increased the inner range of [src]." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/charge.dm b/code/modules/spells/aoe_turf/charge.dm deleted file mode 100644 index d9c8f95af90a..000000000000 --- a/code/modules/spells/aoe_turf/charge.dm +++ /dev/null @@ -1,72 +0,0 @@ -/spell/aoe_turf/charge - name = "Charge" - desc = "This spell can be used to charge up spent magical artifacts, among other things." - - school = "transmutation" - charge_max = 600 - spell_flags = 0 - invocation = "DIRI CEL" - invocation_type = SpI_WHISPER - range = 0 - cooldown_min = 400 //50 deciseconds reduction per rank - - hud_state = "wiz_charge" - cast_sound = 'sound/magic/charge.ogg' - -/spell/aoe_turf/charge/cast(var/list/targets, mob/user) - for(var/turf/T in targets) - depth_cast(T) - -/spell/aoe_turf/charge/proc/depth_cast(var/list/targets) - for(var/atom/A in targets) - if(A.contents.len) - depth_cast(A.contents) - cast_charge(A) - -/spell/aoe_turf/charge/proc/mob_charge(var/mob/living/M) - if(!M.mind) - return - if(M.mind.learned_spells.len != 0) - for(var/spell/S in M.mind.learned_spells) - if(!istype(S, /spell/aoe_turf/charge)) - S.charge_counter = S.charge_max - to_chat(M, "You feel raw magic flowing through you, it feels good!") - else - to_chat(M, "You feel very strange for a moment, but then it passes.") - return M - -/spell/aoe_turf/charge/proc/cast_charge(var/atom/target) - var/atom/charged_item - - if(isliving(target)) - charged_item = mob_charge(target) - - if(istype(target, /obj/item/grab)) - var/obj/item/grab/grab = target - if(grab.affecting) - var/mob/M = grab.get_affecting_mob() - if(M) - charged_item = mob_charge(M) - - if(istype(target, /obj/item/cell/)) - var/obj/item/cell/C = target - if(prob(80) && C.maxcharge) - C.maxcharge -= 200 - if(C.maxcharge <= 0) //maxcharge of 0! Madness! - C.maxcharge = 0 - C.charge = C.maxcharge - charged_item = C - - if(!charged_item) - return 0 - else - charged_item.visible_message("[charged_item] suddenly sparks with energy!") - return 1 - - -/spell/aoe_turf/charge/blood - name = "Blood Infusion" - desc = "This spell charges things around it using the lifeforce gained by sacrificed blood." - charge_type = Sp_HOLDVAR - holder_var_type = "bruteloss" - holder_var_amount = 30 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/conjure.dm b/code/modules/spells/aoe_turf/conjure/conjure.dm index 9291456f41a6..8dd91146310c 100644 --- a/code/modules/spells/aoe_turf/conjure/conjure.dm +++ b/code/modules/spells/aoe_turf/conjure/conjure.dm @@ -20,7 +20,7 @@ How they spawn stuff is decided by behaviour vars, which are explained below var/summon_exclusive = 0 //spawn one of everything, instead of random things var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet - //should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example + //should have format of list("emagged" = 1,"name" = "Justicebot"), for example cast_sound = 'sound/magic/castsummon.ogg' @@ -38,9 +38,6 @@ How they spawn stuff is decided by behaviour vars, which are explained below else summoned_object_type = pick(summon_type) var/turf/spawn_place = pick(targets) - if(spell_flags & IGNOREPREV) - targets -= spawn_place - var/atom/summoned_object if(ispath(summoned_object_type,/turf)) spawn_place.ChangeTurf(summoned_object_type) diff --git a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm deleted file mode 100644 index e6f0b8ea2607..000000000000 --- a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm +++ /dev/null @@ -1,113 +0,0 @@ -/spell/aoe_turf/conjure/summon - var/name_summon = 0 - cast_sound = 'sound/weapons/wave.ogg' - -/spell/aoe_turf/conjure/summon/before_cast() - ..() - if(name_summon) - var/newName = sanitize(input("Would you like to name your summon?") as null|text, MAX_NAME_LEN) - if(newName) - newVars["name"] = newName - -/spell/aoe_turf/conjure/summon/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) - animation.icon_state = "shield2" - flick("shield2",animation) - sleep(10) - ..() - - -/spell/aoe_turf/conjure/summon/bats - name = "Summon Space Bats" - desc = "This spell summons a flock of spooky space bats." - feedback = "SB" - - charge_max = 1200 //2 minutes - spell_flags = NEEDSCLOTHES - invocation = "Bla'yo daya!" - invocation_type = SpI_SHOUT - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) - cooldown_min = 600 - - range = 1 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/hostile/scarybat) - - hud_state = "wiz_bats" - -/spell/aoe_turf/conjure/summon/bats/empower_spell() - if(!..()) - return 0 - - newVars = list("max_health" = 20 + spell_levels[Sp_POWER]*5, "health" = 20 + spell_levels[Sp_POWER]*5, "melee_damage_lower" = 10 + spell_levels[Sp_POWER], "melee_damage_upper" = 10 + spell_levels[Sp_POWER]*2) - - return "Your bats are now stronger." - -/spell/aoe_turf/conjure/summon/bear - name = "Summon Bear" - desc = "This spell summons a permanent bear companion that will follow your orders." - feedback = "BR" - charge_max = 3000 //5 minutes because this is a REALLY powerful spell. May tone it down/up. - spell_flags = NEEDSCLOTHES - invocation = "REA'YO GOR DAYA!" - invocation_type = SpI_SHOUT - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 0, Sp_POWER = 4) - - range = 0 - - name_summon = 1 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/hostile/commanded/bear) - newVars = list("max_health" = 15, - "health" = 15, - "melee_damage_lower" = 10, - "melee_damage_upper" = 10, - ) - - hud_state = "wiz_bear" - -/spell/aoe_turf/conjure/summon/bear/apply_vars(atom/summoned_object, mob/caster) - . = ..() - if(isliving(summoned_object)) - var/mob/living/summoned_mob = summoned_object - if(istype(summoned_mob.ai, /datum/mob_controller/aggressive/commanded)) - var/datum/mob_controller/aggressive/commanded/command_ai = summoned_mob.ai - command_ai.master = caster - -/spell/aoe_turf/conjure/summon/bear/empower_spell() - if(!..()) - return 0 - switch(spell_levels[Sp_POWER]) - if(1) - newVars = list("max_health" = 30, - "health" = 30, - "melee_damage_lower" = 15, - "melee_damage_upper" = 15 - ) - return "Your bear has been upgraded from a cub to a whelp." - if(2) - newVars = list("max_health" = 45, - "health" = 45, - "melee_damage_lower" = 20, - "melee_damage_upper" = 20, - "color" = "#d9d9d9" //basically we want them to look different enough that people can recognize it. - ) - return "Your bear has been upgraded from a whelp to an adult." - if(3) - newVars = list("max_health" = 60, - "health" = 60, - "melee_damage_lower" = 25, - "melee_damage_upper" = 25, - "color" = "#8c8c8c" - ) - return "Your bear has been upgraded from an adult to an alpha." - if(4) - newVars = list("max_health" = 75, - "health" = 75, - "melee_damage_lower" = 35, - "melee_damage_upper" = 35, - "resistance" = 3, - "color" = "#0099ff" - ) - return "Your bear is now worshiped as a god amongst bears." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/faithful_hound.dm b/code/modules/spells/aoe_turf/conjure/faithful_hound.dm deleted file mode 100644 index 4511e6a07f46..000000000000 --- a/code/modules/spells/aoe_turf/conjure/faithful_hound.dm +++ /dev/null @@ -1,28 +0,0 @@ -/spell/aoe_turf/conjure/faithful_hound - name = "Faithful Hound" - desc = "Summon a spectral watchdog with a special password. Anyone without the password is in for a barking and a biting." - feedback = "FH" - - charge_max = 600 - spell_flags = NEEDSCLOTHES - invocation = "Du korilath tangus" - invocation_type = SpI_WHISPER - range = 0 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/faithful_hound) - hud_state = "wiz_hound" - - var/temp_password - -/spell/aoe_turf/conjure/faithful_hound/apply_vars(atom/summoned_object, mob/caster) - . = ..() - var/mob/living/simple_animal/faithful_hound/hound = summoned_object - if(istype(hound) && istype(hound.ai)) - hound.ai.add_friend(caster) - hound.ai.memorise(caster, temp_password) - temp_password = null - -/spell/aoe_turf/conjure/faithful_hound/before_cast() - ..() - temp_password = sanitize(input("What password will this beast listen to?") as text, MAX_NAME_LEN) diff --git a/code/modules/spells/aoe_turf/conjure/force_portal.dm b/code/modules/spells/aoe_turf/conjure/force_portal.dm deleted file mode 100644 index 293e176051f1..000000000000 --- a/code/modules/spells/aoe_turf/conjure/force_portal.dm +++ /dev/null @@ -1,12 +0,0 @@ -/spell/aoe_turf/conjure/force_portal - name = "Force Portal" - desc = "Create a portal that sucks in anything that touches it and then shoots it all out at the end." - school = "conjuration" - feedback = "FP" - summon_type = list(/obj/effect/force_portal) - charge_max = 200 - spell_flags = NEEDSCLOTHES - range = 0 - cast_sound = null - - hud_state = "wiz_force" diff --git a/code/modules/spells/aoe_turf/conjure/forcewall.dm b/code/modules/spells/aoe_turf/conjure/forcewall.dm deleted file mode 100644 index 1c937f3f6d8c..000000000000 --- a/code/modules/spells/aoe_turf/conjure/forcewall.dm +++ /dev/null @@ -1,48 +0,0 @@ -/spell/aoe_turf/conjure/forcewall - name = "Forcewall" - desc = "Create a wall of pure energy at your location." - school = "conjuration" - feedback = "FW" - summon_type = list(/obj/effect/forcefield) - duration = 300 - charge_max = 100 - spell_flags = 0 - range = 0 - cast_sound = 'sound/magic/forcewall.ogg' - - hud_state = "wiz_shield" - -/spell/aoe_turf/conjure/forcewall/mime - name = "Invisible wall" - desc = "Create an invisible wall on your location." - school = "mime" - panel = "Mime" - summon_type = list(/obj/effect/forcefield/mime) - invocation_type = SpI_EMOTE - invocation = "mimes placing their hands on a flat surfacing, and pushing against it." - charge_max = 300 - cast_sound = null - - override_base = "grey" - hud_state = "mime_wall" - -/obj/effect/forcefield - desc = "A space wizard's magic wall." - name = "FORCEWALL" - icon = 'icons/effects/effects.dmi' - icon_state = "m_shield" - anchored = TRUE - opacity = FALSE - density = TRUE - -/obj/effect/forcefield/bullet_act(var/obj/item/projectile/Proj, var/def_zone) - var/turf/T = get_turf(src.loc) - if(T) - for(var/mob/M in T) - Proj.on_hit(M,M.bullet_act(Proj, def_zone)) - return - -/obj/effect/forcefield/mime - icon_state = "empty" - name = "invisible wall" - desc = "You have a bad feeling about this." diff --git a/code/modules/spells/aoe_turf/conjure/grove.dm b/code/modules/spells/aoe_turf/conjure/grove.dm deleted file mode 100644 index 77f68981e9db..000000000000 --- a/code/modules/spells/aoe_turf/conjure/grove.dm +++ /dev/null @@ -1,75 +0,0 @@ -/spell/aoe_turf/conjure/grove - name = "Grove" - desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." - - spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV - charge_max = 1200 - school = "transmutation" - - range = 1 - cooldown_min = 600 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) - - summon_amt = 47 - summon_type = list(/turf/floor/fake_grass) - var/spread = 0 - var/datum/seed/seed - var/seed_type = /datum/seed/merlin_tear - cast_sound = 'sound/magic/repulse.ogg' - -/spell/aoe_turf/conjure/grove/New() - ..() - if(seed_type) - seed = new seed_type() - else - seed = SSplants.create_random_seed(1) - -/spell/aoe_turf/conjure/grove/before_cast() - var/turf/T = get_turf(holder) - var/obj/effect/vine/P = new(T,seed) - P.spread_chance = spread - - -/spell/aoe_turf/conjure/grove/sanctuary - name = "Sanctuary" - desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." - feedback = "SY" - invocation = "Bo K'Iitan!" - invocation_type = SpI_SHOUT - spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV - cooldown_min = 600 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) - - seed_type = /datum/seed/merlin_tear - newVars = list("name" = "sanctuary", "desc" = "This grass makes you feel comfortable. Peaceful.","blessed" = 1) - - hud_state = "wiz_grove" -/spell/aoe_turf/conjure/grove/sanctuary/empower_spell() - if(!..()) - return 0 - - seed.set_trait(TRAIT_SPREAD,2) //make it grow. - spread = 40 - return "Your sanctuary will now grow beyond that of the grassy perimeter." - -/datum/seed/merlin_tear - name = "merlin tears" - product_name = "merlin tears" - display_name = "merlin tears" - chems = list(/decl/material/liquid/brute_meds = list(3,7), /decl/material/liquid/burn_meds = list(3,7), /decl/material/liquid/antitoxins = list(3,7), /decl/material/liquid/regenerator = list(3,7), /decl/material/liquid/neuroannealer = list(1,2), /decl/material/liquid/eyedrops = list(1,2)) - grown_tag = "berries" - -/datum/seed/merlin_tear/New() - ..() - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_PRODUCT_ICON,"berry") - set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") - set_trait(TRAIT_PLANT_COLOUR, "#ff6600") - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_IMMUTABLE,1) //no making op plants pls \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/disable_tech.dm b/code/modules/spells/aoe_turf/disable_tech.dm deleted file mode 100644 index d9912e1c3907..000000000000 --- a/code/modules/spells/aoe_turf/disable_tech.dm +++ /dev/null @@ -1,33 +0,0 @@ -/spell/aoe_turf/disable_tech - name = "Disable Tech" - desc = "This spell disables all weapons, cameras and most other technology in range." - feedback = "DT" - charge_max = 400 - spell_flags = NEEDSCLOTHES - invocation = "NEC CANTIO" - invocation_type = SpI_SHOUT - selection_type = "range" - range = 0 - inner_radius = -1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - cooldown_min = 200 //50 deciseconds reduction per rank - - var/emp_heavy = 3 - var/emp_light = 5 - - hud_state = "wiz_tech" - cast_sound = 'sound/magic/disable_tech.ogg' - -/spell/aoe_turf/disable_tech/cast(list/targets) - - for(var/turf/target in targets) - empulse(get_turf(target), emp_heavy, emp_light) - return - -/spell/aoe_turf/disable_tech/empower_spell() - if(!..()) - return 0 - emp_heavy += 2 - emp_light += 2 - - return "You've increased the range of [src]." diff --git a/code/modules/spells/aoe_turf/drain_blood.dm b/code/modules/spells/aoe_turf/drain_blood.dm deleted file mode 100644 index 8ad4ea6b8a29..000000000000 --- a/code/modules/spells/aoe_turf/drain_blood.dm +++ /dev/null @@ -1,66 +0,0 @@ -/spell/aoe_turf/drain_blood - name = "Drain Blood" - desc = "This spell allows the caster to borrow blood from those around them. Sharing is caring!" - feedback = "DB" - school = "transmutation" - charge_max = 600 - invocation = "whispers something darkly" - invocation_type = SpI_EMOTE - range = 3 - inner_radius = 0 - - time_between_channels = 100 - number_of_channels = 3 - cast_sound = 'sound/effects/squelch2.ogg' - hud_state = "const_rune" - -/spell/aoe_turf/drain_blood/cast(var/list/targets, var/mob/user) - for(var/t in targets) - for(var/mob/living/L in t) - if(L.stat == DEAD || L == user) - continue - //Hurt target - if(ishuman(L)) - var/mob/living/human/H = L - H.vessel.remove_any(10) - else - L.take_damage(10) - to_chat(L, "You feel your lifeforce being ripping out of your body!") - - //Do effect - var/obj/item/projectile/beam/blood_effect/effect = new(get_turf(user)) - effect.pixel_x = 0 - effect.pixel_y = 0 - effect.launch(L, "chest") - - //Heal self - if(ishuman(user)) - var/mob/living/human/H = user - var/amount = min(10, H.species.blood_volume - H.vessel.total_volume) - if(amount > 0) - H.adjust_blood(amount) - continue - L.heal_damage(BRUTE, 5, do_update_health = FALSE) - L.heal_damage(BURN, 2.5, do_update_health = FALSE) - L.heal_damage(TOX, 2.5) - -/obj/item/projectile/beam/blood_effect - name = "blood jet" - icon_state = "blood" - damage = 0 - randpixel = 0 - no_attack_log = 1 - muzzle_type = /obj/effect/projectile/blood - tracer_type = /obj/effect/projectile/blood - impact_type = /obj/effect/projectile/blood - -/obj/item/projectile/beam/blood_effect/Bump(var/atom/a, forced=0) - if(a == original) - on_impact(a) - qdel(src) - return 1 - return 0 - - -/obj/effect/projectile/blood - icon_state = "blood" \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/exchange_wounds.dm b/code/modules/spells/aoe_turf/exchange_wounds.dm deleted file mode 100644 index 7293e960d292..000000000000 --- a/code/modules/spells/aoe_turf/exchange_wounds.dm +++ /dev/null @@ -1,43 +0,0 @@ -/spell/aoe_turf/exchange_wounds - name = "Exchange Wounds" - desc = "Allows you to sacrifice your own well-being for that of those around you." - feedback = "EW" - school = "transmutation" - invocation = "Esh Yek Vai!" - invocation_type = SpI_SHOUT - charge_max = 400 - spell_flags = 0 - - var/amt_healed = 0 - var/heal_max = 100 - range = 4 - inner_radius = 0 - number_of_channels = 0 - time_between_channels = 20 - - hud_state = "wiz_exchange" - -/spell/aoe_turf/exchange_wounds/perform() - amt_healed = 0 - ..() - -/spell/aoe_turf/exchange_wounds/cast(var/list/targets, var/mob/living/user) - new /obj/effect/temporary(get_turf(user),10,'icons/effects/effects.dmi',"purple_electricity_constant") - for(var/t in targets) - for(var/mob/living/L in t) - if(L.faction != user.faction) - continue - new /obj/effect/temporary(get_turf(L),10,'icons/effects/effects.dmi',"green_sparkles") - if(L.get_damage(BRUTE) > 5) - L.heal_damage(BRUTE, 5) - user.take_damage(2) - amt_healed += 5 - if(L.get_damage(BURN) > 5) - L.heal_damage(BURN, 5) - user.take_damage(2, BURN) - amt_healed += 5 - -/spell/aoe_turf/exchange_wounds/check_valid_targets() - if(amt_healed > heal_max) - return FALSE - return ..() \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/knock.dm b/code/modules/spells/aoe_turf/knock.dm deleted file mode 100644 index 3cf8614eeaa7..000000000000 --- a/code/modules/spells/aoe_turf/knock.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/aoe_turf/knock - name = "Knock" - desc = "This spell opens nearby doors and does not require wizard garb." - feedback = "KN" - school = "transmutation" - charge_max = 100 - spell_flags = 0 - invocation = "Aulie Oxin Fiera." - invocation_type = SpI_WHISPER - range = 3 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - cooldown_min = 20 //20 deciseconds reduction per rank - - hud_state = "wiz_knock" - cast_sound = 'sound/magic/knock.ogg' - -/spell/aoe_turf/knock/cast(list/targets) - for(var/turf/T in targets) - for(var/obj/machinery/door/door in T.contents) - spawn(1) - if(istype(door,/obj/machinery/door/airlock)) - var/obj/machinery/door/airlock/AL = door //casting is important - AL.locked = 0 - door.open() - return - - -/spell/aoe_turf/knock/empower_spell() - if(!..()) - return 0 - range *= 2 - - return "You've doubled the range of [src]." - -/spell/aoe_turf/knock/slow - charge_max = 200 - hidden_from_codex = TRUE diff --git a/code/modules/spells/aoe_turf/smoke.dm b/code/modules/spells/aoe_turf/smoke.dm deleted file mode 100644 index f9f0138908fb..000000000000 --- a/code/modules/spells/aoe_turf/smoke.dm +++ /dev/null @@ -1,26 +0,0 @@ -/spell/aoe_turf/smoke - name = "Smoke" - desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb." - feedback = "SM" - school = "transmutation" - charge_max = 120 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 1 - inner_radius = -1 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 2) - cooldown_min = 20 //25 deciseconds reduction per rank - - smoke_spread = 2 - smoke_amt = 5 - - hud_state = "wiz_smoke" - cast_sound = 'sound/magic/smoke.ogg' - -/spell/aoe_turf/smoke/empower_spell() - if(!..()) - return 0 - smoke_amt += 2 - - return "[src] will now create more smoke." diff --git a/code/modules/spells/aoe_turf/summons.dm b/code/modules/spells/aoe_turf/summons.dm deleted file mode 100644 index be61819d9eab..000000000000 --- a/code/modules/spells/aoe_turf/summons.dm +++ /dev/null @@ -1,72 +0,0 @@ -/spell/aoe_turf/conjure/summonEdSwarm //test purposes - name = "Dispense Wizard Justice" - desc = "This spell dispenses wizard justice." - - summon_type = list(/mob/living/bot/secbot/ed209) - summon_amt = 10 - range = 3 - newVars = list("emagged" = 1,"name" = "Wizard's Justicebot") - - hud_state = "wiz_ed" - -/spell/aoe_turf/conjure/carp - name = "Summon Carp" - desc = "This spell conjures a simple carp." - - school = "conjuration" - charge_max = 1200 - spell_flags = NEEDSCLOTHES - invocation = "Nouk Fhumm Sacp Risska!" - invocation_type = SpI_SHOUT - range = 1 - cast_sound = 'sound/magic/summon_carp.ogg' - - summon_type = list(/mob/living/simple_animal/hostile/carp) - - hud_state = "wiz_carp" - -/spell/aoe_turf/conjure/creature - name = "Summon Creature Swarm" - desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth" - - school = "conjuration" - charge_max = 1200 - spell_flags = 0 - invocation = "Ia-Ia! Naomesnalia!" - invocation_type = SpI_SHOUT - summon_amt = 10 - range = 3 - - summon_type = list(/mob/living/simple_animal/hostile/creature) - - hud_state = "wiz_creature" - -/spell/aoe_turf/conjure/mirage - name = "Summon Mirage" - desc = "This spell summons a harmless carp mirage for a few seconds." - feedback = "MR" - school = "illusion" - charge_max = 1200 - spell_flags = NEEDSCLOTHES - invocation = "Nouk Fhunhm Sacp Risska!" - invocation_type = SpI_SHOUT - range = 1 - cast_sound = 'sound/magic/summon_carp.ogg' - - duration = 600 - cooldown_min = 600 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 2, Sp_POWER = 3) - - summon_type = list(/mob/living/simple_animal/hostile/carp) - - hud_state = "wiz_carp" - - newVars = list("melee_damage_lower" = 0, "melee_damage_upper" = 0, "break_stuff_probability" = 0) - -/spell/aoe_turf/conjure/mirage/empower_spell() - if(!..()) - return 0 - - summon_amt++ - - return "You now summon [summon_amt] mirages per spellcast." \ No newline at end of file diff --git a/code/modules/spells/artifacts.dm b/code/modules/spells/artifacts.dm deleted file mode 100644 index 2c085ff8e2a5..000000000000 --- a/code/modules/spells/artifacts.dm +++ /dev/null @@ -1,41 +0,0 @@ -//////////////////////Scrying orb////////////////////// - -/obj/item/scrying - name = "scrying orb" - desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means." - icon = 'icons/obj/projectiles.dmi' - icon_state = "bluespace" - throw_speed = 3 - throw_range = 7 - atom_damage_type = BURN - hitsound = 'sound/magic/forcewall.ogg' - max_health = ITEM_HEALTH_NO_DAMAGE - _base_attack_force = 10 - -/obj/item/scrying/attack_self(mob/user) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if((user.mind && !wizards.is_antagonist(user.mind))) - to_chat(user, "You stare into the orb and see nothing but your own reflection.") - return - - to_chat(user, "You can see... everything!") // This never actually happens. - visible_message("[user] stares into [src], their eyes glazing over.") - - user.teleop = user.ghostize() - announce_ghost_joinleave(user.teleop, 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.") - return - - - -/////////////////////////Cursed Dice/////////////////////////// -/obj/item/dice/d20/cursed - desc = "A dice with twenty sides said to have an ill effect on those that are unlucky..." - -/obj/item/dice/d20/cursed/attack_self(mob/user) - ..() - if(isliving(user)) - var/mob/living/M = user - if(icon_state == "[name][sides]") - M.heal_damage(BRUTE, 30) - else if(icon_state == "[name]1") - M.take_damage(30) diff --git a/code/modules/spells/artifacts/spellbound_servants.dm b/code/modules/spells/artifacts/spellbound_servants.dm deleted file mode 100644 index 6477080cfdf4..000000000000 --- a/code/modules/spells/artifacts/spellbound_servants.dm +++ /dev/null @@ -1,284 +0,0 @@ -/datum/spellbound_type - var/name = "Stuff" - var/desc = "spells n shit" - var/equipment = list() - var/spells = list() - -/datum/spellbound_type/proc/spawn_servant(var/atom/a, var/mob/master, var/mob/user) - set waitfor = 0 - var/mob/living/human/H = new(a) - H.ckey = user.ckey - H.change_appearance(APPEARANCE_GENDER|APPEARANCE_BODY|APPEARANCE_EYE_COLOR|APPEARANCE_HAIR|APPEARANCE_FACIAL_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR_COLOR|APPEARANCE_SKIN) - - var/obj/item/implant/translator/natural/I = new() - I.implant_in_mob(H, BP_HEAD) - if (length(master.languages)) - var/decl/language/lang = master.languages[1] - H.add_language(lang.type) - H.set_default_language(lang.type) - I.languages[lang.name] = 1 - - modify_servant(equip_servant(H), H) - set_antag(H.mind, master) - var/name_choice = sanitize(input(H, "Choose a name. If you leave this blank, it will be defaulted to your current characters.", "Name change") as null|text, MAX_NAME_LEN) - if(name_choice) - H.SetName(name_choice) - H.real_name = name_choice - -/datum/spellbound_type/proc/equip_servant(var/mob/living/human/H) - for(var/stype in spells) - var/spell/S = new stype() - if(S.spell_flags & NEEDSCLOTHES) - S.spell_flags &= ~NEEDSCLOTHES - H.add_spell(S) - . = list() - for(var/etype in equipment) - var/obj/item/I = new etype(get_turf(H)) - if(istype(I, /obj/item/clothing)) - I.canremove = 0 - H.equip_to_slot_if_possible(I,equipment[etype],0,1,1,1) - . += I - -/datum/spellbound_type/proc/set_antag(var/datum/mind/M, var/mob/master) - return - -/datum/spellbound_type/proc/modify_servant(var/list/items, var/mob/living/human/H) - return - -/datum/spellbound_type/apprentice - name = "Apprentice" - desc = "Summon your trusty apprentice, equipped with their very own spellbook." - equipment = list(/obj/item/clothing/head/wizard = slot_head_str, - /obj/item/clothing/jumpsuit/lightpurple = slot_w_uniform_str, - /obj/item/clothing/shoes/sandal = slot_shoes_str, - /obj/item/staff = BP_R_HAND, - /obj/item/book/spell/apprentice = BP_L_HAND, - /obj/item/clothing/suit/wizrobe = slot_wear_suit_str) - spells = list(/spell/noclothes) - -/datum/spellbound_type/apprentice/set_antag(var/datum/mind/M, var/mob/master) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - wizards.add_antagonist_mind(M, 1, "Wizard's Apprentice", "You are an apprentice-type Servant! You're just an ordinary Wizard-To-Be, with no special abilities, but do not need robes to cast spells. Follow your teacher's orders!") - -/datum/spellbound_type/servant - var/spiel = "You don't do anything in particular." - -/datum/spellbound_type/servant/set_antag(var/datum/mind/M, var/mob/master) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - wizards.add_antagonist_mind(M, 1, "Spellbound Servant", "You are a [name]-type Servant! [spiel]") - -/datum/spellbound_type/servant/caretaker - name = "Caretaker" - desc = "A healer, a medic, a shoulder to cry on. This servant will heal you, even from near death." - spiel = "'The last enemy that will be destroyed is death.' You can perceive any injuries with simple sight, and heal them with the Trance spell; potentially even reversing death itself! However, this comes at a price; Trance will become increasingly harder to use as you use it, until you can use it no longer. Be cautious, and aid your Master in any way possible!" - equipment = list(/obj/item/clothing/jumpsuit/caretaker = slot_w_uniform_str, - /obj/item/clothing/shoes/dress/caretakershoes = slot_shoes_str) - spells = list(/spell/toggle_armor/caretaker, - /spell/targeted/heal_target/touch, - /spell/aoe_turf/knock/slow, - /spell/targeted/heal_target/area/slow, - /spell/targeted/analyze, - /spell/targeted/heal_target/trance - ) - -/datum/spellbound_type/servant/champion - name = "Champion" - desc = "A knight in shining armor; a warrior, a protector, and a loyal friend." - spiel = "Your sword and armor are second to none, but you have no unique supernatural powers beyond summoning the sword to your hands. Protect your Master with your life!" - equipment = list( - /obj/item/clothing/pants/champion = slot_w_uniform_str, - /obj/item/clothing/shoes/jackboots/medievalboots = slot_shoes_str - ) - spells = list( - /spell/toggle_armor/champion, - /spell/toggle_armor/excalibur - ) - -/datum/spellbound_type/servant/familiar - name = "Familiar" - desc = "A friend! Or are they a pet? They can transform into animals, and take some particular traits from said creatures." - spiel = "This form of yours is weak in comparison to your transformed form, but that certainly won't pose a problem, considering the fact that you have an alternative. Whatever it is you can turn into, use its powers wisely and serve your Master as well as possible!" - equipment = list( - /obj/item/clothing/head/bandana/familiarband = slot_head_str, - /obj/item/clothing/pants/familiar = slot_w_uniform_str - ) - -/datum/spellbound_type/servant/familiar/modify_servant(var/list/equipment, var/mob/living/human/H) - var/familiar_type - switch(input(H,"Choose your desired animal form:", "Form") as anything in list("Space Pike", "Mouse", "Cat", "Bear")) - if("Space Pike") - H.add_genetic_condition(GENE_COND_NO_BREATH) - H.add_genetic_condition(GENE_COND_SPACE_RESISTANCE) - familiar_type = /mob/living/simple_animal/hostile/carp/pike - if("Mouse") - H.verbs |= /mob/living/proc/ventcrawl - familiar_type = /mob/living/simple_animal/passive/mouse - if("Cat") - H.add_genetic_condition(GENE_COND_RUNNING) - familiar_type = /mob/living/simple_animal/passive/cat - if("Bear") - familiar_type = /mob/living/simple_animal/hostile/bear - var/spell/targeted/shapeshift/familiar/F = new() - F.possible_transformations = list(familiar_type) - H.add_spell(F) - -/datum/spellbound_type/servant/fiend - name = "Fiend" - desc = "A practitioner of dark and evil magics, almost certainly a demon, and possibly a lawyer." - spiel = "The Summoning Ritual has bound you to this world with limited access to your infernal powers; you'll have to be strategic in how you use them. Follow your Master's orders as well as you can!" - spells = list(/spell/targeted/projectile/dumbfire/fireball/firebolt, - /spell/targeted/ethereal_jaunt, - /spell/targeted/torment, - /spell/area_teleport, - /spell/hand/charges/blood_shard - ) - -/datum/spellbound_type/servant/fiend/equip_servant(var/mob/living/human/H) - if(H.gender == MALE) - equipment = list(/obj/item/clothing/costume/fiendsuit = slot_w_uniform_str, - /obj/item/clothing/shoes/dress/devilshoes = slot_shoes_str) - spells += /spell/toggle_armor/fiend - else - equipment = list(/obj/item/clothing/dress/devil = slot_w_uniform_str, - /obj/item/clothing/shoes/dress/devilshoes = slot_shoes_str) - spells += /spell/toggle_armor/fiend/fem - ..() - -/datum/spellbound_type/servant/infiltrator - name = "Infiltrator" - desc = "A spy and a manipulator to the end, capable of hiding in plain sight and falsifying information to your heart's content." - spiel = "On the surface, you are a completely normal person, but is that really all you are? People are so easy to fool, do as your Master says, and do it with style!" - spells = list( - /spell/toggle_armor/infil_items, - /spell/targeted/exude_pleasantness, - /spell/targeted/genetic/blind/hysteria - ) - -/datum/spellbound_type/servant/infiltrator/equip_servant(var/mob/living/human/H) - if(H.gender == MALE) - equipment = list(/obj/item/clothing/pants/slacks/outfit/tie = slot_w_uniform_str, - /obj/item/clothing/shoes/dress/infilshoes = slot_shoes_str) - spells += /spell/toggle_armor/infiltrator - else - equipment = list(/obj/item/clothing/dress/white = slot_w_uniform_str, - /obj/item/clothing/shoes/dress/infilshoes = slot_shoes_str) - spells += /spell/toggle_armor/infiltrator/fem - ..() - -/datum/spellbound_type/servant/overseer - name = "Overseer" - desc = "A ghost, or an imaginary friend; the Overseer is immune to space and can turn invisible at a whim, but has little offensive capabilities." - spiel = "Physicality is not something you are familiar with. Indeed, injuries cannot slow you down, but you can't fight back, either! In addition to this, you can reach into the void and return the soul of a single departed crewmember via the revoke death verb, if so desired; this can even revive your Master, should they fall in combat before you do. Serve them well." - equipment = list( - /obj/item/clothing/pants/casual/blackjeans/outfit = slot_w_uniform_str, - /obj/item/clothing/suit/jacket/hoodie/grim = slot_wear_suit_str, - /obj/item/clothing/shoes/sandal/grimboots = slot_shoes_str, - /obj/item/contract/wizard/xray = BP_L_HAND, - /obj/item/contract/wizard/telepathy = BP_R_HAND - ) - spells = list( - /spell/toggle_armor/overseer, - /spell/targeted/ethereal_jaunt, - /spell/invisibility, - /spell/targeted/revoke - ) - -/datum/spellbound_type/servant/overseer/equip_servant(var/mob/living/human/H) - ..() - H.add_aura(new /obj/aura/regenerating(H)) - -/obj/effect/cleanable/spellbound - name = "strange rune" - desc = "some sort of runic symbol drawn in... crayon?" - icon = 'icons/obj/rune.dmi' - icon_state = "spellbound" - is_spawnable_type = FALSE // invalid without spell_type passed - var/datum/spellbound_type/stype - var/last_called = 0 - -/obj/effect/cleanable/spellbound/Initialize(mapload, var/spell_type) - . = ..(mapload) - stype = new spell_type() - -/obj/effect/cleanable/spellbound/attack_hand(var/mob/user) - SHOULD_CALL_PARENT(FALSE) - if(last_called > world.time) - return TRUE - last_called = world.time + 30 SECONDS - var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/wizard_familiar) - for(var/mob/observer/ghost/ghost in global.player_list) - if(G.assess_candidate(ghost,null,FALSE)) - to_chat(ghost, "[SPAN_NOTICE("A wizard is requesting a Spell-Bound Servant!")] (Join)") - return TRUE - -/obj/effect/cleanable/spellbound/CanUseTopic(var/mob) - if(isliving(mob)) - return STATUS_CLOSE - return STATUS_INTERACTIVE - -/obj/effect/cleanable/spellbound/OnTopic(var/mob/user, href_list, state) - if(href_list["master"]) - var/mob/master = locate(href_list["master"]) - stype.spawn_servant(get_turf(src),master,user) - qdel(src) - return TOPIC_HANDLED - -/obj/effect/cleanable/spellbound/Destroy() - qdel(stype) - stype = null - return ..() - -/obj/item/summoning_stone - name = "summoning stone" - desc = "a small non-descript stone of dubious origin." - icon = 'icons/obj/items/summoning_stone.dmi' - icon_state = "stone" - throw_speed = 5 - throw_range = 10 - w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/stone/basalt - -/obj/item/summoning_stone/attack_self(var/mob/user) - if(isAdminLevel(user.z)) - to_chat(user, "You cannot use \the [src] here.") - return - user.set_machine(src) - interact(user) - -/obj/item/summoning_stone/interact(var/mob/user) - var/list/types = subtypesof(/datum/spellbound_type) - /datum/spellbound_type/servant - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if(user.mind && !wizards.is_antagonist(user.mind)) - use_type(pick(types),user) - return - var/dat = "

Summoning Stone

Choose a companion to help you.

" - for(var/type in types) - var/datum/spellbound_type/SB = type - dat += "
[initial(SB.name)] - [initial(SB.desc)]" - show_browser(user,dat,"window=summoning") - onclose(user,"summoning") - -/obj/item/summoning_stone/proc/use_type(var/type, var/mob/user) - new /obj/effect/cleanable/spellbound(get_turf(src),type) - if(prob(20)) - var/list/base_areas = maintlocs //Have to do it this way as its a macro - var/list/pareas = base_areas.Copy() - while(pareas.len) - var/a = pick(pareas) - var/area/picked_area = pareas[a] - pareas -= a - var/list/turfs = get_area_turfs(picked_area) - for(var/t in turfs) - var/turf/T = t - if(T.density) - turfs -= T - if(turfs.len) - src.visible_message("\The [src] vanishes!") - src.forceMove(pick(turfs)) - show_browser(user, null, "window=summoning") - qdel(src) - -/obj/item/summoning_stone/OnTopic(user, href_list, state) - if(href_list["type"]) - use_type(href_list["type"],user) - return TOPIC_HANDLED \ No newline at end of file diff --git a/code/modules/spells/artifacts/storage.dm b/code/modules/spells/artifacts/storage.dm deleted file mode 100644 index 4d84cab7d3d5..000000000000 --- a/code/modules/spells/artifacts/storage.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/structure/closet/wizard - name = "artifact closet" - desc = "a special lead lined closet used to hold artifacts of immense power." - closet_appearance = /decl/closet_appearance/alien - -/obj/structure/closet/wizard/Initialize() - . = ..() - new /obj/item/parcel(get_turf(src), null, src, "Imported straight from the Wizard Acadamy. Do not lose the contents or suffer a demerit.") - -/obj/structure/closet/wizard/armor - name = "Mastercrafted Armor Set" - desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space." - -/obj/structure/closet/wizard/armor/WillContain() - return list( - /obj/item/clothing/shoes/sandal, - /obj/item/clothing/gloves/wizard, - /obj/item/clothing/suit/space/void/wizard, - /obj/item/clothing/head/helmet/space/void/wizard - ) - -/obj/structure/closet/wizard/scrying - name = "Scrying Orb" - desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to reconnoiter with ease. In addition, buying it will permanently grant you x-ray vision." - -/obj/structure/closet/wizard/scrying/WillContain() - return list( - /obj/item/scrying, - /obj/item/contract/wizard/xray, - ) \ No newline at end of file diff --git a/code/modules/spells/contracts.dm b/code/modules/spells/contracts.dm deleted file mode 100644 index 1b6ebf527f7e..000000000000 --- a/code/modules/spells/contracts.dm +++ /dev/null @@ -1,142 +0,0 @@ -/obj/item/contract - name = "contract" - desc = "written in the blood of some unfortunate fellow." - icon = 'icons/mob/screen/spells.dmi' - icon_state = "master_open" - material = /decl/material/solid/organic/paper - var/contract_master = null - var/list/contract_spells = list(/spell/contract/reward,/spell/contract/punish,/spell/contract/return_master) - -/obj/item/contract/attack_self(mob/user) - if(contract_master == null) - to_chat(user, "You bind the contract to your soul, making you the recipient of whatever poor fool's soul that decides to contract with you.") - contract_master = user - return - - if(contract_master == user) - to_chat(user, "You can't contract with yourself!") - return - - var/ans = alert(user,"The contract clearly states that signing this contract will bind your soul to \the [contract_master]. Are you sure you want to continue?","[src]","Yes","No") - - if(ans == "Yes") - user.visible_message("\The [user] signs the contract, their body glowing a deep yellow.") - if(!src.contract_effect(user)) - user.visible_message("\The [src] visibly rejects \the [user], erasing their signature from the line.") - return - user.visible_message("\The [src] disappears with a flash of light.") - if(contract_spells.len && isliving(contract_master)) //if it aint text its probably a mob or another user - var/mob/living/M = contract_master - for(var/spell_type in contract_spells) - M.add_spell(new spell_type(user), "const_spell_ready") - log_and_message_admins("signed their soul over to \the [contract_master] using \the [src].", user) - qdel(src) - -/obj/item/contract/proc/contract_effect(mob/user) - to_chat(user, "You've signed your soul over to \the [contract_master] and with that your unbreakable vow of servitude begins.") - return 1 - -/obj/item/contract/apprentice - name = "apprentice wizarding contract" - desc = "a wizarding school contract for those who want to sign their soul for a piece of the magic pie." - color = "#993300" - -/obj/item/contract/apprentice/contract_effect(mob/user) - if(user.mind.assigned_special_role == "Wizard's Apprentice") - to_chat(user, "You are already a wizarding apprentice!") - return 0 - if(user.mind.assigned_special_role == "Spellbound Servant") - to_chat(user, "You are a servant. You have no need of apprenticeship.") - return 0 - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - if(wizards.add_antagonist_mind(user.mind, 1, "Wizard's Apprentice", "You are an apprentice! Your job is to learn the wizarding arts!")) - to_chat(user, "With the signing of this paper you agree to become \the [contract_master]'s apprentice in the art of wizardry.") - return 1 - return 0 - -/obj/item/contract/wizard //contracts that involve making a deal with the Wizard Acadamy (or NON PLAYERS) - contract_master = "\improper Wizard Academy" - -/obj/item/contract/wizard/xray - name = "xray vision contract" - desc = "This contract is almost see-through..." - color = "#339900" - -/obj/item/contract/wizard/xray/contract_effect(mob/user) - ..() - if (user.add_genetic_condition(GENE_COND_XRAY)) - user.set_sight(user.sight|SEE_MOBS|SEE_OBJS|SEE_TURFS) - user.set_see_in_dark(8) - user.set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) - to_chat(user, "The walls suddenly disappear.") - return 1 - return 0 - -/obj/item/contract/wizard/telepathy - name = "telepathy contract" - desc = "The edges of the contract grow blurry when you look away from them. To be fair, actually reading it gives you a headache." - color = "#fcc605" - -/obj/item/contract/wizard/telepathy/contract_effect(mob/user) - ..() - return user.add_genetic_condition(GENE_COND_REMOTE_TALK) - -/obj/item/contract/boon - name = "boon contract" - desc = "this contract grants you a boon for signing it." - var/path - -/obj/item/contract/boon/Initialize(mapload, var/new_path) - . = ..(mapload) - if(new_path) - path = new_path - var/item_name = "" - if(ispath(path,/obj)) - var/obj/O = path - item_name = initial(O.name) - else if(ispath(path,/spell)) - var/spell/S = path - item_name = initial(S.name) - name = "[item_name] contract" - -/obj/item/contract/boon/contract_effect(mob/user) - ..() - if(user.mind.assigned_special_role == "Spellbound Servant") - to_chat(user, "As a servant you find yourself unable to use this contract.") - return 0 - if(ispath(path,/spell)) - user.add_spell(new path) - return 1 - else if(ispath(path,/obj)) - new path(get_turf(user.loc)) - playsound(get_turf(usr),'sound/magic/charge.ogg',50,1) - return 1 - -/obj/item/contract/boon/wizard - contract_master = "\improper Wizard Academy" - -/obj/item/contract/boon/wizard/fireball - path = /spell/targeted/projectile/dumbfire/fireball - desc = "This contract feels warm to the touch." - -/obj/item/contract/boon/wizard/smoke - path = /spell/aoe_turf/smoke - desc = "This contract smells as dank as they come." - -/obj/item/contract/boon/wizard/forcewall - path = /spell/aoe_turf/conjure/forcewall - contract_master = "\improper Mime Federation" - desc = "This contract has a dedication to mimes everywhere at the top." - -/obj/item/contract/boon/wizard/knock - path = /spell/aoe_turf/knock - desc = "This contract is hard to hold still." - -/obj/item/contract/boon/wizard/horsemask - path = /spell/targeted/equip_item/horsemask - desc = "This contract is more horse than your mind has room for." - -/obj/item/contract/boon/wizard/charge - path = /spell/aoe_turf/charge - desc = "This contract is made of 100% post-consumer wizard." - diff --git a/code/modules/spells/general/acid_spray.dm b/code/modules/spells/general/acid_spray.dm deleted file mode 100644 index 752a17eecb72..000000000000 --- a/code/modules/spells/general/acid_spray.dm +++ /dev/null @@ -1,26 +0,0 @@ -/spell/acid_spray - name = "Acid Spray" - desc = "A common spell used to destroy basically anything in front of the wizard." - school = "conjuration" - feedback = "as" - spell_flags = 0 - charge_max = 600 - - invocation = "Tagopar lethodar!" - invocation_type = SpI_SHOUT - var/reagent_type = /decl/material/liquid/acid/hydrochloric - hud_state = "wiz_acid" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/acid_spray/choose_targets() - return list(holder) - -/spell/acid_spray/cast(var/list/targets, var/mob/user) - var/atom/target = targets[1] - var/angle = dir2angle(target.dir) - for(var/mod in list(315, 0, 45)) - var/obj/effect/effect/water/chempuff/chem = new(get_turf(target)) - chem.create_reagents(10) - chem.add_to_reagents(reagent_type,10) - spawn(0) - chem.set_up(get_ranged_target_turf(target, angle2dir(angle+mod), 3)) diff --git a/code/modules/spells/general/area_teleport.dm b/code/modules/spells/general/area_teleport.dm deleted file mode 100644 index 68e20f3d6f9a..000000000000 --- a/code/modules/spells/general/area_teleport.dm +++ /dev/null @@ -1,60 +0,0 @@ -/spell/area_teleport - name = "Teleport" - desc = "This spell teleports you to a type of area of your selection." - feedback = "TP" - school = "conjuration" - charge_max = 60 SECONDS - spell_flags = NEEDSCLOTHES - invocation = "Scyar Nila!" - invocation_type = SpI_SHOUT - cooldown_min = 200 //100 deciseconds reduction per rank - - smoke_spread = 1 - smoke_amt = 5 - - var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list - var/invocation_area = 1 //if the invocation appends the selected area - - cast_sound = 'sound/effects/teleport.ogg' - - hud_state = "wiz_tele" - -/spell/area_teleport/before_cast() - return - -/spell/area_teleport/choose_targets() - var/area/thearea - if(!randomise_selection) - thearea = input("Area to teleport to", "Teleport") as null|anything in wizteleportlocs - if(!thearea) - return - else - thearea = pick(wizteleportlocs) - return list(wizteleportlocs[thearea]) - -/spell/area_teleport/cast(area/thearea, mob/user) - playsound(get_turf(user),cast_sound,50,1) - var/turf/end = user.try_teleport(thearea) - - if(!end) - to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") - return - return - -/spell/area_teleport/check_valid_targets(list/targets) - // Teleport should function across z's, so we make sure that happens - // without this check, it only works for teleporting to areas you can see - return islist(targets) && length(targets) - -/spell/area_teleport/after_cast() - return - -/spell/area_teleport/invocation(mob/user, area/chosenarea) - if(!istype(chosenarea)) - return //can't have that, can we - if(!invocation_area || !chosenarea) - ..() - else - invocation += "[uppertext(chosenarea.proper_name)]" - ..() - return diff --git a/code/modules/spells/general/camera_vision.dm b/code/modules/spells/general/camera_vision.dm deleted file mode 100644 index cfd0cfb030e2..000000000000 --- a/code/modules/spells/general/camera_vision.dm +++ /dev/null @@ -1,36 +0,0 @@ -/spell/camera_connection - name = "Camera Connection" - desc = "This spell allows the wizard to connect to the local camera network and see what it sees." - - school = "racial" - - invocation_type = SpI_EMOTE - invocation = "emits a beeping sound before standing very, very still." - - charge_max = 600 //1 minute - charge_type = Sp_RECHARGE - - - spell_flags = Z2NOCAST - hud_state = "wiz_IPC" - - var/extension_type = /datum/extension/eye/cameranet - -/spell/camera_connection/New() - ..() - set_extension(src, extension_type) - -/spell/camera_connection/choose_targets() - var/mob/living/L = holder - if(!istype(L) || L.eyeobj) //no using if we already have an eye on. - return null - return list(holder) - -/spell/camera_connection/cast(var/list/targets, mob/user) - var/mob/living/L = targets[1] - - var/datum/extension/eye/cameranet/cn = get_extension(src, /datum/extension/eye/) - if(!cn) - to_chat(user, SPAN_WARNING("There's a flash of sparks as the spell fizzles out!")) - return - cn.look(L) \ No newline at end of file diff --git a/code/modules/spells/general/contract_spells.dm b/code/modules/spells/general/contract_spells.dm deleted file mode 100644 index fa95cd16e23c..000000000000 --- a/code/modules/spells/general/contract_spells.dm +++ /dev/null @@ -1,68 +0,0 @@ -//These spells are given to the owner of a contract when a victim signs it. -//As such they are REALLY REALLY powerful (because the victim is rewarded for signing it, and signing contracts is completely voluntary) - -/spell/contract - name = "Contract Spell" - desc = "A spell perfecting the techniques of keeping a servant happy and obedient." - - school = "transmutation" - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - - - var/mob/subject - -/spell/contract/New(var/mob/M) - ..() - subject = M - name += " ([M.real_name])" - -/spell/contract/choose_targets() - return list(subject) - -/spell/contract/cast(mob/target,mob/user) - if(!subject) - to_chat(usr, "This spell was not properly given a target. Contact a coder.") - return null - - if(istype(target,/list)) - var/list/target_list = target - target = target_list[1] - return target - - -/spell/contract/reward - name = "Reward Contractee" - desc = "A spell that makes your contracted victim feel better." - - charge_max = 300 - cooldown_min = 100 - - hud_state = "wiz_jaunt_old" - -/spell/contract/reward/cast(mob/living/target,mob/user) - target = ..(target,user) - if(!target) - return - - to_chat(target, SPAN_BLUE("You feel great!")) - target.ExtinguishMob() - -/spell/contract/punish - name = "Punish Contractee" - desc = "A spell that sets your contracted victim ablaze." - - charge_max = 300 - cooldown_min = 100 - - hud_state = "gen_immolate" - -/spell/contract/punish/cast(mob/living/target,mob/user) - target = ..(target,user) - if(!target) - return - - to_chat(target, "You feel punished!") - target.fire_stacks += 15 - target.IgniteMob() \ No newline at end of file diff --git a/code/modules/spells/general/create_air.dm b/code/modules/spells/general/create_air.dm deleted file mode 100644 index 405e161a54a9..000000000000 --- a/code/modules/spells/general/create_air.dm +++ /dev/null @@ -1,24 +0,0 @@ -/spell/create_air - name = "Create Air" - desc = "A much used spell used in the vasteness of space to make it not so killey." - - charge_max = 200 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "wiz_air" - var/list/air_change = list(/decl/material/gas/oxygen = ONE_ATMOSPHERE) - -/spell/create_air/choose_targets() - var/air = holder.return_air() - if(air) - return list(air) - return null - -/spell/create_air/cast(var/list/targets, var/mob/holder, var/channel_count) - var/datum/gas_mixture/environment = targets[1] - for(var/gas in air_change) - environment.adjust_gas(gas, air_change[gas]) diff --git a/code/modules/spells/general/invisibility.dm b/code/modules/spells/general/invisibility.dm deleted file mode 100644 index 3fbab715efd1..000000000000 --- a/code/modules/spells/general/invisibility.dm +++ /dev/null @@ -1,24 +0,0 @@ -/spell/invisibility - name = "invisibility" - desc = "A simple spell of invisibility, for when you really just can't afford a paper bag." - feedback = "IV" - spell_flags = 0 - charge_max = 100 - invocation = "Ror Rim Or!" - invocation_type = SpI_SHOUT - var/on = 0 - hud_state = "invisibility" - -/spell/invisibility/choose_targets() - if(ishuman(holder)) - return holder - -/spell/invisibility/cast(var/mob/living/human/H, var/mob/user) - on = !on - if(on) - if(H.add_cloaking_source(src)) - playsound(get_turf(H), 'sound/effects/teleport.ogg', 90, 1) - H.add_genetic_condition(GENE_COND_CLUMSY) - else if(H.remove_cloaking_source(src)) - playsound(get_turf(H), 'sound/effects/stealthoff.ogg', 90, 1) - H.remove_genetic_condition(GENE_COND_CLUMSY) \ No newline at end of file diff --git a/code/modules/spells/general/mark_recall.dm b/code/modules/spells/general/mark_recall.dm deleted file mode 100644 index 11131e72ece2..000000000000 --- a/code/modules/spells/general/mark_recall.dm +++ /dev/null @@ -1,88 +0,0 @@ -/spell/mark_recall - name = "Mark and Recall" - desc = "This spell was created so wizards could get home from the bar without driving. Does not require wizard garb." - feedback = "MK" - school = "conjuration" - charge_max = 600 //1 minutes for how OP this shit is (apparently not as op as I thought) - spell_flags = Z2NOCAST - invocation = "Re-Alki R'natha." - invocation_type = SpI_WHISPER - cooldown_min = 300 - - smoke_amt = 1 - smoke_spread = 5 - - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - - cast_sound = 'sound/effects/teleport.ogg' - hud_state = "wiz_mark" - var/mark = null - -/spell/mark_recall/choose_targets() - if(!mark) - return list("magical fairy dust") //because why not - else - return list(mark) - -/spell/mark_recall/cast(var/list/targets,mob/user) - if(!targets.len) - return 0 - var/target = targets[1] - if(istext(target)) - mark = new /obj/effect/cleanable/wizard_mark(get_turf(user),src) - return 1 - if(!istype(target,/obj)) //something went wrong - return 0 - var/turf/T = get_turf(target) - if(!T) - return 0 - user.forceMove(T) - ..() - -/spell/mark_recall/empower_spell() - if(!..()) - return 0 - - spell_flags = NO_SOMATIC - - return "You will always be able to cast this spell, even while unconscious or handcuffed." - -/obj/effect/cleanable/wizard_mark - name = "\improper Mark of the Wizard" - desc = "A strange rune said to be made by wizards. Or its just some shmuck playing with crayons again." - icon = 'icons/obj/rune.dmi' - icon_state = "wizard_mark" - anchored = TRUE - layer = TURF_LAYER - is_spawnable_type = FALSE // invalid without spell passed - var/spell/mark_recall/spell - -/obj/effect/cleanable/wizard_mark/Initialize(mapload,var/mrspell) - . = ..() - spell = mrspell - -/obj/effect/cleanable/wizard_mark/Destroy() - spell.mark = null //dereference pls. - spell = null - return ..() - -/obj/effect/cleanable/wizard_mark/attack_hand(var/mob/user) - if(user != spell.holder) - return ..() - user.visible_message("\The [user] mutters an incantation and \the [src] disappears!") - qdel(src) - return TRUE - -/obj/effect/cleanable/wizard_mark/nullrod_act(mob/user, obj/item/nullrod/rod) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - visible_message("\The [user] dispels \the [src] and it fades away!") - qdel(src) - return TRUE - -/obj/effect/cleanable/wizard_mark/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/book/spell)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - visible_message("\The [src] fades away!") - qdel(src) - return TRUE - return ..() \ No newline at end of file diff --git a/code/modules/spells/general/portal_teleport.dm b/code/modules/spells/general/portal_teleport.dm deleted file mode 100644 index 1f1ed0ad603b..000000000000 --- a/code/modules/spells/general/portal_teleport.dm +++ /dev/null @@ -1,67 +0,0 @@ -/spell/portal_teleport - name = "Create Portal" - desc = "This spell creates a long lasting portal to an area of your selection." - feedback = "TP" - school = "conjuration" - spell_flags = NEEDSCLOTHES - invocation = "Scyar Peranda!" - invocation_type = SpI_SHOUT - charge_max = 30 MINUTES - cooldown_min = 25 MINUTES - - smoke_spread = 1 - smoke_amt = 5 - - var/list/select_areas = list() - - cast_sound = 'sound/effects/teleport.ogg' - - hud_state = "wiz_tele" - -/spell/portal_teleport/before_cast() - return - -/spell/portal_teleport/choose_targets() - var/area/thearea - var/message = alert("Would you like to show station areas?\nNote: it can take up to 5 minutes for the away sites to load in and show up.",, "Yes", "No") - switch(message) - if("Yes") - select_areas = stationlocs - if("No") - select_areas = (stationlocs) ^ (wizportallocs) - - thearea = input("Area to teleport to", "Teleport") as null|anything in select_areas - if(!thearea) return - - return list(select_areas[thearea]) - -/spell/portal_teleport/cast(area/thearea, mob/user) - playsound(get_turf(user),cast_sound,50,1) - var/turf/start = get_turf(user) - var/turf/end = user.try_teleport(thearea) - - if(!end) - to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") - return - - new /obj/effect/portal/wizard(start, end, 35 MINUTES) - new /obj/effect/portal/wizard(end, start, 35 MINUTES) - - return - -/spell/portal_teleport/after_cast() - return - -/spell/portal_teleport/invocation(mob/user, area/chosenarea) - if(!chosenarea || !istype(chosenarea)) - ..() - else - invocation += "[uppertext(chosenarea.proper_name)]" - ..() - return - -/obj/effect/portal/wizard - name = "dark anomaly" - desc = "It pulls on the edges of reality as if trying to draw them in." - icon = 'icons/obj/objects.dmi' - icon_state = "bhole3" diff --git a/code/modules/spells/general/radiant_aura.dm b/code/modules/spells/general/radiant_aura.dm deleted file mode 100644 index 27e85404027e..000000000000 --- a/code/modules/spells/general/radiant_aura.dm +++ /dev/null @@ -1,21 +0,0 @@ -/spell/radiant_aura - name = "Radiant aura" - desc = "Form a protective layer of light around you, making you immune to laser fire." - feedback = "ra" - invocation_type = SpI_EMOTE - invocation = "conjures a sphere of fire around themselves." - school = "conjuration" - spell_flags = NEEDSCLOTHES - charge_max = 300 - cooldown_min = 100 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 0) - cast_sound = 'sound/effects/snap.ogg' - duration = 40 - hud_state = "gen_immolate" - -/spell/radiant_aura/choose_targets() - return list(holder) - -/spell/radiant_aura/cast(var/list/targets, var/mob/user) - var/obj/aura/radiant_aura/A = new(user) - QDEL_IN(A,duration) diff --git a/code/modules/spells/general/return_master.dm b/code/modules/spells/general/return_master.dm deleted file mode 100644 index 119cc93804de..000000000000 --- a/code/modules/spells/general/return_master.dm +++ /dev/null @@ -1,23 +0,0 @@ -/spell/contract/return_master - name = "Return to Master" - desc = "Teleport back to your master" - - school = "conjuration" - charge_max = 600 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - cooldown_min = 200 - - smoke_spread = 1 - smoke_amt = 5 - - hud_state = "wiz_tele" - - -/spell/contract/return_master/cast(mob/target,mob/user) - target = ..(target,user) - if(!target) - return - - user.forceMove(get_turf(target)) \ No newline at end of file diff --git a/code/modules/spells/general/toggle_armor.dm b/code/modules/spells/general/toggle_armor.dm deleted file mode 100644 index 5da3bf537f83..000000000000 --- a/code/modules/spells/general/toggle_armor.dm +++ /dev/null @@ -1,121 +0,0 @@ -/spell/toggle_armor - name = "Toggle Armor" - spell_flags = 0 - charge_max = 10 - school = "Conjuration" - var/list/armor_pieces - var/equip = 0 - hud_state = "const_shell" - -/spell/toggle_armor/New() - if(armor_pieces) - var/list/nlist = list() - for(var/type in armor_pieces) - var/obj/item/I = new type(null) - nlist[I] = armor_pieces[type] - armor_pieces = nlist - return ..() - -/spell/toggle_armor/proc/drop_piece(var/obj/I) - if(ismob(I.loc)) - var/mob/M = I.loc - M.drop_from_inventory(I) - -/spell/toggle_armor/choose_targets() - return list(holder) - -/spell/toggle_armor/cast(var/list/targets, var/mob/user) - equip = !equip - name = "[initial(name)] ([equip ? "off" : "on"])" - if(equip) - for(var/piece in armor_pieces) - var/slot = armor_pieces[piece] - drop_piece(piece) - user.drop_from_inventory(user.get_equipped_item(slot)) - user.equip_to_slot_if_possible(piece,slot,0,1,1,1) - else - for(var/piece in armor_pieces) - var/obj/item/I = piece - drop_piece(piece) - I.forceMove(null) - -/spell/toggle_armor/greytide_worldwide - name = "Greytide Worldwide" - invocation_type = SpI_EMOTE - invocation = "screams incoherently!" - armor_pieces = list(/obj/item/clothing/jumpsuit/grey = slot_w_uniform_str, - /obj/item/clothing/gloves/insulated/cheap = slot_gloves_str, - /obj/item/clothing/mask/gas = slot_wear_mask_str, - /obj/item/clothing/shoes/color/black = slot_shoes_str, - /obj/item/toolbox/mechanical = BP_R_HAND, - /obj/item/chems/spray/extinguisher = BP_L_HAND) - -/spell/toggle_armor/caretaker - name = "Toggle Armor (Caretaker)" - invocation_type = SpI_EMOTE - invocation = "radiates a holy light" - armor_pieces = list(/obj/item/clothing/head/caretakerhood = slot_head_str, - /obj/item/clothing/suit/caretakercloak = slot_wear_suit_str - ) - hud_state = "caretaker" - -/spell/toggle_armor/champion - name = "Toggle Armor (Champion)" - invocation_type = SpI_EMOTE - invocation = "is covered in golden embers for a moment, before they fade" - armor_pieces = list(/obj/item/clothing/head/champhelm = slot_head_str, - /obj/item/clothing/suit/champarmor = slot_wear_suit_str - ) - hud_state = "champion" - -/spell/toggle_armor/excalibur - name = "Toggle Sword" - invocation_type = SpI_EMOTE - invocation = "thrusts /his hand forward, and it is enveloped in golden embers!" - armor_pieces = list(/obj/item/sword/excalibur = BP_R_HAND) - hud_state = "excalibur" - -/spell/toggle_armor/fiend - name = "Toggle Armor (Fiend)" - invocation_type = SpI_EMOTE - invocation = "snaps /his fingers, and /his clothes begin to shift and change" - armor_pieces = list(/obj/item/clothing/head/fiendhood = slot_head_str, - /obj/item/clothing/suit/fiendcowl = slot_wear_suit_str - ) - hud_state = "fiend" - -/spell/toggle_armor/fiend/fem - armor_pieces = list(/obj/item/clothing/head/fiendhood/fem = slot_head_str, - /obj/item/clothing/suit/fiendcowl/fem = slot_wear_suit_str - ) - -/spell/toggle_armor/infiltrator - name = "Toggle Armor (Infiltrator)" - invocation_type = SpI_EMOTE - invocation = "winks. In an instant, /his clothes change dramatically" - armor_pieces = list(/obj/item/clothing/head/infilhat = slot_head_str, - /obj/item/clothing/suit/infilsuit = slot_wear_suit_str - ) - hud_state = "infiltrator" - -/spell/toggle_armor/infiltrator/fem - armor_pieces = list(/obj/item/clothing/head/infilhat/fem = slot_head_str, - /obj/item/clothing/suit/infilsuit/fem = slot_wear_suit_str - ) - -/spell/toggle_armor/infil_items - name = "Toggle Counterfeit Kit" - invocation_type = SpI_EMOTE - invocation = "flicks /his wrists, one at a time" - armor_pieces = list(/obj/item/stamp/chameleon = BP_L_HAND, - /obj/item/pen/chameleon = BP_R_HAND) - hud_state = "forgery" - -/spell/toggle_armor/overseer - name = "Toggle Armor (Overseer)" - invocation_type = SpI_EMOTE - invocation = " is enveloped in shadows, before /his form begins to shift rapidly" - armor_pieces = list(/obj/item/clothing/head/overseerhood = slot_head_str, - /obj/item/clothing/suit/straight_jacket/overseercloak = slot_wear_suit_str - ) - hud_state = "overseer" \ No newline at end of file diff --git a/code/modules/spells/hand/blood_shards.dm b/code/modules/spells/hand/blood_shards.dm deleted file mode 100644 index 0908ee285201..000000000000 --- a/code/modules/spells/hand/blood_shards.dm +++ /dev/null @@ -1,39 +0,0 @@ -/spell/hand/charges/blood_shard - name = "Blood Shards" - desc = "Invoke a corrupted projectile forward that causes an enemy's blood to fly out in painful shards. Anyone hit by this will have their blood explode out of them in a spray of smaller shards. Stores two charges." - spell_flags = 0 - charge_max = 600 - invocation = "opens their hand, which bursts into vicious red light." - invocation_type = SpI_EMOTE - - range = 7 - max_casts = 2 - compatible_targets = list(/atom) - hud_state = "wiz_bshard" - cast_sound = 'sound/magic/demon_attack1.ogg' - -/spell/hand/charges/blood_shard/cast_hand(var/atom/A,var/mob/user) - var/obj/item/projectile/blood_shard/B = new(get_turf(user)) - B.firer = user - B.launch(A, BP_CHEST) - user.visible_message("\The [user] shoots out a deep red shard from their hand!") - return ..() - -/obj/item/projectile/blood_shard - name = "bloodshard" - damage = 25 - icon_state = "blood" - atom_damage_type = BRUTE - damage_flags = 0 - -/obj/item/projectile/blood_shard/on_hit(var/atom/movable/target, var/blocked = 0) - if(..()) - if(ishuman(target)) - var/mob/living/human/H = target - H.vessel.remove_any(30) - H.visible_message("Tiny red shards burst from \the [H]'s skin!") - fragmentate(get_turf(src), 30, 5, list(/obj/item/projectile/bullet/pellet/blood)) - -/obj/item/projectile/bullet/pellet/blood - name = "blood fragment" - damage = 10 \ No newline at end of file diff --git a/code/modules/spells/hand/burning_grip.dm b/code/modules/spells/hand/burning_grip.dm deleted file mode 100644 index 772b4e6aa9c4..000000000000 --- a/code/modules/spells/hand/burning_grip.dm +++ /dev/null @@ -1,39 +0,0 @@ -/spell/hand/burning_grip - name = "Burning Grip" - desc = "Cause someone to drop a held object by causing it to heat up intensly." - school = "transmutation" - feedback = "bg" - range = 5 - spell_flags = 0 - invocation_type = SpI_NONE - show_message = " throws sparks from their hands" - spell_delay = 120 - hud_state = "wiz_burn" - cast_sound = 'sound/magic/fireball.ogg' - compatible_targets = list(/mob/living/human) - -/spell/hand/burning_grip/valid_target(var/mob/living/L, var/mob/user) - if(!..()) - return 0 - if(length(L.get_held_items())) - return 0 - return 1 - -/spell/hand/burning_grip/cast_hand(var/mob/living/human/H, var/mob/user) - var/list/targets = list() - for(var/hand_slot in H.get_held_item_slots()) - targets |= hand_slot - - var/obj/O = new /obj/effect/temporary(get_turf(H),3, 'icons/effects/effects.dmi', "fire_goon") - O.alpha = 150 - - for(var/organ in targets) - var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, organ) - if(!E) - continue - E.take_external_damage(burn=10, used_weapon = "hot iron") - if(E.can_feel_pain()) - E.check_pain_disarm() - else - E.take_external_damage(burn=6, used_weapon = "hot iron") - to_chat(H, SPAN_WARNING("You notice that your [E] is burned.")) diff --git a/code/modules/spells/hand/entangle.dm b/code/modules/spells/hand/entangle.dm deleted file mode 100644 index 37a4776fe28e..000000000000 --- a/code/modules/spells/hand/entangle.dm +++ /dev/null @@ -1,51 +0,0 @@ -/spell/hand/charges/entangle - name = "Entangle" - desc = "This spell creates vines that immediately entangle a nearby victim." - feedback = "ET" - school = "transmutation" - charge_max = 600 - spell_flags = NEEDSCLOTHES | SELECTABLE | IGNOREPREV - invocation = "Bu-Ekel'Inas!" - invocation_type = SpI_SHOUT - range = 3 - max_casts = 1 - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - cooldown_min = 300 - duration = 30 - compatible_targets = list(/mob) - - hud_state = "wiz_entangle" - cast_sound = 'sound/magic/staff_door.ogg' - show_message = " points towards the ground, causing plants to erupt" - var/datum/seed/seed - -/spell/hand/charges/entangle/New() - ..() - seed = new() - seed.set_trait(TRAIT_PLANT_ICON,"flower") - seed.set_trait(TRAIT_PRODUCT_ICON,"flower2") - seed.set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") - seed.set_trait(TRAIT_SPREAD,2) - seed.name = "heirlooms" - seed.product_name = "heirloom" - seed.display_name = "vines" - seed.chems = list(/decl/material/liquid/nutriment = list(1,20)) - -/spell/hand/charges/entangle/cast_hand(var/mob/M,var/mob/user) - var/turf/T = get_turf(M) - var/obj/effect/vine/single/P = new(T, seed, null, TRUE) - P.can_buckle = 1 - - P.buckle_mob(M) - M.set_dir(pick(global.cardinal)) - M.visible_message("[P] appear from the floor, spinning around \the [M] tightly!") - return ..() - -/spell/hand/charges/entangle/empower_spell() - if(!..()) - return 0 - - max_casts++ - - return "This spell will now entangle [max_casts] times before running out." \ No newline at end of file diff --git a/code/modules/spells/hand/hand.dm b/code/modules/spells/hand/hand.dm deleted file mode 100644 index 9652cf1cce18..000000000000 --- a/code/modules/spells/hand/hand.dm +++ /dev/null @@ -1,83 +0,0 @@ -/spell/hand - var/min_range = 0 - var/list/compatible_targets = list(/atom) - var/spell_delay = 5 - var/move_delay - var/click_delay - var/hand_state = "spell" - var/obj/item/magic_hand/current_hand - var/show_message - -/spell/hand/choose_targets(mob/user = usr) - return list(user) - -/spell/hand/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) - if(!..()) - return FALSE - if(user.get_active_held_item()) - to_chat(holder, "You need an empty hand to cast this spell.") - return FALSE - return TRUE - -/spell/hand/cast(list/targets, mob/user) - if(current_hand) - cancel_hand() - if(user.get_active_held_item()) - to_chat(user, "You need an empty hand to cast this spell.") - return FALSE - current_hand = new(null, src) - if(!user.put_in_active_hand(current_hand)) - QDEL_NULL(current_hand) - return FALSE - return TRUE - -/spell/hand/proc/cancel_hand() - if(!QDELETED(current_hand)) - QDEL_NULL(current_hand) - -/spell/hand/Destroy() - QDEL_NULL(current_hand) - . = ..() - -/spell/hand/proc/valid_target(var/atom/a,var/mob/user) //we use seperate procs for our target checking for the hand spells. - var/distance = get_dist(a,user) - if((min_range && distance < min_range) || (range && distance > range)) - return FALSE - if(!is_type_in_list(a,compatible_targets)) - return FALSE - return TRUE - -/spell/hand/proc/cast_hand(var/atom/a,var/mob/user) //same for casting. - return TRUE - -/spell/hand/charges - var/casts = 1 - var/max_casts = 1 - -/spell/hand/charges/cast(list/targets, mob/user) - . = ..() - if(.) - casts = max_casts - to_chat(user, "You ready the [name] spell ([casts]/[casts] charges).") - -/spell/hand/charges/cast_hand() - if(..()) - casts-- - to_chat(holder, SPAN_NOTICE("The [name] spell has [casts] out of [max_casts] charges left.")) - cancel_hand() - return TRUE - return FALSE - -/spell/hand/duration - var/hand_timer = null - var/hand_duration = 0 - -/spell/hand/duration/cast(var/list/targets, var/mob/user) - . = ..() - if(.) - hand_timer = addtimer(CALLBACK(src, PROC_REF(cancel_hand)), hand_duration, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) - -/spell/hand/duration/cancel_hand() - deltimer(hand_timer) - hand_timer = null - ..() \ No newline at end of file diff --git a/code/modules/spells/hand/hand_item.dm b/code/modules/spells/hand/hand_item.dm deleted file mode 100644 index 6141577f2471..000000000000 --- a/code/modules/spells/hand/hand_item.dm +++ /dev/null @@ -1,68 +0,0 @@ -/*much like grab this item is used primarily for the utility it provides. -Basically: I can use it to target things where I click. I can then pass these targets to a spell and target things not using a list. -*/ - -/obj/item/magic_hand - name = "Magic Hand" - icon = 'icons/mob/screen/spells.dmi' - atom_flags = 0 - item_flags = 0 - obj_flags = 0 - simulated = 0 - icon_state = "spell" - max_health = ITEM_HEALTH_NO_DAMAGE - is_spawnable_type = FALSE - obj_flags = OBJ_FLAG_NO_STORAGE - var/next_spell_time = 0 - var/spell/hand/hand_spell - -/obj/item/magic_hand/Initialize(ml, _hand_spell) - . = ..() - hand_spell = _hand_spell - name = "[name] ([hand_spell.name])" - icon_state = hand_spell.hand_state - -// These return values do not look correct... -/obj/item/magic_hand/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) - if(hand_spell && hand_spell.valid_target(target, user)) - fire_spell(target, user) - return FALSE - return TRUE - -/obj/item/magic_hand/proc/fire_spell(var/atom/A, mob/living/user) - if(!hand_spell) //no spell? Die. - user.drop_from_inventory(src) - - if(!hand_spell.valid_target(A,user)) - return - if(world.time < next_spell_time) - to_chat(user, "The spell isn't ready yet!") - return - if(user.check_intent(I_FLAG_HELP)) - to_chat(user, "You decide against casting this spell as your intent is set to help.") - return - - if(hand_spell.show_message) - user.visible_message("\The [user][hand_spell.show_message]") - if(hand_spell.cast_hand(A,user)) - next_spell_time = world.time + hand_spell.spell_delay - if(hand_spell.move_delay) - user.ExtraMoveCooldown(hand_spell.move_delay) - if(hand_spell.click_delay) - user.setClickCooldown(hand_spell.move_delay) - -/obj/item/magic_hand/afterattack(var/atom/A, var/mob/user, var/proximity) - if(hand_spell) - fire_spell(A,user) - -/obj/item/magic_hand/throw_at() //no throwing pls - usr.drop_from_inventory(src) - -/obj/item/magic_hand/dropped() //gets deleted on drop - ..() - qdel(src) - -/obj/item/magic_hand/Destroy() //better save than sorry. - hand_spell.current_hand = null - hand_spell = null - . = ..() \ No newline at end of file diff --git a/code/modules/spells/hand/slippery_surface.dm b/code/modules/spells/hand/slippery_surface.dm deleted file mode 100644 index 3b5fc448d034..000000000000 --- a/code/modules/spells/hand/slippery_surface.dm +++ /dev/null @@ -1,19 +0,0 @@ -/spell/hand/slippery_surface - name = "Slippery Surface" - desc = "More of a practical joke than an actual spell." - school = "transmutation" - feedback = "su" - range = 5 - spell_flags = 0 - invocation_type = SpI_NONE - show_message = " snaps their fingers." - spell_delay = 50 - hud_state = "gen_ice" - cast_sound = 'sound/magic/summonitems_generic.ogg' - -/spell/hand/slippery_surface/cast_hand(var/atom/a, var/mob/user) - for(var/turf/T in view(1,a)) - if(T.simulated) - T.wet_floor(50) - new /obj/effect/temporary(T, 3, 'icons/effects/effects.dmi', "sonar_ping") - return ..() diff --git a/code/modules/spells/hand/sunwrath.dm b/code/modules/spells/hand/sunwrath.dm deleted file mode 100644 index 63da9a54c611..000000000000 --- a/code/modules/spells/hand/sunwrath.dm +++ /dev/null @@ -1,32 +0,0 @@ -/spell/hand/duration/sunwrath - name = "Sun God's Wrath" - desc = "Your hands become a gateway of fire, shooting hot plasma from your fingertips." - spell_flags = 0 - charge_max = 600 - invocation_type = SpI_SHOUT - invocation = "Herald! Bless me with your anger!" - show_message = " erupts fire from their hands" - school = "Divine" - hand_duration = 100 - spell_delay = 30 - range = 4 - hud_state = "wiz_immolate" - -/spell/hand/duration/sunwrath/cast_hand(var/atom/A, var/mob/user) - var/turf/T = get_turf(user) - var/list/turfs = getline(T,A) - T - for(var/t in turfs) - var/turf/turf = t - if(turf.density || isspaceturf(turf)) - break - new /obj/effect/fake_fire/sunwrath(t) - return 1 - -/obj/effect/fake_fire/sunwrath - firelevel = 2 - last_temperature = 0 - pressure = 3000 - -/obj/effect/fake_fire/sunwrath/Process() //Override, so we burn mobs only - for(var/mob/living/L in loc) - L.FireBurn(firelevel,last_temperature,pressure) \ No newline at end of file diff --git a/code/modules/spells/no_clothes.dm b/code/modules/spells/no_clothes.dm deleted file mode 100644 index 3b8502923519..000000000000 --- a/code/modules/spells/no_clothes.dm +++ /dev/null @@ -1,5 +0,0 @@ -/spell/noclothes - name = "No Clothes" - desc = "Learn the ancient art of not wearing fancy robes while casting spells." - feedback = "NC" - spell_flags = NO_BUTTON \ No newline at end of file diff --git a/code/modules/spells/racial_wizard.dm b/code/modules/spells/racial_wizard.dm deleted file mode 100644 index ce5c4e651162..000000000000 --- a/code/modules/spells/racial_wizard.dm +++ /dev/null @@ -1,81 +0,0 @@ -//this file is full of all the racial spells/artifacts/etc that each species has. - -/obj/item/magic_rock - name = "magical rock" - desc = "Legends say that this rock will unlock the true potential of anyone who touches it." - icon = 'icons/obj/wizard.dmi' - icon_state = "magic rock" - w_class = ITEM_SIZE_SMALL - throw_speed = 1 - throw_range = 3 - material = /decl/material/solid/stone/basalt - var/list/potentials = list( - SPECIES_HUMAN = /obj/item/bag/cash/infinite - ) - -/obj/item/magic_rock/attack_self(mob/user) - if(!ishuman(user)) - to_chat(user, "\The [src] can do nothing for such a simple being.") - return - var/mob/living/human/H = user - var/reward = potentials[H.species.get_root_species_name(H)] //we get body type because that lets us ignore subspecies. - if(!reward) - to_chat(user, "\The [src] does not know what to make of you.") - return - for(var/spell/S in user.mind.learned_spells) - if(istype(S,reward)) - to_chat(user, "\The [src] can do no more for you.") - return - var/a = new reward() - if(ispath(reward,/spell)) - H.add_spell(a) - else if(ispath(reward,/obj)) - H.put_in_hands(a) - to_chat(user, "\The [src] crumbles in your hands.") - qdel(src) - -/obj/item/bag/cash/infinite - storage = /datum/storage/bag/cash/infinite - -/obj/item/bag/cash/infinite/WillContain() - return list(/obj/item/cash/c1000) - -/spell/messa_shroud/choose_targets() - return list(get_turf(holder)) - -/spell/messa_shroud/cast(var/list/targets, mob/user) - var/turf/T = targets[1] - - if(!istype(T)) - return - - var/obj/O = new /obj(T) - O.set_light(range, -10, "#ffffff") - - spawn(duration) - qdel(O) - -/mob/observer/eye/freelook/wizard_eye - name_sufix = "Wizard Eye" - -/mob/observer/eye/freelook/wizard_eye/Initialize() - . = ..() //we dont use the Ai one because it has AI specific procs imbedded in it. - visualnet = cameranet - -/mob/living/proc/release_eye() - set name = "Release Vision" - set desc = "Return your sight to your body." - set category = "Abilities" - - verbs -= /mob/living/proc/release_eye //regardless of if we have an eye or not we want to get rid of this verb. - - if(!eyeobj) - return - eyeobj.release(src) - -/mob/observer/eye/freelook/wizard_eye/Destroy() - if(isliving(eyeobj.owner)) - var/mob/living/L = eyeobj.owner - L.release_eye() - qdel(eyeobj) - return ..() \ No newline at end of file diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm index 653d2b8cae2f..bfcf1f4d8f6c 100644 --- a/code/modules/spells/spell_code.dm +++ b/code/modules/spells/spell_code.dm @@ -26,7 +26,7 @@ var/global/list/spells = typesof(/spell) //needed for the badmin verb for now var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var" var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used - var/spell_flags = NEEDSCLOTHES + var/spell_flags = 0 var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell var/invocation_type = SpI_NONE //can be none, whisper, shout, and emote var/range = 7 //the range of the spell; outer radius for aoe spells @@ -241,21 +241,14 @@ var/global/list/spells = typesof(/spell) //needed for the badmin verb for now to_chat(SA, "The null sceptre's power interferes with your own!") return 0 - if(!(spell_flags & GHOSTCAST)) - if(!(spell_flags & NO_SOMATIC)) - var/mob/living/L = user - if(L.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING|INCAPACITATION_KNOCKOUT)) - to_chat(user, "You can't cast spells while incapacitated!") - return 0 - - if(ishuman(user) && !(invocation_type in list(SpI_EMOTE, SpI_NONE)) && user.get_item_blocking_speech()) - to_chat(user, "Mmmf mrrfff!") - return 0 + var/mob/living/L = user + if(L.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING|INCAPACITATION_KNOCKOUT)) + to_chat(user, "You can't cast spells while incapacitated!") + return 0 - var/spell/noclothes/spell = locate() in user.mind.learned_spells - if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check - if(!user.wearing_wiz_garb()) - return 0 + if(ishuman(user) && !(invocation_type in list(SpI_EMOTE, SpI_NONE)) && user.get_item_blocking_speech()) + to_chat(user, "Mmmf mrrfff!") + return 0 return 1 @@ -381,10 +374,7 @@ var/global/list/spells = typesof(/spell) //needed for the badmin verb for now if(!user || isnull(user)) return 0 - var/incap_flags = INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING - if(!(spell_flags & (GHOSTCAST))) - incap_flags |= INCAPACITATION_KNOCKOUT - + var/incap_flags = INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING|INCAPACITATION_KNOCKOUT return do_after(user,delay, incapacitation_flags = incap_flags) /proc/view_or_range(distance = world.view , center = usr , type) diff --git a/code/modules/spells/spell_projectile.dm b/code/modules/spells/spell_projectile.dm deleted file mode 100644 index 1599a59d3a78..000000000000 --- a/code/modules/spells/spell_projectile.dm +++ /dev/null @@ -1,56 +0,0 @@ -/obj/item/projectile/spell_projectile - name = "spell" - icon = 'icons/obj/projectiles.dmi' - - nodamage = 1 //Most of the time, anyways - - var/spell/targeted/projectile/carried - - penetrating = 0 - life_span = 10 //set by the duration of the spell - - var/proj_trail = 0 //if it leaves a trail - var/proj_trail_lifespan = 0 //deciseconds - var/proj_trail_icon = 'icons/obj/wizard.dmi' - var/proj_trail_icon_state = "trail" - var/list/trails = new() - -/obj/item/projectile/spell_projectile/Destroy() - for(var/trail in trails) - qdel(trail) - carried = null - return ..() - -/obj/item/projectile/spell_projectile/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return - -/obj/item/projectile/spell_projectile/before_move() - if(proj_trail && src && src.loc) //pretty trails - var/obj/effect/overlay/trail = new /obj/effect/overlay(loc) - trails += trail - trail.icon = proj_trail_icon - trail.icon_state = proj_trail_icon_state - trail.set_density(0) - spawn(proj_trail_lifespan) - trails -= trail - qdel(trail) - -/obj/item/projectile/spell_projectile/proc/prox_cast(var/list/targets) - if(loc) - carried.prox_cast(targets, src) - qdel(src) - return - -/obj/item/projectile/spell_projectile/Bump(var/atom/A, forced=0) - if(loc && carried) - prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) - return 1 - -/obj/item/projectile/spell_projectile/on_impact() - if(loc && carried) - prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) - return 1 - -/obj/item/projectile/spell_projectile/seeking - name = "seeking spell" diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm deleted file mode 100644 index fa43c3e8d63f..000000000000 --- a/code/modules/spells/spellbook.dm +++ /dev/null @@ -1,322 +0,0 @@ -#define NOREVERT 1 -#define LOCKED 2 -#define CAN_MAKE_CONTRACTS 4 -#define INVESTABLE 8 -#define NO_LOCKING 16 - -//spells/spellbooks have a variable for this but as artefacts are literal items they do not. -//so we do this instead. -var/global/list/artefact_feedback = list( - /obj/structure/closet/wizard/armor = "HS", - /obj/item/gun/energy/staff/focus = "MF", - /obj/item/gun/energy/staff/fire = "FS", - /obj/item/summoning_stone = "ST", - /obj/item/magic_rock = "RA", - /obj/item/contract/apprentice = "CP", - /obj/structure/closet/wizard/scrying = "SO", - /obj/item/paper/scroll/teleportation = "TS", - /obj/item/gun/energy/staff = "ST", - /obj/item/gun/energy/staff/animate = "SA", - /obj/item/dice/d20/cursed = "DW" -) - -/obj/item/book/spell - name = "master spell book" - desc = "The legendary book of spells of the wizard." - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_NORMAL - material = /decl/material/solid/organic/paper - matter = list(/decl/material/solid/organic/leather = MATTER_AMOUNT_REINFORCEMENT) - unique = TRUE - var/uses = 1 - var/temp = null - var/datum/spellbook/spellbook - var/spellbook_type = /datum/spellbook/ //for spawning specific spellbooks. - var/investing_time = 0 //what time we target forr a return on our spell investment. - var/has_sacrificed = 0 //whether we have already got our sacrifice bonus for the current investment. - -/obj/item/book/spell/Initialize() - . = ..() - set_spellbook(spellbook_type) - -/obj/item/book/spell/try_carve() - return FALSE - -/obj/item/book/spell/proc/set_spellbook(var/type) - if(spellbook) - qdel(spellbook) - spellbook = new type() - uses = spellbook.max_uses - name = spellbook.name - desc = spellbook.desc - -/obj/item/book/spell/attack_self(mob/user) - if(!user.mind) - return - if (user.mind.assigned_special_role != /decl/special_role/wizard) - if (user.mind.assigned_special_role != "Wizard's Apprentice") - to_chat(user, "You can't make heads or tails of this book.") - return - if (spellbook.book_flags & LOCKED) - to_chat(user, "Drat! This spellbook's apprentice-proof lock is on!") - return - else if (spellbook.book_flags & LOCKED) - to_chat(user, "You notice the apprentice-proof lock is on. Luckily you are beyond such things.") - interact(user) - -/obj/item/book/spell/proc/make_sacrifice(obj/item/I, mob/user, var/reagent) - if(has_sacrificed) - to_chat(user, SPAN_WARNING("\The [src] is already sated! Wait for a return on your investment before you sacrifice more to it.")) - return - if(reagent) - if(I.reagents?.has_reagent(reagent, 5)) - I.remove_from_reagents(reagent, 5) - else if(LAZYACCESS(I.matter, reagent) >= (SHEET_MATERIAL_AMOUNT * 5)) - qdel(I) - else - if(istype(I,/obj/item/stack)) - var/obj/item/stack/S = I - if(S.amount < S.max_amount) - to_chat(usr, "You must sacrifice [S.max_amount] stacks of [S]!") - return - qdel(I) - to_chat(user, "Your sacrifice was accepted!") - has_sacrificed = 1 - investing_time = max(investing_time - 6000,1) //subtract 10 minutes. Make sure it doesn't act funky at the beginning of the game. - - -/obj/item/book/spell/attackby(obj/item/I, mob/user) - if(investing_time) - for(var/type in spellbook.sacrifice_objects) - if(istype(I,type)) - make_sacrifice(I, user) - return TRUE - - for(var/mat in spellbook.sacrifice_materials) - if(LAZYACCESS(I.matter, mat) > (SHEET_MATERIAL_AMOUNT * 10)) - make_sacrifice(I, user, mat) - return TRUE - - if(I.reagents) - for(var/id in spellbook.sacrifice_reagents) - if(I.reagents.has_reagent(id, 5)) - make_sacrifice(I, user, id) - return TRUE - return ..() - -/obj/item/book/spell/interact(mob/user) - var/dat = null - if(temp) - dat = "[temp]
Return" - else - dat = "

[spellbook.title]

[spellbook.title_desc]
You have [uses] spell slot\s left.

" - dat += "
Requires Wizard Garb
Selectable Target
Spell Charge Type: Recharge, Sacrifice, Charges

" - dat += "
To use a contract, first bind it to your soul, then give it to someone to sign. This will bind their soul to you.

" - for(var/i in 1 to spellbook.spells.len) - var/name = "" //name of target - var/desc = "" //description of target - var/info = "" //additional information - if(ispath(spellbook.spells[i],/datum/spellbook)) - var/datum/spellbook/S = spellbook.spells[i] - name = initial(S.name) - desc = initial(S.book_desc) - info = "[initial(S.max_uses)] Spell Slots" - else if(ispath(spellbook.spells[i],/obj)) - var/obj/O = spellbook.spells[i] - name = "Artefact: [capitalize(initial(O.name))]" //because 99.99% of objects dont have capitals in them and it makes it look weird. - desc = initial(O.desc) - else if(ispath(spellbook.spells[i],/spell)) - var/spell/S = spellbook.spells[i] - name = initial(S.name) - desc = initial(S.desc) - var/testing = initial(S.spell_flags) - if(testing & NEEDSCLOTHES) - info = "W" - var/type = "" - switch(initial(S.charge_type)) - if(Sp_RECHARGE) - type = "R" - if(Sp_HOLDVAR) - type = "S" - if(Sp_CHARGES) - type = "C" - info += "[type]" - dat += "[name]" - if(length(info)) - dat += " ([info])" - dat += " ([spellbook.spells[spellbook.spells[i]]] spell slot[spellbook.spells[spellbook.spells[i]] > 1 ? "s" : "" ])" - if(spellbook.book_flags & CAN_MAKE_CONTRACTS) - dat += " Make Contract" - dat += "
[desc]

" - dat += "
" - dat += "
Re-memorise your spellbook.
" - if(spellbook.book_flags & INVESTABLE) - if(investing_time) - dat += "
Currently investing in a slot...
" - else - dat += "
Invest a Spell Slot
Investing a spellpoint will return two spellpoints back in 15 minutes.
Some say a sacrifice could even shorten the time...
" - if(!(spellbook.book_flags & NOREVERT)) - dat += "
Choose different spellbook.
" - if(!(spellbook.book_flags & NO_LOCKING)) - dat += "
[spellbook.book_flags & LOCKED ? "Unlock" : "Lock"] the spellbook.
" - show_browser(user, dat, "window=spellbook") - -/obj/item/book/spell/CanUseTopic(var/mob/living/human/H) - if(!istype(H)) - return STATUS_CLOSE - - if(H.mind && (spellbook.book_flags & LOCKED) && H.mind.assigned_special_role == "Wizard's Apprentice") //make sure no scrubs get behind the lock - return STATUS_CLOSE - - return ..() - -/obj/item/book/spell/OnTopic(var/mob/living/human/user, href_list) - if(href_list["lock"] && !(spellbook.book_flags & NO_LOCKING)) - if(spellbook.book_flags & LOCKED) - spellbook.book_flags &= ~LOCKED - else - spellbook.book_flags |= LOCKED - . = TOPIC_REFRESH - - else if(href_list["temp"]) - temp = null - . = TOPIC_REFRESH - - else if(href_list["book"]) - if(initial(spellbook.max_uses) != spellbook.max_uses || uses != spellbook.max_uses) - temp = "You've already purchased things using this spellbook!" - else - src.set_spellbook(/datum/spellbook) - temp = "You have reverted back to the Book of Tomes." - . = TOPIC_REFRESH - - else if(href_list["invest"]) - temp = invest() - . = TOPIC_REFRESH - - else if(href_list["path"]) - var/path = locate(href_list["path"]) in spellbook.spells - if(!path) - return TOPIC_HANDLED - if(uses < spellbook.spells[path]) - to_chat(user, "You do not have enough spell slots to purchase this.") - return TOPIC_HANDLED - send_feedback(path) //feedback stuff - if(ispath(path,/datum/spellbook)) - src.set_spellbook(path) - temp = "You have chosen a new spellbook." - else - if(href_list["contract"]) - if(!(spellbook.book_flags & CAN_MAKE_CONTRACTS)) - return //no - uses -= spellbook.spells[path] - spellbook.max_uses -= spellbook.spells[path] //no basksies - var/obj/O = new /obj/item/contract/boon(get_turf(user),path) - temp = "You have purchased \the [O]." - else - if(ispath(path,/spell)) - temp = src.add_spell(user,path) - if(temp) - uses -= spellbook.spells[path] - else - var/obj/O = new path(get_turf(user)) - temp = "You have purchased \a [O]." - uses -= spellbook.spells[path] - spellbook.max_uses -= spellbook.spells[path] - //finally give it a bit of an oomf - playsound(get_turf(user),'sound/effects/phasein.ogg',50,1) - . = TOPIC_REFRESH - - else if(href_list["reset"] && !(spellbook.book_flags & NOREVERT)) - var/area/map_template/wizard_station/A = get_area(user) - if(istype(A)) - uses = spellbook.max_uses - investing_time = 0 - has_sacrificed = 0 - user.spellremove() - temp = "All spells and investments have been removed. You may now memorise a new set of spells." - SSstatistics.add_field_details("wizard_spell_learned","UM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells - else - to_chat(user, "You must be in the wizard academy to re-memorise your spells.") - . = TOPIC_REFRESH - - src.interact(user) - -/obj/item/book/spell/proc/invest() - if(uses < 1) - return "You don't have enough slots to invest!" - if(investing_time) - return "You can only invest one spell slot at a time." - uses-- - START_PROCESSING(SSobj, src) - investing_time = world.time + (15 MINUTES) - return "You invest a spellslot and will recieve two in return in 15 minutes." - -/obj/item/book/spell/Process() - if(investing_time && investing_time <= world.time) - src.visible_message("\The [src] emits a soft chime.") - uses += 2 - if(uses > spellbook.max_uses) - spellbook.max_uses = uses - investing_time = 0 - has_sacrificed = 0 - STOP_PROCESSING(SSobj, src) - return 1 - -/obj/item/book/spell/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/book/spell/proc/send_feedback(var/path) - if(ispath(path,/datum/spellbook)) - var/datum/spellbook/S = path - SSstatistics.add_field_details("wizard_spell_learned","[initial(S.feedback)]") - else if(ispath(path,/spell)) - var/spell/S = path - SSstatistics.add_field_details("wizard_spell_learned","[initial(S.feedback)]") - else if(ispath(path,/obj)) - SSstatistics.add_field_details("wizard_spell_learned","[artefact_feedback[path]]") - - -/obj/item/book/spell/proc/add_spell(var/mob/user, var/spell_path) - for(var/spell/S in user.mind.learned_spells) - if(istype(S,spell_path)) - if(!S.can_improve()) - return - if(S.can_improve(Sp_SPEED) && S.can_improve(Sp_POWER)) - switch(alert(user, "Do you want to upgrade this spell's speed or power?", "Spell upgrade", "Speed", "Power", "Cancel")) - if("Speed") - return S.quicken_spell() - if("Power") - return S.empower_spell() - else - return - else if(S.can_improve(Sp_POWER)) - return S.empower_spell() - else if(S.can_improve(Sp_SPEED)) - return S.quicken_spell() - - var/spell/S = new spell_path() - user.add_spell(S) - return "You learn the spell [S]" - -/datum/spellbook - var/name = "\improper Book of Tomes" - var/desc = "The legendary book of spells of the wizard." - var/book_desc = "Holds information on the various tomes available to a wizard" - var/feedback = "" //doesn't need one. - var/book_flags = NOREVERT - var/max_uses = 1 - var/title = "Book of Tomes" - var/title_desc = "This tome marks down all the available tomes for use. Choose wisely, there are no refunds." - var/list/spells = list(/datum/spellbook/standard = 1, - /datum/spellbook/cleric = 1, - /datum/spellbook/battlemage = 1, - /datum/spellbook/spatial = 1, - /datum/spellbook/druid = 1 - ) //spell's path = cost of spell - - var/list/sacrifice_reagents - var/list/sacrifice_objects - var/list/sacrifice_materials diff --git a/code/modules/spells/spellbook/battlemage.dm b/code/modules/spells/spellbook/battlemage.dm deleted file mode 100644 index 07cebf63d820..000000000000 --- a/code/modules/spells/spellbook/battlemage.dm +++ /dev/null @@ -1,44 +0,0 @@ -//Battlemage is all about mixing physical with the mystical in head to head combat. -//Things like utility and mobility come second. -/datum/spellbook/battlemage - name = "\improper Battlemage's Bible" - feedback = "BM" - desc = "Smells like blood." - book_desc = "Mix physical with the mystical in head to head combat." - title = "The Art of Magical Combat" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list( - /spell/targeted/projectile/dumbfire/passage = 1, - /spell/targeted/equip_item/dyrnwyn = 1, - /spell/targeted/equip_item/shield = 1, - /spell/targeted/projectile/dumbfire/fireball = 1, - /spell/targeted/torment = 1, - /spell/targeted/heal_target = 2, - /spell/aoe_turf/conjure/mirage = 1, - /spell/targeted/shapeshift/corrupt_form = 1, - /spell/radiant_aura = 1, - /spell/noclothes = 1, - /obj/structure/closet/wizard/armor = 1, - /obj/item/gun/energy/staff/focus = 1, - /obj/item/gun/energy/staff/fire = 1, - /obj/item/dice/d20/cursed = 1, - /obj/item/summoning_stone = 2, - /obj/item/magic_rock = 1, - /obj/item/contract/wizard/xray = 1, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_objects = list( - /obj/item/sword, - /obj/item/bladed/axe/fire, - /obj/item/baton, - /obj/item/knife/ritual, - /obj/item/knife/kitchen/cleaver, - /obj/item/knife/folding/combat/balisong, - /obj/item/knife/folding/tacticool, - /obj/item/star - ) diff --git a/code/modules/spells/spellbook/cleric.dm b/code/modules/spells/spellbook/cleric.dm deleted file mode 100644 index 98c5a48f6d52..000000000000 --- a/code/modules/spells/spellbook/cleric.dm +++ /dev/null @@ -1,50 +0,0 @@ -//Cleric is all about healing. Mobility and offense comes at a higher price but not impossible. -/obj/item/book/spell/cleric - spellbook_type = /datum/spellbook/cleric - -/datum/spellbook/cleric - name = "\improper Cleric's Tome" - feedback = "CR" - desc = "For those who do not harm, or at least feel sorry about it." - book_desc = "All about healing. Mobility and offense comes at a higher price but not impossible." - title = "Cleric's Tome of Healing" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 7 - - spells = list( - /spell/targeted/heal_target/major = 1, - /spell/targeted/heal_target/area = 1, - /spell/targeted/heal_target/sacrifice = 1, - /spell/targeted/genetic/blind = 1, - /spell/targeted/shapeshift/baleful_polymorph = 1, - /spell/targeted/projectile/dumbfire/stuncuff = 1, - /spell/targeted/ethereal_jaunt = 2, - /spell/aoe_turf/knock = 1, - /spell/radiant_aura = 1, - /spell/targeted/equip_item/holy_relic = 1, - /spell/aoe_turf/conjure/grove/sanctuary = 1, - /spell/targeted/projectile/dumbfire/fireball = 2, - /spell/area_teleport = 2, - /spell/portal_teleport = 2, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/noclothes = 1, - /obj/item/magic_rock = 1, - /obj/structure/closet/wizard/scrying = 2, - /obj/item/summoning_stone = 2, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_reagents = list( - /decl/material/liquid/adminordrazine - ) - sacrifice_objects = list( - /obj/item/stack/nanopaste, - /obj/item/scanner/health, - /obj/item/scanner/breath, - /obj/item/stack/medical/bandage/advanced, - /obj/item/stack/medical/ointment/advanced, - /obj/item/bodybag/rescue, - /obj/item/defibrillator - ) diff --git a/code/modules/spells/spellbook/druid.dm b/code/modules/spells/spellbook/druid.dm deleted file mode 100644 index 48ee015d3499..000000000000 --- a/code/modules/spells/spellbook/druid.dm +++ /dev/null @@ -1,43 +0,0 @@ -//all about the summons, nature, and a bit o' healin. - -/obj/item/book/spell/druid - spellbook_type = /datum/spellbook/druid - -/datum/spellbook/druid - name = "\improper Druid's Leaflet" - feedback = "DL" - desc = "It smells like an air freshener." - book_desc = "Summons, nature, and a bit o' healin." - title = "Druidic Guide on how to be smug about nature" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list( - /spell/targeted/heal_target = 1, - /spell/targeted/heal_target/sacrifice = 1, - /spell/aoe_turf/conjure/mirage = 1, - /spell/aoe_turf/conjure/summon/bats = 1, - /spell/aoe_turf/conjure/summon/bear = 1, - /spell/targeted/equip_item/party_hardy = 1, - /spell/targeted/equip_item/seed = 1, - /spell/targeted/shapeshift/avian = 1, - /spell/aoe_turf/disable_tech = 1, - /spell/hand/charges/entangle = 1, - /spell/aoe_turf/conjure/grove/sanctuary = 1, - /spell/aoe_turf/knock = 1, - /spell/area_teleport = 2, - /spell/portal_teleport = 2, - /spell/noclothes = 1, - /obj/item/magic_rock = 1, - /obj/item/summoning_stone = 2, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - sacrifice_objects = list( - /obj/item/seeds, - /obj/item/wirecutters/clippers, - /obj/item/scanner/plant, - /obj/item/tool/axe/hatchet, - /obj/item/tool/hoe/mini - ) diff --git a/code/modules/spells/spellbook/spatial.dm b/code/modules/spells/spellbook/spatial.dm deleted file mode 100644 index def9a6695d25..000000000000 --- a/code/modules/spells/spellbook/spatial.dm +++ /dev/null @@ -1,48 +0,0 @@ -//all about moving around and mobility and being an annoying shit. - -/obj/item/book/spell/spatial - spellbook_type = /datum/spellbook/spatial - -/datum/spellbook/spatial - name = "\improper Spatial Manual" - feedback = "SP" - desc = "You feel like this might disappear from out of under you." - book_desc = "Movement and teleportation. Run from your problems!" - title = "Manual of Spatial Transportation" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 11 - - spells = list( - /spell/targeted/ethereal_jaunt = 1, - /spell/aoe_turf/blink = 1, - /spell/area_teleport = 1, - /spell/portal_teleport = 1, - /spell/targeted/projectile/dumbfire/passage = 1, - /spell/mark_recall = 1, - /spell/targeted/swap = 1, - /spell/targeted/shapeshift/avian = 1, - /spell/targeted/projectile/magic_missile = 1, - /spell/targeted/heal_target = 1, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/aoe_turf/smoke = 1, - /spell/aoe_turf/conjure/summon/bats = 3, - /spell/noclothes = 1, - /obj/item/dice/d20/cursed = 1, - /obj/structure/closet/wizard/scrying = 2, - /obj/item/paper/scroll/teleportation = 1, - /obj/item/magic_rock = 1, - /obj/item/summoning_stone = 3, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_reagents = list( - /decl/material/liquid/amphetamines - ) - sacrifice_objects = list( - /obj/item/stack/telecrystal - ) - sacrifice_materials = list( - /decl/material/solid/gemstone/diamond - ) \ No newline at end of file diff --git a/code/modules/spells/spellbook/standard.dm b/code/modules/spells/spellbook/standard.dm deleted file mode 100644 index 99e8f27c2740..000000000000 --- a/code/modules/spells/spellbook/standard.dm +++ /dev/null @@ -1,54 +0,0 @@ -//the spellbook we know and love. Well, the one we know, at least. - -/obj/item/book/spell/standard - spellbook_type = /datum/spellbook/standard - -/datum/spellbook/standard - name = "\improper Standard Spellbook" - feedback = "SB" - title = "Book of Spells and Artefacts" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_desc = "A general wizard's spellbook. All its spells are easy to use but hard to master." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list( - /spell/targeted/projectile/magic_missile = 1, - /spell/targeted/projectile/dumbfire/fireball = 1, - /spell/aoe_turf/disable_tech = 1, - /spell/aoe_turf/smoke = 1, - /spell/targeted/genetic/blind = 1, - /spell/targeted/subjugation = 1, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/aoe_turf/blink = 1, - /spell/area_teleport = 1, - /spell/targeted/ethereal_jaunt = 1, - /spell/targeted/heal_target = 1, - /spell/aoe_turf/knock = 1, - /spell/noclothes = 2, - /obj/item/gun/energy/staff/focus = 1, - /obj/item/gun/energy/staff/fire = 1, - /obj/item/gun/energy/staff/animate = 1, - /obj/structure/closet/wizard/scrying = 1, - /obj/item/summoning_stone = 2, - /obj/item/magic_rock = 1, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_objects = list( - /obj/item/toolbox, - /obj/item/cane/fancy, - /obj/item/flamethrower, - /obj/item/plastique, - /obj/item/dice, - /obj/item/soap, - /obj/item/flame/candle, - /obj/item/flame/candle/scented/incense, - /obj/item/caution, - /obj/item/towel, - /obj/item/tank/jetpack, - /obj/item/plunger, - /obj/item/megaphone, - /obj/item/deck/cards - ) \ No newline at end of file diff --git a/code/modules/spells/spellbook/student.dm b/code/modules/spells/spellbook/student.dm deleted file mode 100644 index 1c07a5135b13..000000000000 --- a/code/modules/spells/spellbook/student.dm +++ /dev/null @@ -1,28 +0,0 @@ -//wizard's training wheels. Basically. Same shit as in the general one. - -/obj/item/book/spell/student - spellbook_type = /datum/spellbook/student - -/datum/spellbook/student - name = "\improper Student's Spellbook" - feedback = "ST" - desc = "This spell book has a sticker on it that says, 'certified for children 5 and older'." - book_desc = "This spellbook is dedicated to teaching neophytes in the ways of magic." - title = "Book of Spells and Education" - title_desc = "Hello. Congratulations on becoming a wizard. You may be asking yourself: What? A wizard? Already? Of course! Anybody can become a wizard! Learning to be a good one is the hard part.
Without further adue, let us begin by learning the three concepts of wizardry, 'Spell slots', 'Spells', and 'Artifacts'.
Firstly lets try to understand the 'spell slot'. A spell slot is the measurable amount of spells and artifacts one tome can give. Most spells will only take up a singular spell slot, however more powerful spells/artifacts can take up more.
Spells are spells. They can have requirements, such as wizard garb, and most can be upgraded by purchasing additional spell slots for them. Most upgrades fall into two categories, 'Speed' and 'Power'. Speed upgrades decrease the time you have to spend recharging your spell. Power increases the potency of your spells. Spells are also special in that they can be refunded while inside the Wizard Acadamy, so if you want to test a spell out before moving out into the field, feel free to do that in the comfort of our home.
Artifacts, or 'Artefacts' as we call them, are powerful wizard tools or items made specially for wizards everywhere. Extremely potent, they cannot be refunded like spells, and some of them can be used by non-wizards, so be careful!
Knowing these three concepts puts you in a league above most wizards, however knowledge of spells is just as important so we've included a list of spells below made specifically for the beginning wizard. Take all of them, or mix and match, remember being creative is half of being a wizard!" - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 5 - - spells = list( - /spell/aoe_turf/knock = 1, - /spell/targeted/ethereal_jaunt = 1, - /spell/targeted/projectile/magic_missile = 1, - /obj/item/gun/energy/staff/focus = 1, - /obj/item/contract/wizard/xray = 1 - ) - -/datum/spellbook/student/apprentice - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE|NOREVERT|NO_LOCKING - -/obj/item/book/spell/apprentice - spellbook_type = /datum/spellbook/student/apprentice diff --git a/code/modules/spells/targeted/analyze.dm b/code/modules/spells/targeted/analyze.dm deleted file mode 100644 index 705d97399c70..000000000000 --- a/code/modules/spells/targeted/analyze.dm +++ /dev/null @@ -1,19 +0,0 @@ -/spell/targeted/analyze - name = "Analyze" - desc = "Using your wizardly powers, you can detect the inner destructions of a persons body." - - feedback = "AZ" - school = "illusion" - charge_max = 100 - spell_flags = INCLUDEUSER|SELECTABLE - range = 2 - invocation_type = SpI_WHISPER - invocation = "Fu Yi Fim" - compatible_mobs = list(/mob/living/human) - hud_state = "analyze" - -/spell/targeted/analyze/cast(var/list/targets, var/mob/user) - for(var/a in targets) - var/mob/living/human/H = a - new /obj/effect/temporary(get_turf(a),5, 'icons/effects/effects.dmi', "repel_missiles") - to_chat(user,medical_scan_results(H,1)) \ No newline at end of file diff --git a/code/modules/spells/targeted/blood_boil.dm b/code/modules/spells/targeted/blood_boil.dm deleted file mode 100644 index 4c39b3b4620b..000000000000 --- a/code/modules/spells/targeted/blood_boil.dm +++ /dev/null @@ -1,25 +0,0 @@ -/spell/targeted/blood_boil - name = "Blood Boil" - desc = "Allow you to concentrate so deeply on a target that their body temperature increases, eventually setting them on fire." - feedback = "BO" - school = "transmutation" - charge_max = 300 - spell_flags = 0 - invocation_type = SpI_NONE - range = 5 - max_targets = 1 - compatible_mobs = list(/mob/living/human) - - time_between_channels = 50 - number_of_channels = 0 - - hud_state = "wiz_boilblood" - -/spell/targeted/blood_boil/cast(var/list/targets, var/mob/user) - var/mob/living/human/H = targets[1] - H.bodytemperature += 40 - if(prob(10)) - to_chat(H,"\The [user] seems to radiate an uncomfortable amount of heat your direction.") - if(H.bodytemperature > H.get_mob_temperature_threshold(HEAT_LEVEL_3)) //Burst into flames - H.fire_stacks += 50 - H.IgniteMob() \ No newline at end of file diff --git a/code/modules/spells/targeted/cleric_spells.dm b/code/modules/spells/targeted/cleric_spells.dm deleted file mode 100644 index 74061d776dd6..000000000000 --- a/code/modules/spells/targeted/cleric_spells.dm +++ /dev/null @@ -1,248 +0,0 @@ -/spell/targeted/heal_target - name = "Cure Light Wounds" - desc = "a rudimentary spell used mainly by wizards to heal papercuts. Does not require wizard garb." - feedback = "CL" - school = "transmutation" - charge_max = 20 SECONDS - spell_flags = INCLUDEUSER | SELECTABLE - invocation = "Di'Nath!" - invocation_type = SpI_SHOUT - range = 2 - max_targets = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 2) - - cooldown_reduc = 50 - hud_state = "heal_minor" - cast_sound = 'sound/magic/staff_healing.ogg' - - amt_dam_brute = -15 - amt_dam_fire = -5 - amt_dam_robo = -4 - effect_state = "green_sparkles" - effect_duration = 5 - - // Vars expect a constant at compile time, so we can't use macros for spans here - message = "You feel a pleasant rush of heat move through your body." - -/spell/targeted/heal_target/empower_spell() - if(!..()) - return 0 - amt_dam_brute -= 15 - amt_dam_fire -= 15 - amt_dam_robo -= 7 - return "[src] will now heal more." - -/spell/targeted/heal_target/touch - name = "Healing Touch" - desc = "Heals an adjacent target for a reasonable amount of health." - range = 1 - amt_dam_fire = -7 - amt_dam_brute = -7 - amt_dam_robo = -5 - charge_max = 10 SECONDS - spell_flags = SELECTABLE - invocation = "Di'Na!" - - hud_state = "heal_touch" - -/spell/targeted/heal_target/major - name = "Cure Major Wounds" - desc = "A spell used to fix others that cannot be fixed with regular medicine." - feedback = "CM" - charge_max = 30 SECONDS - spell_flags = INCLUDEUSER | SELECTABLE | NEEDSCLOTHES - invocation = "Borv Di'Nath!" - range = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) - cooldown_reduc = 100 - hud_state = "heal_major" - - amt_dam_brute = -75 - amt_dam_fire = -50 - amt_dam_robo = -10 - amt_blood = 28 - - message = "Your body feels like a warm, cozy fire." - -/spell/targeted/heal_target/major/empower_spell() - if(!..()) - return 0 - amt_blood = 28 - amt_organ = 5 - amt_brain = -5 - amt_radiation = -25 - amt_dam_tox = -20 - amt_dam_oxy = -14 - amt_dam_brute = -35 - amt_dam_fire = -35 - amt_dam_robo = -15 - - return "[src] heals more, and heals organ damage and radiation." - -/spell/targeted/heal_target/area - name = "Cure Area" - desc = "This spell heals everyone in an area." - feedback = "HA" - charge_max = 1 MINUTE - spell_flags = INCLUDEUSER - invocation = "Nal Di'Nath!" - range = 2 - max_targets = 0 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 1) - cooldown_reduc = 300 - hud_state = "heal_area" - amt_dam_robo = -6 - amt_dam_brute = -25 - amt_dam_fire = -25 - -/spell/targeted/heal_target/area/empower_spell() - if(!..()) - return 0 - amt_dam_brute -= 15 - amt_dam_fire -= 15 - amt_dam_robo -= 4 - range += 2 - - return "[src] now heals more in a wider area." - -/spell/targeted/heal_target/area/slow - charge_max = 2 MINUTES - -/spell/targeted/heal_target/sacrifice - name = "Sacrifice" - desc = "This spell heals immensily. For a price. Does not require wizard garb." - feedback = "SF" - spell_flags = SELECTABLE - invocation = "Ei'Nath Borv Di'Nath!" - charge_type = Sp_HOLDVAR - holder_var_type = "fireloss" - holder_var_amount = 100 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - - amt_dam_brute = -1000 - amt_dam_fire = -1000 - amt_dam_oxy = -100 - amt_dam_tox = -100 - amt_dam_robo = -1000 - amt_blood = 280 - effect_color = "#ff0000" - - hud_state = "gen_dissolve" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/targeted/heal_target/sacrifice/empower_spell() - if(!..()) - return 0 - - amt_organ = 25 - amt_brain = -25 - amt_radiation = -100 - - - return "You will now heal organ and brain damage, as well as virtually purge all radiation." - - -/spell/targeted/heal_target/trance - name = "Trance" - desc = "A mighty spell of restoration that briefly forces its target into a deep, dreamless sleep, rapidly repairing their body and soul as their senses are dulled. The users of this mighty art are known for being short lived, slowly devolving into raving madness as the power they once relied on fails them with excessive use." - feedback = "TC" - spell_flags = SELECTABLE - invocation = "Di' Dae Nath!" - charge_max = 2 MINUTES - - amt_dam_brute = -1000 - amt_dam_fire = -1000 - amt_dam_oxy = -100 - amt_dam_tox = -100 - amt_dam_robo = -1000 - hud_state = "trance" - var/obj/effect/effect - -/spell/targeted/heal_target/trance/cast(var/list/targets, var/mob/user) - for(var/t in targets) - var/mob/living/L = t - var/turf/T = get_turf(L) - effect = new /obj/effect/rift(T) - effect.color = "f0e68c" - L.forceMove(effect) - var/time = (L.get_damage(BRUTE) + L.get_damage(BURN)) * 20 - L.status_flags &= GODMODE - to_chat(L,"You will be in stasis for [time/10] second\s.") - addtimer(CALLBACK(src,PROC_REF(cancel_rift)),time) - -/spell/targeted/heal_target/trance/Destroy() - cancel_rift() - return ..() - -/spell/targeted/heal_target/trance/proc/cancel_rift() - if(effect) - var/mob/living/L = locate() in effect - L.status_flags &= ~GODMODE - L.forceMove(get_turf(L)) - apply_spell_damage(L) - charge_max += 300 - QDEL_NULL(effect) - -/obj/effect/rift - name = "rift" - desc = "a tear in space and time." - icon = 'icons/obj/wizard.dmi' - icon_state = "rift" - anchored = TRUE - density = FALSE - -/obj/effect/rift/Destroy() - for(var/o in contents) - var/atom/movable/M = o - M.dropInto(loc) - . = ..() - -/spell/targeted/revoke - name = "Revoke Death" - desc = "Revoke that of death itself. Comes at a cost that may be hard to manage for some." - feedback = "RK" - - spell_flags = SELECTABLE - - charge_type = Sp_CHARGES - charge_max = 1 - invocation = "Di Le Nal Yen Nath!" - invocation_type = SpI_SHOUT - range = 1 - hud_state = "heal_revoke" - -/spell/targeted/revoke/cast(var/list/targets, var/mob/living/user) - if(alert(user, "Are you sure?", "Alert", "Yes", "No") == "Yes" && alert(user, "Are you ABSOLUTELY SURE?", "Alert", "Absolutely!", "No") == "Absolutely!") - var/should_wait = 1 - for(var/t in targets) - var/mob/living/M = t - M.rejuvenate() - if(M.client) //We've got a dude - should_wait = 0 - break //Don't need to check anymore. - if(should_wait) - addtimer(CALLBACK(src,PROC_REF(check_for_revoke),targets), 30 SECONDS) - else - revoke_spells() - - -/spell/targeted/revoke/proc/check_for_revoke(var/list/targets) - for(var/t in targets) - var/mob/M = t - if(M.client) - revoke_spells() - return - charge_counter = charge_max - to_chat(holder,"\The [src] refreshes as it seems it could not bring back the souls of those you healed.") - -/spell/targeted/revoke/proc/revoke_spells() - if(!isliving(holder)) - return - var/mob/living/M = holder - if(M.mind) - for(var/s in M.mind.learned_spells) - if(istype(s, /spell/toggle_armor)) //Can keep the armor n junk. - continue - M.remove_spell(s) - for(var/a in M.auras) - M.remove_aura(a) \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/burning_touch.dm b/code/modules/spells/targeted/equip/burning_touch.dm deleted file mode 100644 index 65ed431693bf..000000000000 --- a/code/modules/spells/targeted/equip/burning_touch.dm +++ /dev/null @@ -1,69 +0,0 @@ -/spell/targeted/equip_item/burning_hand - name = "Burning Hand" - desc = "Bathes your hand in fire, giving you all the perks and disadvantages that brings." - feedback = "BH" - school = "conjuration" - invocation = "Horila Kiha!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - duration = 0 - max_targets = 1 - equipped_summons = list("active hand" = /obj/item/burning_hands) - delete_old = 0 - hud_state = "gen_burnhand" - -/obj/item/burning_hands - name = "Burning Hand" - icon = 'icons/mob/screen/grabs.dmi' - icon_state = "grabbed+1" - _base_attack_force = 10 - atom_damage_type = BURN - simulated = 0 - max_health = ITEM_HEALTH_NO_DAMAGE - obj_flags = OBJ_FLAG_NO_STORAGE - var/burn_power = 0 - var/burn_timer - -/obj/item/burning_hands/on_picked_up(var/mob/user) - burn_power = 0 - burn_timer = world.time + 10 SECONDS - START_PROCESSING(SSobj,src) - -/obj/item/burning_hands/get_heat() - return 1000 - -/obj/item/burning_hands/isflamesource() - return TRUE - -/obj/item/burning_hands/Process() - if(world.time < burn_timer) - return - burn_timer = world.time + 5 SECONDS - burn_power++ - set_base_attack_force(get_base_attack_force()+2) - if(!ishuman(src.loc)) - qdel(src) - return - var/mob/living/human/user = src.loc - var/obj/item/organ/external/hand - if(src == user.get_equipped_item(BP_L_HAND)) - hand = GET_EXTERNAL_ORGAN(user, BP_L_HAND) - else if(src == user.get_equipped_item(BP_R_HAND)) - hand = GET_EXTERNAL_ORGAN(user, BP_R_HAND) - if(hand) - hand.take_external_damage(burn = 2 * burn_power) - if(burn_power > 5) - user.fire_stacks += 15 - user.IgniteMob() - user.visible_message("\The [user] bursts into flames!") - user.drop_from_inventory(src) - else - if(burn_power == 5) - to_chat(user, "You begin to lose control of \the [src]'s flames as they rapidly move up your arm...") - else - to_chat(user, "You feel \the [src] grow hotter and hotter!") - -/obj/item/burning_hands/dropped() - ..() - qdel(src) \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/dyrnwyn.dm b/code/modules/spells/targeted/equip/dyrnwyn.dm deleted file mode 100644 index 71d7ace1e4f0..000000000000 --- a/code/modules/spells/targeted/equip/dyrnwyn.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/targeted/equip_item/dyrnwyn - name = "Summon Dyrnwyn" - desc = "Summons the legendary sword of Rhydderch Hael, said to draw in flame when held by a worthy man." - feedback = "SD" - charge_type = Sp_HOLDVAR - holder_var_type = "fireloss" - holder_var_amount = 10 - school = "conjuration" - invocation = "Anrhydeddu Fi!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - duration = 300 //30 seconds - max_targets = 1 - equipped_summons = list("active hand" = /obj/item/sword) - delete_old = FALSE - var/material = /decl/material/solid/metal/gold - - hud_state = "gen_immolate" - - -/spell/targeted/equip_item/dyrnwyn/summon_item(var/new_type) - var/obj/item/sword = new new_type(null,material) - sword.SetName("\improper Dyrnwyn") - sword.atom_damage_type = BURN - sword.hitsound = 'sound/items/welder2.ogg' - LAZYSET(sword.slowdown_per_slot, BP_L_HAND, 1) - LAZYSET(sword.slowdown_per_slot, BP_R_HAND, 1) - return sword - -/spell/targeted/equip_item/dyrnwyn/empower_spell() - if(!..()) - return FALSE - - material = /decl/material/solid/metal/silver - return "Dyrnwyn has been made pure: it is now made of silver." diff --git a/code/modules/spells/targeted/equip/equip.dm b/code/modules/spells/targeted/equip/equip.dm deleted file mode 100644 index 7b0304d9e076..000000000000 --- a/code/modules/spells/targeted/equip/equip.dm +++ /dev/null @@ -1,38 +0,0 @@ -//You can set duration to 0 to have the items last forever - -/spell/targeted/equip_item - cast_sound = 'sound/magic/summonitems_generic.ogg' - var/list/equipped_summons = list() //assoc list of text ids and paths to spawn - var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out - var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped - -/spell/targeted/equip_item/cast(list/targets, mob/user = usr) - ..() - for(var/mob/living/L in targets) - for(var/slot_id in equipped_summons) - var/to_create = equipped_summons[slot_id] - if(cmptext(slot_id,"active hand")) - slot_id = user.get_active_held_item_slot() - else if(cmptext(slot_id, "off hand")) - slot_id = user.get_empty_hand_slot() - else - slot_id = text2num(slot_id) //because the index is text, we access this instead - var/obj/item/new_item = summon_item(to_create) - var/obj/item/old_item = L.get_equipped_item(slot_id) - if(old_item) - L.drop_from_inventory(old_item) - if(delete_old) - qdel(old_item) - L.equip_to_slot(new_item, slot_id) - new_item.on_picked_up(L) - - if(duration) - summoned_items += new_item //we store it in a list to remove later - - if(duration) - spawn(duration) - for(var/obj/item/to_remove in summoned_items) - qdel(to_remove) - -/spell/targeted/equip_item/proc/summon_item(var/newtype) - return new newtype diff --git a/code/modules/spells/targeted/equip/holy_relic.dm b/code/modules/spells/targeted/equip/holy_relic.dm deleted file mode 100644 index 7c6dadf5da26..000000000000 --- a/code/modules/spells/targeted/equip/holy_relic.dm +++ /dev/null @@ -1,34 +0,0 @@ -/spell/targeted/equip_item/holy_relic - name = "Summon Holy Relic" - desc = "This spell summons a relic of purity into your hand for a short while. The relic will disrupt occult and magical energies - be wary, as this includes your own." - feedback = "SR" - school = "conjuration" - charge_type = Sp_RECHARGE - spell_flags = NEEDSCLOTHES | INCLUDEUSER - invocation = "Yee'Ro Su!" - invocation_type = SpI_SHOUT - range = 0 - max_targets = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) - charge_max = 60 SECONDS - duration = 25 SECONDS - cooldown_min = 35 SECONDS - delete_old = 0 - compatible_mobs = list(/mob/living/human) - - hud_state = "purge1" - - equipped_summons = list("active hand" = /obj/item/nullrod) - -/spell/targeted/equip_item/holy_relic/cast(list/targets, mob/user = usr) - ..() - for(var/mob/M in targets) - M.visible_message(SPAN_DANGER("A rod of metal appears in \the [M]'s hand!")) - -/spell/targeted/equip_item/holy_relic/empower_spell() - if(!..()) - return 0 - - duration += 50 - - return "The holy relic now lasts for [duration/10] seconds." \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/horsemask.dm b/code/modules/spells/targeted/equip/horsemask.dm deleted file mode 100644 index 31995ba86bd0..000000000000 --- a/code/modules/spells/targeted/equip/horsemask.dm +++ /dev/null @@ -1,48 +0,0 @@ -/spell/targeted/equip_item/horsemask - name = "Curse of the Horseman" - desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes." - school = "transmutation" - charge_type = Sp_RECHARGE - charge_max = 150 - charge_counter = 0 - spell_flags = 0 - invocation = "Kn'a Ftaghu, Puck'Bthnk!" - invocation_type = SpI_SHOUT - range = 7 - max_targets = 1 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - cooldown_min = 30 //30 deciseconds reduction per rank - selection_type = "range" - - compatible_mobs = list(/mob/living/human) - - hud_state = "wiz_horse" - cast_sound = 'sound/magic/horsehead_curse.ogg' - -/spell/targeted/equip_item/horsemask/New() - ..() - equipped_summons = list("[slot_wear_mask_str]" = /obj/item/clothing/mask/horsehead) - -/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr) - ..() - for(var/mob/living/target in targets) - target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ - "Your face burns up, and shortly after the fire you realise you have the face of a horse!") - target.flash_eyes() - -/spell/targeted/equip_item/horsemask/summon_item(var/new_type) - var/obj/item/new_item = new new_type - new_item.canremove = 0 //curses! - if(istype(new_item, /obj/item/clothing/mask/horsehead)) - var/obj/item/clothing/mask/horsehead/magichead = new_item - magichead.flags_inv = null //so you can still see their face - magichead.voicechange = 1 //NEEEEIIGHH - return new_item - -/spell/targeted/equip_item/horsemask/empower_spell() - if(!..()) - return 0 - - spell_flags = SELECTABLE - - return "You can now select your target with [src]" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/party_hardy.dm b/code/modules/spells/targeted/equip/party_hardy.dm deleted file mode 100644 index f6f7ba54d071..000000000000 --- a/code/modules/spells/targeted/equip/party_hardy.dm +++ /dev/null @@ -1,36 +0,0 @@ -/spell/targeted/equip_item/party_hardy - name = "Summon Party" - desc = "This spell was invented for the sole purpose of getting crunked at 11am on a Tuesday. Does not require wizard garb." - feedback = "PY" - school = "conjuration" - charge_type = Sp_RECHARGE - charge_max = 900 - cooldown_min = 600 - spell_flags = INCLUDEUSER - invocation = "Llet'Su G'iit Rrkned!" //Let's get wrecked. - invocation_type = SpI_SHOUT - range = 6 - max_targets = 0 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 2) - delete_old = 0 - - hud_state = "wiz_party" - - compatible_mobs = list(/mob/living/human) - equipped_summons = list("active hand" = /obj/item/chems/drinks/bottle/small/beer) - -/spell/targeted/equip_item/party_hardy/empower_spell() - if(!..()) - return 0 - switch(spell_levels[Sp_POWER]) - if(1) - equipped_summons = list("active hand" = /obj/item/chems/drinks/bottle/small/beer, - "off hand" = /obj/item/food/poppypretzel) - return "The spell will now give everybody a preztel as well." - if(2) - equipped_summons = list("active hand" = /obj/item/chems/drinks/bottle/absinthe, - "off hand" = /obj/item/food/poppypretzel, - "[slot_head_str]" = /obj/item/clothing/head/collectable/wizard) - return "Woo! Now everybody gets a cool wizard hat and MORE BOOZE!" - - return 0 \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/seed.dm b/code/modules/spells/targeted/equip/seed.dm deleted file mode 100644 index 2252ec75c8c0..000000000000 --- a/code/modules/spells/targeted/equip/seed.dm +++ /dev/null @@ -1,21 +0,0 @@ -/spell/targeted/equip_item/seed - name = "Summon Seed" - desc = "This spell summons a random seed into the hand of the wizard." - feedback = "SE" - delete_old = 0 - - spell_flags = INCLUDEUSER | NEEDSCLOTHES - invocation_type = SpI_WHISPER - invocation = "Ria'li akta." - - equipped_summons = list("active hand" = /obj/item/seeds/random) - compatible_mobs = list(/mob/living/human) - - charge_max = 600 //1 minute - cooldown_min = 200 //20 seconds - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 0) - - range = -1 - max_targets = 1 - - hud_state = "wiz_seed" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/shield.dm b/code/modules/spells/targeted/equip/shield.dm deleted file mode 100644 index b725196ad3a6..000000000000 --- a/code/modules/spells/targeted/equip/shield.dm +++ /dev/null @@ -1,41 +0,0 @@ -/spell/targeted/equip_item/shield - name = "Summon Shield" - desc = "Summons the most holy of shields, the riot shield. Commonly used during wizard riots." - feedback = "SH" - school = "conjuration" - invocation = "Sia helda!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER | NEEDSCLOTHES - range = -1 - max_targets = 1 - - compatible_mobs = list(/mob/living/human) - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 1) - charge_type = Sp_RECHARGE - charge_max = 900 - cooldown_min = 300 - equipped_summons = list("off hand" = /obj/item/shield/) - duration = 300 - delete_old = 0 - var/item_color = "#6666ff" - var/block_chance = 30 - - hud_state = "wiz_shield" - -/spell/targeted/equip_item/shield/summon_item(var/new_type) - var/obj/item/shield/I = new new_type() - I.icon_state = "buckler" - I.color = item_color - I.SetName("Wizard's Shield") - I.base_block_chance = block_chance - return I - -/spell/targeted/equip_item/shield/empower_spell() - if(!..()) - return 0 - - item_color = "#6600ff" - block_chance = 60 - - return "Your summoned shields will now block more often." diff --git a/code/modules/spells/targeted/ethereal_jaunt.dm b/code/modules/spells/targeted/ethereal_jaunt.dm index e686e7712dc5..fdccd1ce64d1 100644 --- a/code/modules/spells/targeted/ethereal_jaunt.dm +++ b/code/modules/spells/targeted/ethereal_jaunt.dm @@ -4,7 +4,7 @@ feedback = "EJ" school = "transmutation" charge_max = 30 SECONDS - spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER + spell_flags = Z2NOCAST | INCLUDEUSER invocation = "none" invocation_type = SpI_NONE range = 0 diff --git a/code/modules/spells/targeted/exude_pleasantness.dm b/code/modules/spells/targeted/exude_pleasantness.dm deleted file mode 100644 index 74ae51237ab7..000000000000 --- a/code/modules/spells/targeted/exude_pleasantness.dm +++ /dev/null @@ -1,19 +0,0 @@ -/spell/targeted/exude_pleasantness - name = "Exhude Pleasantness" - desc = "A simple spell used to make friends with people. Be warned, this spell only has a subtle effect" - feedback = "AP" - school = "Illusion" - spell_flags = INCLUDEUSER - range = 5 - max_targets = 0 - charge_max = 100 - var/list/possible_messages = list("seems pretty trustworthy!", "makes you feel appreciated.", "looks pretty cool.", "feels like the only decent person here!", "makes you feel safe.") - hud_state = "friendly" - -/spell/targeted/exude_pleasantness/cast(var/list/targets, var/mob/user) - for(var/m in targets) - var/mob/living/L = m - if(L.mind && L.mind.assigned_special_role == "Spellbound Servant") - to_chat(m, SPAN_NOTICE("\The [user] seems relatively harmless.")) - else - to_chat(m, FONT_LARGE(SPAN_NOTICE("\The [user] [pick(possible_messages)]"))) \ No newline at end of file diff --git a/code/modules/spells/targeted/genetic.dm b/code/modules/spells/targeted/genetic.dm deleted file mode 100644 index bcc5233b9b65..000000000000 --- a/code/modules/spells/targeted/genetic.dm +++ /dev/null @@ -1,73 +0,0 @@ -/* -Other mutation or disability spells can be found in -code\game\dna\genes\vg_powers.dm -code\game\dna\genes\goon_disabilities.dm -code\game\dna\genes\goon_powers.dm -*/ -/spell/targeted/genetic - name = "Genetic modifier" - desc = "This spell inflicts a set of genetic conditions upon the target." - duration = 10 SECONDS - var/list/genetic_conditions = list() - -/spell/targeted/genetic/cast(list/targets) - ..() - for(var/mob/living/target in targets) - for(var/x in genetic_conditions) - target.add_genetic_condition(x, duration) - -/spell/targeted/genetic/blind - name = "Blind" - desc = "This spell inflicts a target with temporary blindness. Does not require wizard garb." - feedback = "BD" - school = "illusion" - duration = 300 - charge_max = 300 - spell_flags = 0 - invocation = "Sty Kaly." - invocation_type = SpI_WHISPER - message = "Your eyes cry out in pain!" - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 3) - cooldown_min = 50 - range = 7 - max_targets = 0 - amt_eye_blind = 10 - amt_eye_blurry = 20 - hud_state = "wiz_blind" - cast_sound = 'sound/magic/blind.ogg' - genetic_conditions = list(GENE_COND_BLINDED) - -/spell/targeted/genetic/blind/empower_spell() - if(!..()) - return 0 - duration += 10 SECONDS - return "[src] will now blind for a longer period of time." - -/spell/targeted/genetic/blind/hysteria - name = "Hysteria" - desc = "A spell used to make someone look like a blind fool, and also makes them a blind fool." - feedback = "HY" - school = "illusion" - spell_flags = SELECTABLE - charge_max = 600 - invocation_type = SpI_SHOUT - invocation = "Sty Di Kaly!" - amt_dizziness = 10 - hud_state = "hysteria" - -/spell/targeted/genetic/blind/starburst - name = "Starburst" - desc = "Send a jolt of electricity through everyone's nerve center, blinding and stunning them." - feedback = "SB" - school = "transmutation" - invocation = "Tid Caeh Yor!" - spell_flags = NOFACTION - invocation_type = SpI_SHOUT - charge_max = 60 SECONDS - spell_flags = 0 - amt_dizziness = 0 - amt_eye_blurry = 5 - amt_stunned = 1 - effect_state = "electricity_constant" - effect_duration = 5 - hud_state = "wiz_starburst" diff --git a/code/modules/spells/targeted/glimpse_of_eternity.dm b/code/modules/spells/targeted/glimpse_of_eternity.dm deleted file mode 100644 index a4d783245ab9..000000000000 --- a/code/modules/spells/targeted/glimpse_of_eternity.dm +++ /dev/null @@ -1,26 +0,0 @@ -/spell/targeted/glimpse_of_eternity - name = "Glimpse of Eternity" - desc = "Show the non-believers what enlightenment truely means." - feedback = "GE" - school = "illusion" - invocation = "Ghe Tar Yet!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - max_targets = 0 - charge_max = 400 - range = 3 - - hud_state = "wiz_glimpse" - -/spell/targeted/glimpse_of_eternity/cast(var/list/targets, var/mob/user) - for(var/t in targets) - var/mob/living/L = t - if(L.faction != user.faction) //Worse for non-allies - SET_STATUS_MAX(L, STAT_BLIND, 5) - SET_STATUS_MAX(L, STAT_STUN, 5) - new /obj/effect/temporary(get_turf(L), 5, 'icons/effects/effects.dmi', "electricity_constant") - else - SET_STATUS_MAX(L, STAT_BLIND, 2) - L.heal_damage(BRUTE, 10, do_update_health = FALSE) - L.heal_damage(BURN, 10) - new /obj/effect/temporary(get_turf(L), 5, 'icons/effects/effects.dmi', "green_sparkles") \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/dumbfire.dm b/code/modules/spells/targeted/projectile/dumbfire.dm deleted file mode 100644 index 491a5f00f99e..000000000000 --- a/code/modules/spells/targeted/projectile/dumbfire.dm +++ /dev/null @@ -1,13 +0,0 @@ -/spell/targeted/projectile/dumbfire - selection_type = "range" - -/spell/targeted/projectile/dumbfire/choose_targets(mob/user = usr) - var/list/targets = list() - - var/starting_dir = user.dir //where are we facing at the time of casting? - var/turf/starting_turf = get_turf(user) - var/current_turf = starting_turf - for(var/i = 1; i <= src.range; i++) - current_turf = get_step(current_turf, starting_dir) - targets += current_turf - return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/fireball.dm b/code/modules/spells/targeted/projectile/fireball.dm deleted file mode 100644 index ef65dc885f73..000000000000 --- a/code/modules/spells/targeted/projectile/fireball.dm +++ /dev/null @@ -1,66 +0,0 @@ -/spell/targeted/projectile/dumbfire/fireball - name = "Fireball" - desc = "A classic spell, grants you the ability to throw an exploding ball of flame in any direction. Does not require wizard garb." - feedback = "FB" - proj_type = /obj/item/projectile/spell_projectile/fireball - - school = "conjuration" - charge_max = 10 SECONDS - spell_flags = 0 - invocation = "Oni-Soma!" - invocation_type = SpI_SHOUT - range = 20 - - level_max = list(Sp_TOTAL = 5, Sp_SPEED = 0, Sp_POWER = 5) - - duration = 20 - proj_step_delay = 1 - - amt_dam_brute = 20 - amt_dam_fire = 25 - - var/ex_severe = -1 - var/ex_heavy = 1 - var/ex_light = 2 - var/ex_flash = 5 - - hud_state = "wiz_fireball" - cast_sound = 'sound/magic/fireball.ogg' - -/spell/targeted/projectile/dumbfire/fireball/prox_cast(var/list/targets, spell_holder) - for(var/mob/living/M in targets) - apply_spell_damage(M) - explosion(get_turf(spell_holder), ex_severe, ex_heavy, ex_light, ex_flash) - -/spell/targeted/projectile/dumbfire/fireball/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER]%2 == 1) - ex_severe++ - ex_heavy++ - ex_light++ - ex_flash++ - - return "The spell [src] now has a larger explosion." - -//PROJECTILE - -/obj/item/projectile/spell_projectile/fireball - name = "fireball" - icon_state = "fireball" - -/spell/targeted/projectile/dumbfire/fireball/firebolt - name = "Firebolt" - desc = "A quick-casted fireball. Burns the user, and their enemies, but is much faster to shoot." - feedback = "FO" - charge_type = Sp_HOLDVAR - invocation = "Ignus!" - holder_var_type = "fireloss" - holder_var_amount = 10 - amt_dam_brute = 10 - amt_dam_fire = 15 - ex_heavy = -1 - ex_light = 1 - ex_flash = 3 - hud_state = "firebolt" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/magic_missile.dm b/code/modules/spells/targeted/projectile/magic_missile.dm deleted file mode 100644 index 1d72399718a9..000000000000 --- a/code/modules/spells/targeted/projectile/magic_missile.dm +++ /dev/null @@ -1,56 +0,0 @@ -/spell/targeted/projectile/magic_missile - name = "Magic Missile" - desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - feedback = "MM" - school = "conjuration" - charge_max = 150 - spell_flags = NEEDSCLOTHES - invocation = "Forti Gy-Ama!" - invocation_type = SpI_SHOUT - range = 7 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) - cooldown_min = 90 //15 deciseconds reduction per rank - - max_targets = 0 - - proj_type = /obj/item/projectile/spell_projectile/seeking/magic_missile - duration = 10 - proj_step_delay = 5 - - hud_state = "wiz_mm" - cast_sound = 'sound/magic/magic_missile.ogg' - amt_paralysis = 3 - amt_stunned = 3 - - amt_dam_fire = 10 - -/spell/targeted/projectile/magic_missile/prox_cast(var/list/targets, atom/spell_holder) - spell_holder.visible_message("\The [spell_holder] pops with a flash!") - playsound(src, 'sound/magic/mm_hit.ogg', 40) - for(var/mob/living/M in targets) - apply_spell_damage(M) - return - -/spell/targeted/projectile/magic_missile/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) - amt_paralysis += 2 - amt_stunned += 2 - return "[src] will now stun people for a longer duration." - amt_dam_fire += 5 - - return "[src] does more damage now." - - - -//PROJECTILE - -/obj/item/projectile/spell_projectile/seeking/magic_missile - name = "magic missile" - icon_state = "magicm" - - proj_trail = 1 - proj_trail_lifespan = 5 - proj_trail_icon_state = "magicmd" diff --git a/code/modules/spells/targeted/projectile/passage.dm b/code/modules/spells/targeted/projectile/passage.dm deleted file mode 100644 index b99e147bee22..000000000000 --- a/code/modules/spells/targeted/projectile/passage.dm +++ /dev/null @@ -1,46 +0,0 @@ -/spell/targeted/projectile/dumbfire/passage - name = "Passage" - desc = "throw a spell towards an area and teleport to it." - feedback = "PA" - proj_type = /obj/item/projectile/spell_projectile/passage - - - school = "conjuration" - charge_max = 250 - invocation = "A'YASAMA" - invocation_type = SpI_SHOUT - range = 15 - - - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - spell_flags = NEEDSCLOTHES - duration = 15 - - proj_step_delay = 1 - - hud_state = "gen_project" - cast_sound = 'sound/magic/lightning_bolt.ogg' - -/spell/targeted/projectile/dumbfire/passage/prox_cast(var/list/targets, atom/spell_holder) - for(var/mob/living/L in targets) - apply_spell_damage(L) - - var/turf/T = get_turf(spell_holder) - - holder.forceMove(T) - var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread() - S.set_up(3,0,T) - S.start() - playsound(src, 'sound/magic/lightningshock.ogg', 50) - -/spell/targeted/projectile/dumbfire/passage/empower_spell() - if(!..()) - return 0 - - amt_stunned += 3 - - return "[src] now stuns those who get hit by it." - -/obj/item/projectile/spell_projectile/passage - name = "spell" - icon_state = "energy2" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/projectile.dm b/code/modules/spells/targeted/projectile/projectile.dm deleted file mode 100644 index 6df791094be2..000000000000 --- a/code/modules/spells/targeted/projectile/projectile.dm +++ /dev/null @@ -1,45 +0,0 @@ -/* -Projectile spells make special projectiles (obj/item/spell_projectile) and fire them at targets -Dumbfire projectile spells fire directly ahead of the user -spell_projectiles call their spell's (carried) prox_cast when they get in range of a target -If the spell_projectile is seeking, it will update its target every process and follow them -*/ - -/spell/targeted/projectile - range = 7 - var/proj_type = /obj/item/projectile/spell_projectile //use these. They are very nice - var/proj_step_delay = 1 //lower = faster - var/cast_prox_range = 1 - -/spell/targeted/projectile/cast(list/targets, mob/user = usr) - for(var/atom/target in targets) - var/obj/item/projectile/projectile = new proj_type(user.loc, user.dir) - - if(!projectile) - return - - if(istype(projectile, /obj/item/projectile/spell_projectile)) - var/obj/item/projectile/spell_projectile/SP = projectile - SP.carried = src //casting is magical - projectile.original = target - projectile.starting = get_turf(user) - projectile.shot_from = user //fired from the user - projectile.current = projectile.original - projectile.yo = target.y - user.y - projectile.xo = target.x - user.x - projectile.life_span = src.duration - projectile.hitscan = !proj_step_delay - projectile.step_delay = proj_step_delay - projectile.launch(target) - return - -/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder) - var/list/targets = list() - for(var/mob/living/M in range(spell_holder, cast_prox_range)) - if(M == user && !(spell_flags & INCLUDEUSER)) - continue - targets += M - return targets - -/spell/targeted/projectile/proc/prox_cast(var/list/targets, var/atom/movable/spell_holder) - return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/stuncuff.dm b/code/modules/spells/targeted/projectile/stuncuff.dm deleted file mode 100644 index 520463815888..000000000000 --- a/code/modules/spells/targeted/projectile/stuncuff.dm +++ /dev/null @@ -1,47 +0,0 @@ -/spell/targeted/projectile/dumbfire/stuncuff - name = "Stun Cuff" - desc = "This spell fires out a small curse that stuns and cuffs the target." - feedback = "SC" - proj_type = /obj/item/projectile/spell_projectile/stuncuff - - charge_type = Sp_CHARGES - charge_max = 6 - charge_counter = 6 - spell_flags = 0 - invocation = "Fu'Reai Diakan!" - invocation_type = SpI_SHOUT - range = 20 - - level_max = list(Sp_TOTAL = 0, Sp_SPEED = 0, Sp_POWER = 0) - - duration = 20 - proj_step_delay = 1 - - amt_stunned = 6 - - hud_state = "wiz_cuff" - cast_sound = 'sound/magic/wandodeath.ogg' - -/spell/targeted/projectile/dumbfire/stuncuff/prox_cast(var/list/targets, spell_holder) - for(var/mob/living/M in targets) - if(ishuman(M)) - var/mob/living/human/H = M - var/obj/item/handcuffs/wizard/cuffs = new() - H.equip_to_slot(cuffs, slot_handcuffed_str) - H.visible_message("Beams of light form around \the [H]'s hands!") - apply_spell_damage(M) - - -/obj/item/handcuffs/wizard - name = "beams of light" - desc = "Undescribable and unpenetrable. Or so they say." - - breakouttime = 300 //30 seconds - -/obj/item/handcuffs/wizard/dropped(var/mob/user) - ..() - qdel(src) - -/obj/item/projectile/spell_projectile/stuncuff - name = "stuncuff" - icon_state = "spell" \ No newline at end of file diff --git a/code/modules/spells/targeted/shapeshift.dm b/code/modules/spells/targeted/shapeshift.dm deleted file mode 100644 index ae5de55a0f76..000000000000 --- a/code/modules/spells/targeted/shapeshift.dm +++ /dev/null @@ -1,203 +0,0 @@ -//basic transformation spell. Should work for most simple_animals - -/spell/targeted/shapeshift - name = "Shapeshift" - desc = "This spell transforms the target into something else for a short while." - - school = "transmutation" - - charge_type = Sp_RECHARGE - charge_max = 600 - - duration = 0 //set to 0 for permanent. - - var/list/possible_transformations = list() - var/list/newVars = list() //what the variables of the new created thing will be. - - cast_sound = 'sound/magic/charge.ogg' - var/revert_sound = 'sound/magic/charge.ogg' //the sound that plays when something gets turned back. - var/share_damage = 1 //do we want the damage we take from our new form to move onto our real one? (Only counts for finite duration) - var/drop_items = 1 //do we want to drop all our items when we transform? - var/toggle = 0 //Can we toggle this? - var/list/transformed_dudes = list() //Who we transformed. Transformed = Transformation. Both mobs. - -/spell/targeted/shapeshift/cast(var/list/targets, mob/user) - for(var/m in targets) - var/mob/living/M = m - if(M.stat == DEAD) - to_chat(user, "[name] can only transform living targets.") - continue - if(M.buckled) - M.buckled.unbuckle_mob() - if(toggle && transformed_dudes.len && stop_transformation(M)) - continue - var/new_mob = pick(possible_transformations) - - var/mob/living/trans = new new_mob(get_turf(M)) - for(var/varName in newVars) //stolen shamelessly from Conjure - if(varName in trans.vars) - trans.vars[varName] = newVars[varName] - //Give them our languages - for(var/decl/language/lang as anything in M.languages) - trans.add_language(lang.type) - - trans.SetName("[trans.name] ([M])") - if(ishuman(M) && drop_items) - for(var/obj/item/I in M.contents) - M.drop_from_inventory(I) - if(M.mind) - M.mind.transfer_to(trans) - else - trans.key = M.key - new /obj/effect/temporary(get_turf(M), 5, 'icons/effects/effects.dmi', "summoning") - - M.forceMove(trans) //move inside the new dude to hide him. - M.status_flags |= GODMODE //dont want him to die or breathe or do ANYTHING - transformed_dudes[trans] = M - events_repository.register(/decl/observ/death, trans,src, TYPE_PROC_REF(/spell/targeted/shapeshift, stop_transformation)) - events_repository.register(/decl/observ/destroyed, trans,src, TYPE_PROC_REF(/spell/targeted/shapeshift, stop_transformation)) - events_repository.register(/decl/observ/destroyed, M, src, TYPE_PROC_REF(/spell/targeted/shapeshift, destroyed_transformer)) - if(duration) - spawn(duration) - stop_transformation(trans) - -/spell/targeted/shapeshift/proc/destroyed_transformer(var/mob/target) //Juuuuust in case - var/mob/current = transformed_dudes[target] - to_chat(current, "You suddenly feel as if this transformation has become permanent...") - remove_target(target) - -/spell/targeted/shapeshift/proc/stop_transformation(var/mob/living/target) - var/mob/living/transformer = transformed_dudes[target] - if(!transformer) - return FALSE - transformer.status_flags &= ~GODMODE - if(share_damage) - var/transformer_max_health = transformer.get_max_health() - var/damage = transformer.set_max_health(transformer_max_health-round(transformer_max_health*(transformer.get_health_ratio()))) - for(var/i in 1 to ceil(damage/10)) - transformer.take_damage(10) - if(target.mind) - target.mind.transfer_to(transformer) - else - transformer.key = target.key - playsound(get_turf(target), revert_sound, 50, 1) - transformer.forceMove(get_turf(target)) - remove_target(target) - qdel(target) - return TRUE - -/spell/targeted/shapeshift/proc/remove_target(var/mob/living/target) - var/mob/current = transformed_dudes[target] - events_repository.unregister(/decl/observ/destroyed, target,src) - events_repository.unregister(/decl/observ/death, current,src) - events_repository.unregister(/decl/observ/destroyed, current,src) - transformed_dudes[target] = null - transformed_dudes -= target - -/spell/targeted/shapeshift/baleful_polymorph - name = "Baleful Polymorth" - desc = "This spell transforms its target into a small, furry animal." - feedback = "BP" - possible_transformations = list( - /mob/living/simple_animal/lizard, - /mob/living/simple_animal/passive/mouse, - /mob/living/simple_animal/passive/mouse/rat, - /mob/living/simple_animal/corgi - ) - - share_damage = 0 - invocation = "Yo'balada!" - invocation_type = SpI_SHOUT - spell_flags = NEEDSCLOTHES | SELECTABLE - range = 3 - duration = 150 //15 seconds. - cooldown_min = 200 //20 seconds - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - - newVars = list("health" = 50, "max_health" = 50) - - hud_state = "wiz_poly" - - -/spell/targeted/shapeshift/baleful_polymorph/empower_spell() - if(!..()) - return 0 - - duration += 50 - - return "Your target will now stay in their polymorphed form for [duration/10] seconds." - -/spell/targeted/shapeshift/avian - name = "Polymorph" - desc = "This spell transforms the wizard into the common parrot." - feedback = "AV" - possible_transformations = list(/mob/living/simple_animal/hostile/parrot) - - drop_items = 0 - share_damage = 0 - invocation = "Poli'crakata!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - duration = 150 - charge_max = 600 - cooldown_min = 300 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 0) - hud_state = "wiz_parrot" - -/spell/targeted/shapeshift/corrupt_form - name = "Corrupt Form" - desc = "This spell shapes the wizard into a terrible, terrible beast." - feedback = "CF" - possible_transformations = list(/mob/living/simple_animal/hostile/revenant) - - invocation = "mutters something dark and twisted as their form begins to twist..." - invocation_type = SpI_EMOTE - spell_flags = INCLUDEUSER - range = -1 - duration = 150 - charge_max = 1200 - cooldown_min = 600 - - drop_items = 0 - share_damage = 0 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 2) - - newVars = list("name" = "corrupted soul") - - hud_state = "wiz_corrupt" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/targeted/shapeshift/corrupt_form/empower_spell() - if(!..()) - return 0 - - switch(spell_levels[Sp_POWER]) - if(1) - duration *= 2 - return "You will now stay corrupted for [duration/10] seconds." - if(2) - newVars = list("name" = "\proper corruption incarnate", - "melee_damage_upper" = 25, - "resistance" = 6, - "health" = 125, - "max_health" = 125) - duration = 0 - return "You revel in the corruption. There is no turning back." - -/spell/targeted/shapeshift/familiar - name = "Transform" - desc = "Transform into a familiar form. Literally." - feedback = "FA" - possible_transformations = list() - drop_items = 0 - invocation_type = SpI_EMOTE - invocation = "'s body dissipates into a pale mass of light, then reshapes!" - range = -1 - spell_flags = INCLUDEUSER - duration = 0 - charge_max = 2 MINUTES - toggle = 1 - - hud_state = "wiz_carp" \ No newline at end of file diff --git a/code/modules/spells/targeted/shatter_mind.dm b/code/modules/spells/targeted/shatter_mind.dm deleted file mode 100644 index f84d6765035d..000000000000 --- a/code/modules/spells/targeted/shatter_mind.dm +++ /dev/null @@ -1,29 +0,0 @@ -/spell/targeted/shatter - name = "Shatter Mind" - desc = "Assaults the mind of the target with fear of the unknown, shattering their sanity and causing brain damage." - feedback = "SM" - school = "illusion" - charge_max = 300 - spell_flags = 0 - invocation_type = SpI_NONE - range = 5 - max_targets = 1 - compatible_mobs = list(/mob/living/human) - - time_between_channels = 150 - number_of_channels = 0 - - hud_state = "wiz_statue" - -/spell/targeted/shatter/cast(var/list/targets, var/mob/user) - var/mob/living/human/H = targets[1] - if(prob(50)) - sound_to(user, get_sfx("swing_hit")) - if(prob(5)) - to_chat(H, "You feel unhinged.") - H.adjust_hallucination(5,5) - ADJ_STATUS(H, STAT_CONFUSE, 2) - ADJ_STATUS(H, STAT_DIZZY, 2) - if(H.hallucination_power > 50) - H.take_damage(5, BRAIN) - to_chat(H, "You feel your mind tearing apart!") \ No newline at end of file diff --git a/code/modules/spells/targeted/shift.dm b/code/modules/spells/targeted/shift.dm index 2b53b60d2441..2bcc684939a6 100644 --- a/code/modules/spells/targeted/shift.dm +++ b/code/modules/spells/targeted/shift.dm @@ -21,4 +21,4 @@ flick("phase_shift2",animation) /spell/targeted/ethereal_jaunt/shift/jaunt_steam(var/mobloc) - return \ No newline at end of file + return diff --git a/code/modules/spells/targeted/subjugate.dm b/code/modules/spells/targeted/subjugate.dm deleted file mode 100644 index 700dac35b36d..000000000000 --- a/code/modules/spells/targeted/subjugate.dm +++ /dev/null @@ -1,35 +0,0 @@ -/spell/targeted/subjugation - name = "Subjugation" - desc = "This spell temporarily subjugates a target's mind and does not require wizard garb." - feedback = "SJ" - school = "illusion" - charge_max = 500 - spell_flags = NOFACTION - invocation = "Dii Oda Baji." - invocation_type = SpI_WHISPER - - message = "You suddenly feel completely overwhelmed!" - - max_targets = 1 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 0, Sp_POWER = 3) - - amt_dizziness = 100 - amt_confused = 100 - amt_stuttering = 100 - - compatible_mobs = list(/mob/living/human) - - hud_state = "wiz_subj" - -/spell/targeted/subjugation/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) - max_targets = 0 - - return "[src] will now effect everyone in the area." - else - max_targets++ - return "[src] will now effect [max_targets] people." \ No newline at end of file diff --git a/code/modules/spells/targeted/swap.dm b/code/modules/spells/targeted/swap.dm deleted file mode 100644 index 150bd9030772..000000000000 --- a/code/modules/spells/targeted/swap.dm +++ /dev/null @@ -1,41 +0,0 @@ -/spell/targeted/swap - name = "swap" - desc = "This spell swaps the positions of the wizard and a target. Causes brain damage." - feedback = "SW" - school = "conjuration" - - charge_type = Sp_HOLDVAR - holder_var_type = "brainloss" - holder_var_amount = 10 - - invocation = "Joyo!" - invocation_type = SpI_WHISPER - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 0, Sp_POWER = 2) - - spell_flags = Z2NOCAST - range = 6 - max_targets = 1 - compatible_mobs = list(/mob/living) - - hud_state = "wiz_swap" - - cast_sound = 'sound/magic/mandswap.ogg' - -/spell/targeted/swap/cast(var/list/targets, mob/user) - for(var/mob/T in targets) - var/turf/aT = get_turf(T) - var/turf/bT = get_turf(user) - - T.forceMove(bT) - user.forceMove(aT) - - apply_spell_damage(T) - -/spell/targeted/swap/empower_spell() - if(!..()) - return 0 - - amt_eye_blind += 2 - - return "This spell will now blind the target." diff --git a/code/modules/spells/targeted/targeted.dm b/code/modules/spells/targeted/targeted.dm index 46e6e242b26b..733bbf1e5403 100644 --- a/code/modules/spells/targeted/targeted.dm +++ b/code/modules/spells/targeted/targeted.dm @@ -3,7 +3,6 @@ Targeted spells (with the exception of dumbfire) select from all the mobs in the Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm */ - /spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast @@ -62,10 +61,6 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp for(var/mob/living/M in starting_targets) if(!(spell_flags & INCLUDEUSER) && M == user) continue - if((spell_flags & NOFACTION) && user.faction == M.faction) - continue - if((spell_flags & NONONFACTION) && user.faction != M.faction) - continue if(compatible_mobs && compatible_mobs.len) if(!is_type_in_list(M, compatible_mobs)) continue if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs)) @@ -73,12 +68,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp possible_targets += M if(possible_targets.len) - if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details - var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(temp_target) - targets += temp_target - else - targets += pick(possible_targets) + targets += pick(possible_targets) //Adds a safety check post-input to make sure those targets are actually in range. @@ -98,28 +88,15 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp continue possible_targets += target - if(spell_flags & SELECTABLE) - for(var/i = 1; i<=max_targets, i++) - if(!possible_targets.len) - break - var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(!M) - break - if(range != -2) - if(!(M in view_or_range(range, holder, selection_type))) - continue - targets += M - possible_targets -= M - else - for(var/i=1,i<=max_targets,i++) - if(!possible_targets.len) - break - if(target_ignore_prev) - var/target = pick(possible_targets) - possible_targets -= target - targets += target - else - targets += pick(possible_targets) + for(var/i=1,i<=max_targets,i++) + if(!possible_targets.len) + break + if(target_ignore_prev) + var/target = pick(possible_targets) + possible_targets -= target + targets += target + else + targets += pick(possible_targets) if(!(spell_flags & INCLUDEUSER) && (user in targets)) targets -= user @@ -172,4 +149,4 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp ADJ_STATUS(target, STAT_STUTTER, amt_stuttering) if(effect_state) var/obj/o = new /obj/effect/temporary(get_turf(target), effect_duration, 'icons/effects/effects.dmi', effect_state) - o.color = effect_color \ No newline at end of file + o.color = effect_color diff --git a/code/modules/spells/targeted/torment.dm b/code/modules/spells/targeted/torment.dm deleted file mode 100644 index e98836699f30..000000000000 --- a/code/modules/spells/targeted/torment.dm +++ /dev/null @@ -1,34 +0,0 @@ -/spell/targeted/torment - name = "Torment" - desc = "Darkness stabs at the bodies of those around you. All within a medium range will suffer significant pain." - feedback = "TM" - school = "illusion" - charge_max = 150 - spell_flags = NOFACTION - invocation = "Rai Di-Kaal!" - invocation_type = SpI_SHOUT - range = 5 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - cooldown_min = 50 - message = "So much pain! All you can hear is screaming!" - - max_targets = 0 - compatible_mobs = list(/mob/living/human) - - var/loss = 30 - - hud_state = "wiz_horse" - cast_sound = 'sound/magic/cowhead_curse.ogg' - -/spell/targeted/torment/cast(var/list/targets, var/mob/user) - user.spawn_gibber() - for(var/mob/living/human/H in targets) - H.take_damage(loss, PAIN) - -/spell/targeted/torment/empower_spell() - if(!..()) - return 0 - - loss += 30 - - return "[src] will now cause more pain." \ No newline at end of file diff --git a/config/example/configuration.txt b/config/example/configuration.txt index 13bfd6b1c6db..2c603dbfd791 100644 --- a/config/example/configuration.txt +++ b/config/example/configuration.txt @@ -345,22 +345,19 @@ ROUNDSTART_LEVEL_GENERATION ## If uncommented, votes can be called to add extra antags to the round. Uncomment to enable. #ALLOW_EXTRA_ANTAGS -## Remove the # to make rounds which end instantly (Rev, Wizard, Malf) to continue until the shuttle is called or the station is nuked. +## Remove the # to make rounds which end instantly continue until the shuttle is called or the station is nuked. ## Malf and Rev will let the shuttle be called when the antags/protags are dead. ## Uncomment to enable. #CONTINUOUS_ROUNDS -## Spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard. Uncomment to enable. -#FEATURE_OBJECT_SPELL_SYSTEM - ## Allowed modes. -#MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","spyvspy","traitor","wizard"] +#MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","spyvspy","traitor"] ## Mode names. -#MODE_NAMES {"calamity":"Calamity","extended":"Extended","mercenary":"Mercenary","wizard":"Wizard","cult":"Cult","heist":"Heist","ninja":"Ninja","revolution":"Revolution","traitor":"Traitor","spyvspy":"Spy v. spy","crossfire":"Crossfire"} +#MODE_NAMES {"calamity":"Calamity","extended":"Extended","mercenary":"Mercenary","cult":"Cult","heist":"Heist","ninja":"Ninja","revolution":"Revolution","traitor":"Traitor","spyvspy":"Spy v. spy","crossfire":"Crossfire"} ## Relative probability of each mode. -#PROBABILITIES {"calamity":0,"extended":1,"mercenary":1,"wizard":1,"cult":1,"heist":0,"ninja":0,"revolution":0,"traitor":0,"spyvspy":0,"crossfire":0} +#PROBABILITIES {"calamity":0,"extended":1,"mercenary":1,"cult":1,"heist":0,"ninja":0,"revolution":0,"traitor":0,"spyvspy":0,"crossfire":0} ## If security is prohibited from being most antagonists. Uncomment to enable. #PROTECT_ROLES_FROM_ANTAGONIST @@ -369,7 +366,7 @@ ROUNDSTART_LEVEL_GENERATION #TRAITOR_SCALING ## A list of modes that should be votable. -#VOTABLE_MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","secret","spyvspy","traitor","wizard"] +#VOTABLE_MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","secret","spyvspy","traitor"] ## # PROTECTED @@ -377,13 +374,13 @@ ROUNDSTART_LEVEL_GENERATION ## ## Password used for authorizing external tools that can apply bans. -#BAN_COMMS_PASSWORD +#BAN_COMMS_PASSWORD ## Password used for authorizing ircbot and other external tools. -#COMMS_PASSWORD +#COMMS_PASSWORD ## Export address where external tools that monitor logins are located. -#LOGIN_EXPORT_ADDR +#LOGIN_EXPORT_ADDR ## # RESOURCES @@ -413,7 +410,7 @@ ROUNDSTART_LEVEL_GENERATION #ABANDON_ALLOWED 1 ## IRC channel to send adminhelps to. Leave blank to disable adminhelps-to-irc. -#ADMIN_IRC +#ADMIN_IRC ## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system. #ADMIN_LEGACY_SYSTEM 1 @@ -431,7 +428,7 @@ ROUNDSTART_LEVEL_GENERATION #AOOC_ALLOWED 1 ## Ban appeals URL - usually for a forum or wherever people should go to contact your admins. -#BANAPPEALS +#BANAPPEALS ## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system. #BAN_LEGACY_SYSTEM 1 @@ -452,7 +449,7 @@ ROUNDSTART_LEVEL_GENERATION #DISABLE_WEBHOOK_EMBEDS ## Discord server permanent invite address. -#DISCORDURL +#DISCORDURL ## Comment to disable the dead OOC channel by default. #DOOC_ALLOWED 1 @@ -473,20 +470,20 @@ ROUNDSTART_LEVEL_GENERATION #FORBID_SINGULO_POSSESSION ## Discussion forum address. -#FORUMURL +#FORUMURL ## Defines world FPS. Defaults to 20. ## Can also accept ticklag values (0.9, 0.5, etc) which will automatically be converted to FPS. #FPS 20 ## GitHub address. -#GITHUBURL +#GITHUBURL ## Determines whether or not people without a registered ckey (i.e. guest-*) can connect to your server. Uncomment to enable. #GUESTS_ALLOWED ## Set a hosted by name for UNIX platforms. -#HOSTEDBY +#HOSTEDBY ## Hub visibility: If you want to be visible on the hub, uncomment the below line and be sure that Dream Daemon is set to visible. This can be changed in-round as well with toggle-hub-visibility if Dream Daemon is set correctly. Uncomment to enable. #HUB_VISIBILITY @@ -495,7 +492,7 @@ ROUNDSTART_LEVEL_GENERATION #IRC_BOT_HOST localhost ## GitHub new issue address. -#ISSUEREPORTURL +#ISSUEREPORTURL ## Add a # here if you wish to use the setup where jobs have more access. This is intended for servers with low populations - where there are not enough players to fill all roles, so players need to do more than just one job. Also for servers where they don't want people to hide in their own departments. #JOBS_HAVE_MINIMAL_ACCESS 1 @@ -554,11 +551,11 @@ ROUNDSTART_LEVEL_GENERATION #RESPAWN_DELAY 30 ## Set a server location for world reboot. Don't include the byond://, just give the address and port. -#SERVER +#SERVER ## Set a server URL for the IRC bot to use; like SERVER, don't include the byond:// ## Unlike SERVER, this one shouldn't break auto-reconnect. -#SERVERURL +#SERVERURL ## Server name: This appears at the top of the screen in-game. #SERVER_NAME Nebula 13 @@ -591,7 +588,7 @@ USEALIENWHITELIST #WAIT_FOR_SIGUSR1_REBOOT ## Wiki address. -#WIKIURL +#WIKIURL ## # VOTING diff --git a/maps/antag_spawn/wizard/wizard.dm b/maps/antag_spawn/wizard/wizard.dm deleted file mode 100644 index 4ca75cd145d4..000000000000 --- a/maps/antag_spawn/wizard/wizard.dm +++ /dev/null @@ -1,13 +0,0 @@ -/datum/map_template/ruin/antag_spawn/wizard - name = "Wizard Base" - suffixes = list("wizard/wizard_base.dmm") - apc_test_exempt_areas = list( - /area/map_template/wizard_station = NO_SCRUBBER|NO_VENT|NO_APC - ) - -/area/map_template/wizard_station - name = "\improper Wizard's Den" - icon_state = "yellow" - requires_power = 0 - dynamic_lighting = FALSE - req_access = list(access_wizard) diff --git a/maps/antag_spawn/wizard/wizard_base.dmm b/maps/antag_spawn/wizard/wizard_base.dmm deleted file mode 100644 index abc19fb4422c..000000000000 --- a/maps/antag_spawn/wizard/wizard_base.dmm +++ /dev/null @@ -1,1747 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space/infinity, -/area/space) -"ab" = ( -/turf/unsimulated/wall, -/area/map_template/wizard_station) -"ac" = ( -/obj/structure/table/wood, -/obj/item/backpack/cultpack, -/turf/floor/carpet, -/area/map_template/wizard_station) -"ad" = ( -/turf/unsimulated/wall/fakeglass/alt{ - dir = 8 - }, -/area/map_template/wizard_station) -"ae" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 4 - }, -/area/map_template/wizard_station) -"af" = ( -/obj/structure/table/wood, -/obj/item/backpack/satchel/grey/withwallet, -/turf/floor/carpet, -/area/map_template/wizard_station) -"ag" = ( -/turf/floor/carpet, -/area/map_template/wizard_station) -"ah" = ( -/obj/structure/undies_wardrobe, -/turf/floor/carpet, -/area/map_template/wizard_station) -"ai" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 8 - }, -/area/map_template/wizard_station) -"aj" = ( -/obj/structure/door/wood, -/turf/floor/carpet, -/area/map_template/wizard_station) -"ak" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp/green{ - on = 0; - pixel_x = -3; - pixel_y = 8 - }, -/obj/item/chems/drinks/flask/barflask, -/turf/floor/carpet, -/area/map_template/wizard_station) -"al" = ( -/obj/structure/table/wood, -/obj/item/dice, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"am" = ( -/obj/structure/bed/padded, -/obj/item/bedsheet/rd, -/turf/floor/carpet, -/area/map_template/wizard_station) -"an" = ( -/obj/structure/table/wood, -/obj/item/dice/d20, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"ao" = ( -/obj/structure/table/wood, -/obj/item/backpack/satchel/grey/withwallet, -/obj/item/clothing/glasses/eyepatch/monocle, -/turf/floor/carpet, -/area/map_template/wizard_station) -"ap" = ( -/mob/living/human/monkey{ - name = "Murphey" - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aq" = ( -/obj/structure/table/wood, -/obj/item/food/chawanmushi, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"ar" = ( -/obj/structure/table/wood, -/obj/abstract/landmark{ - name = "Teleport-Scroll" - }, -/obj/item/toy/figure/ninja, -/turf/floor/carpet, -/area/map_template/wizard_station) -"as" = ( -/obj/structure/table/wood, -/obj/item/megaphone, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"at" = ( -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"au" = ( -/obj/structure/table/wood, -/obj/item/cash/c1, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"av" = ( -/obj/structure/table/wood, -/obj/machinery/chemical_dispenser/bar_soft/full, -/obj/item/radio/intercom/wizard{ - dir = 8; - pixel_x = 22 - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aw" = ( -/obj/machinery/vending/magivend, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"ax" = ( -/obj/structure/bed/chair/wood/wings{ - dir = 8 - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"ay" = ( -/obj/abstract/landmark/start{ - name = "wizard" - }, -/turf/floor/carpet, -/area/map_template/wizard_station) -"az" = ( -/obj/structure/aliumizer, -/turf/floor/carpet, -/area/map_template/wizard_station) -"aA" = ( -/obj/item/radio/intercom/wizard{ - dir = 8; - pixel_x = 22 - }, -/turf/floor/carpet, -/area/map_template/wizard_station) -"aB" = ( -/obj/structure/bookcase{ - name = "Forbidden Knowledge" - }, -/obj/effect/decal/cleanable/cobweb, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aC" = ( -/obj/structure/bookcase{ - name = "bookcase (Tactics)" - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aD" = ( -/obj/structure/bookcase, -/obj/item/book/manual/nuclear, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aE" = ( -/obj/structure/bookcase{ - name = "Forbidden Knowledge" - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aF" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 1 - }, -/area/map_template/wizard_station) -"aG" = ( -/turf/unsimulated/floor/water, -/area/map_template/wizard_station) -"aH" = ( -/obj/structure/bookcase, -/obj/item/book/manual/robotics_cyborgs, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aI" = ( -/obj/item/bikehorn/rubberducky, -/turf/unsimulated/floor/water, -/area/map_template/wizard_station) -"aJ" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/obj/machinery/acting/changer/mirror{ - pixel_y = 32 - }, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"aK" = ( -/obj/structure/hygiene/toilet{ - pixel_y = 8 - }, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"aL" = ( -/obj/structure/table/wood, -/obj/item/radio/intercom/wizard{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aM" = ( -/obj/structure/closet/coffin, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"aN" = ( -/obj/structure/bed/chair/wood/wings{ - dir = 4 - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aO" = ( -/obj/structure/table/wood, -/obj/item/box/cups, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aP" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/red, -/obj/item/clothing/shoes/sandal, -/obj/item/clothing/head/wizard/red, -/obj/item/staff/crystal/beacon, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"aQ" = ( -/obj/structure/table/wood, -/obj/item/bag/cash, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aR" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/marisa, -/obj/item/clothing/shoes/sandal/marisa, -/obj/item/clothing/head/wizard/marisa, -/obj/item/staff/broom, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"aS" = ( -/obj/structure/table/wood, -/obj/item/box/candles, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aT" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/magusblue, -/obj/item/clothing/head/wizard/magus, -/obj/item/staff/crystal, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"aU" = ( -/obj/structure/closet, -/obj/item/chems/drinks/bottle/pwine, -/obj/item/chems/drinks/bottle/agedwhiskey, -/obj/item/chems/drinks/bottle/cognac, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"aV" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"aW" = ( -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"aX" = ( -/obj/structure/door/iron, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"aY" = ( -/obj/structure/table/wood, -/obj/item/box/fancy/donut, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"aZ" = ( -/obj/structure/door/wood, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"ba" = ( -/obj/structure/door/silver, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"bb" = ( -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"bc" = ( -/turf/unsimulated/wall/fakeglass, -/area/map_template/wizard_station) -"bd" = ( -/obj/item/soap, -/turf/unsimulated/floor/water, -/area/map_template/wizard_station) -"be" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/obj/item/radio/intercom/wizard{ - dir = 1; - pixel_y = -30 - }, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"bf" = ( -/obj/structure/hygiene/sink{ - dir = 4; - pixel_x = 11 - }, -/obj/structure/mirror{ - pixel_x = 32 - }, -/turf/unsimulated/floor/freezer, -/area/map_template/wizard_station) -"bg" = ( -/obj/structure/table/wood, -/obj/item/chems/glass/bowl/mapped/meatball, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"bh" = ( -/obj/structure/closet, -/obj/item/clothing/jumpsuit/psysuit, -/obj/item/clothing/suit/wizrobe/psypurple, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"bi" = ( -/turf/unsimulated/wall/fakeglass/alt{ - dir = 1 - }, -/area/map_template/wizard_station) -"bj" = ( -/obj/structure/closet, -/obj/item/clothing/shoes/sandal/marisa{ - desc = "A set of fancy shoes that are as functional as they are comfortable."; - name = "Gentlemans Shoes" - }, -/obj/item/clothing/shirt/button/black, -/obj/item/clothing/suit/jacket/vest/gray, -/obj/item/clothing/suit/wizrobe/gentlecoat, -/obj/item/clothing/head/wizard/cap, -/obj/item/cane/fancy, -/obj/item/radio/intercom/wizard{ - dir = 1; - pixel_y = -30 - }, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"bk" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/magusred, -/obj/item/clothing/head/wizard/magus, -/obj/item/staff/crystal/beacon, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"bl" = ( -/obj/structure/closet, -/obj/item/briefcase, -/turf/unsimulated/floor/lino, -/area/map_template/wizard_station) -"bm" = ( -/obj/structure/bookcase, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"bn" = ( -/obj/item/radio/intercom/wizard{ - dir = 1; - pixel_y = -30 - }, -/turf/unsimulated/floor/laminate, -/area/map_template/wizard_station) -"bo" = ( -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bp" = ( -/obj/item/radio/intercom/wizard{ - pixel_y = 20 - }, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bq" = ( -/obj/structure/fake_pylon, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"br" = ( -/obj/structure/meat_hook, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bs" = ( -/obj/item/remains/human, -/turf/unsimulated/floor/lava, -/area/map_template/wizard_station) -"bt" = ( -/turf/unsimulated/floor/lava, -/area/map_template/wizard_station) -"bu" = ( -/turf/unsimulated/floor/grass, -/area/map_template/wizard_station) -"bv" = ( -/obj/structure/flora/bush/fullgrass, -/turf/unsimulated/floor/grass, -/area/map_template/wizard_station) -"bw" = ( -/mob/living/simple_animal/hostile/creature{ - name = "Experiment 35b" - }, -/turf/unsimulated/floor/lava, -/area/map_template/wizard_station) -"bx" = ( -/obj/structure/talisman_altar, -/obj/item/knife/ritual, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"by" = ( -/obj/structure/table/wood, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bz" = ( -/obj/effect/gateway/active/spooky, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bA" = ( -/obj/structure/table/marble, -/obj/item/flashlight/slime, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bB" = ( -/mob/living/simple_animal/hostile/goat{ - name = "Experiment 97d" - }, -/turf/unsimulated/floor/grass, -/area/map_template/wizard_station) -"bC" = ( -/obj/structure/flora/bush/grassybush, -/turf/unsimulated/floor/grass, -/area/map_template/wizard_station) -"bD" = ( -/obj/structure/flora/pottedplant/unusual, -/turf/unsimulated/floor/cult, -/area/map_template/wizard_station) -"bE" = ( -/turf/unsimulated/floor/asteroid, -/area/map_template/wizard_station) -"bF" = ( -/obj/effect/overlay/palmtree_r, -/turf/unsimulated/floor/asteroid, -/area/map_template/wizard_station) -"bG" = ( -/mob/living/simple_animal/crab{ - name = "Experiment 68a" - }, -/turf/unsimulated/floor/asteroid, -/area/map_template/wizard_station) -"bH" = ( -/obj/effect/overlay/coconut, -/turf/unsimulated/floor/asteroid, -/area/map_template/wizard_station) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aF -bi -bc -ab -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aG -aG -bd -ab -aa -aa -aa -aa -aa -aa -aa -ab -bs -bt -bt -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aI -aG -aG -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bt -bt -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aJ -aV -be -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bw -bt -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aK -aW -bf -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bt -bs -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aX -ab -ab -ab -aa -aa -aa -aa -aa -ab -ab -aF -bi -bc -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -aE -aL -at -aw -aD -ab -ab -aa -aa -aa -ab -ab -bq -bo -bx -bo -bq -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -ab -ab -ab -ab -ab -ab -aB -at -at -at -at -at -bm -ab -aF -bi -bc -ab -aM -bo -bo -bo -bo -bo -bD -ab -ab -ab -ab -ab -ab -aa -aa -aa -"} -(16,1,1) = {" -aa -aa -aa -ai -ak -ar -ac -af -ab -al -at -aN -as -aN -at -aQ -ab -at -at -bn -ab -bo -bo -ai -ab -ai -bo -bo -ai -bE -bE -bE -bH -ab -aa -aa -aa -"} -(17,1,1) = {" -aa -aa -aa -ad -am -ay -ag -ag -aj -at -at -aq -aY -bg -at -at -ba -at -at -at -ba -bo -bo -ad -bz -ad -bo -by -ad -bE -bE -bG -bE -ab -aa -aa -aa -"} -(18,1,1) = {" -aa -aa -aa -ae -ao -az -aA -ah -ab -an -ap -ax -au -ax -at -aS -ab -at -at -at -ab -bp -bo -ae -ab -ae -bo -bo -ae -bE -bF -bE -bE -ab -aa -aa -aa -"} -(19,1,1) = {" -aa -aa -aa -ab -ab -ab -ab -ab -ab -aC -at -at -at -at -at -bm -ab -aF -bi -bc -ab -aM -bo -bo -bo -bo -bo -bD -ab -ab -ab -ab -ab -ab -aa -aa -aa -"} -(20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -aC -aO -at -av -aH -ab -ab -aa -aa -aa -ab -ab -br -bo -bA -bo -br -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -"} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aZ -ab -ab -ab -aa -aa -aa -aa -aa -ab -ab -aF -bi -bc -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aP -bb -bh -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bu -bC -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aR -bb -bj -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bu -bu -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aT -bb -bk -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bB -bu -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aU -bb -bl -ab -aa -aa -aa -aa -aa -aa -aa -ab -bv -bu -bu -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aF -bi -bc -ab -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/mods/content/corporate/items/stamps.dm b/mods/content/corporate/items/stamps.dm index cfc6df4dbbf9..35b358297287 100644 --- a/mods/content/corporate/items/stamps.dm +++ b/mods/content/corporate/items/stamps.dm @@ -4,7 +4,7 @@ /obj/item/stamp/hop name = "head of personnel's rubber stamp" - icon = 'icons/obj/items/stamps/stamp_xo.dmi' + icon = 'icons/obj/items/stamps/stamp_cap.dmi' /obj/item/stamp/ce name = "chief engineer's rubber stamp" @@ -32,7 +32,7 @@ /obj/item/stamp/ward name = "warden's rubber stamp" - icon = 'icons/obj/items/stamps/stamp_cos.dmi' + icon = 'icons/obj/items/stamps/stamp_brig.dmi' /obj/item/stamp/internalaffairs name = "internal affairs' rubber stamp" diff --git a/mods/content/psionics/_psionics.dme b/mods/content/psionics/_psionics.dme index 7bf5f2f680d3..df5544cffe15 100644 --- a/mods/content/psionics/_psionics.dme +++ b/mods/content/psionics/_psionics.dme @@ -17,6 +17,7 @@ #include "items\_items.dm" #include "items\brain.dm" #include "items\cerebro_enhancers.dm" +#include "items\clothing.dm" #include "items\coffee_cup.dm" #include "items\foundation_implanter.dm" #include "items\foundation_labcoat.dm" diff --git a/mods/content/psionics/datum/antagonists/paramount.dm b/mods/content/psionics/datum/antagonists/paramount.dm index 5d4da1a87759..d00ab6c5c979 100644 --- a/mods/content/psionics/datum/antagonists/paramount.dm +++ b/mods/content/psionics/datum/antagonists/paramount.dm @@ -17,7 +17,7 @@ name = "Special Role - Paramount Grandmaster" head = /obj/item/clothing/head/helmet/space/psi_amp uniform = /obj/item/clothing/jumpsuit/psysuit - suit = /obj/item/clothing/suit/wizrobe/psypurple + suit = /obj/item/clothing/suit/paramount shoes = /obj/item/clothing/shoes/jackboots back = /obj/item/backpack/satchel gloves = /obj/item/clothing/gloves/grey diff --git a/mods/content/psionics/datum/chems.dm b/mods/content/psionics/datum/chems.dm index c19db16e091e..1bc713de0eb3 100644 --- a/mods/content/psionics/datum/chems.dm +++ b/mods/content/psionics/datum/chems.dm @@ -1,6 +1,5 @@ /decl/material/liquid/crystal_agent/do_material_check(var/mob/living/M) - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - . = (M.get_ability_handler(/datum/ability_handler/psionics) || (M.mind && wizards.is_antagonist(M.mind))) ? /decl/material/nullglass : ..() + . = !!M.get_ability_handler(/datum/ability_handler/psionics) ? /decl/material/nullglass : ..() /decl/material/liquid/glowsap/gleam/affect_overdose(mob/living/M, total_dose) ..() @@ -13,15 +12,12 @@ required_reagents = list(/decl/material/liquid/blood = 15, /decl/material/liquid/crystal_agent = 1) result_amount = 1 -// TODO: #if defined(GAMEMODE_PACK_CULT) && defined(GAMEMODE_PACK_WIZARD) -// once wizard is modpacked #ifdef GAMEMODE_PACK_CULT /decl/chemical_reaction/synthesis/nullglass/get_alternate_reaction_indicator(var/datum/reagents/holder) var/list/blood_data = REAGENT_DATA(holder, /decl/material/liquid/blood) var/weakref/donor_ref = LAZYACCESS(blood_data, DATA_BLOOD_DONOR) var/mob/living/donor = donor_ref?.resolve() - var/decl/special_role/wizard/wizards = GET_DECL(/decl/special_role/wizard) - . = (istype(donor) && (!!donor.get_ability_handler(/datum/ability_handler/psionics) || (donor.mind && wizards.is_antagonist(donor.mind)))) + . = istype(donor) && !!donor.get_ability_handler(/datum/ability_handler/psionics) #endif /decl/chemical_reaction/synthesis/nullglass/on_reaction(datum/reagents/holder, created_volume, reaction_flags, list/reaction_data) diff --git a/mods/content/psionics/items/clothing.dm b/mods/content/psionics/items/clothing.dm new file mode 100644 index 000000000000..32e5786c2440 --- /dev/null +++ b/mods/content/psionics/items/clothing.dm @@ -0,0 +1,16 @@ +/obj/item/clothing/suit/paramount + name = "purple robes" + desc = "Heavy, royal purple robes threaded with psychic amplifiers and weird, bulbous lenses. Do not machine wash." + icon = 'icons/clothing/suits/wizard/psy.dmi' + gender = PLURAL + permeability_coefficient = 0.01 + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, + ARMOR_LASER = ARMOR_LASER_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_MINOR, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.8 \ No newline at end of file diff --git a/mods/gamemodes/cult/_cult.dme b/mods/gamemodes/cult/_cult.dme index e35ffed9db68..82d4e19aed59 100644 --- a/mods/gamemodes/cult/_cult.dme +++ b/mods/gamemodes/cult/_cult.dme @@ -21,7 +21,6 @@ #include "special_role.dm" #include "structures.dm" #include "talisman.dm" -#include "wizard.dm" #include "cultify\de-cultify.dm" #include "cultify\defile.dm" #include "cultify\mob.dm" diff --git a/mods/gamemodes/cult/items.dm b/mods/gamemodes/cult/items.dm index 1674cdb92eb8..2b2e826617c7 100644 --- a/mods/gamemodes/cult/items.dm +++ b/mods/gamemodes/cult/items.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/items/weapon/swords/cult.dmi' material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME -// separated into a proc so that subtypes can modify it +// separated into a proc so that modpacks can modify it /obj/item/sword/cultblade/proc/can_use_safely(mob/living/user) return iscultist(user) @@ -21,9 +21,9 @@ affecting = GET_EXTERNAL_ORGAN(H, zone) if(affecting) - to_chat(user, "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!") + to_chat(user, SPAN_DANGER("An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!")) else - to_chat(user, "An unexplicable force rips through you, tearing the sword from your grasp!") + to_chat(user, SPAN_DANGER("An unexplicable force rips through you, tearing the sword from your grasp!")) //random amount of damage between half of the blade's force and the full force of the blade. var/force = get_attack_force(user) diff --git a/mods/gamemodes/cult/overrides.dm b/mods/gamemodes/cult/overrides.dm index 874dc92049c7..2077c9f0b1e1 100644 --- a/mods/gamemodes/cult/overrides.dm +++ b/mods/gamemodes/cult/overrides.dm @@ -14,19 +14,6 @@ else playsound(src, 'sound/effects/ghost2.ogg', 10, 5) -/datum/trader/ship/unique/wizard/New() - possible_wanted_items |= list( - /mob/living/simple_animal/construct = TRADER_SUBTYPES_ONLY, - /obj/item/sword/cultblade = TRADER_THIS_TYPE, - /obj/item/clothing/head/culthood = TRADER_ALL, - /obj/item/clothing/suit/space/cult = TRADER_ALL, - /obj/item/clothing/suit/cultrobes = TRADER_ALL, - /obj/item/clothing/head/helmet/space/cult = TRADER_ALL, - /obj/structure/cult = TRADER_SUBTYPES_ONLY, - /obj/structure/constructshell = TRADER_ALL - ) - ..() - /datum/trader/ship/clothingshop/hatglovesaccessories/New() possible_trading_items[/obj/item/clothing/head/culthood] = TRADER_BLACKLIST_ALL diff --git a/mods/gamemodes/cult/wizard.dm b/mods/gamemodes/cult/wizard.dm deleted file mode 100644 index b29fa023f65c..000000000000 --- a/mods/gamemodes/cult/wizard.dm +++ /dev/null @@ -1,47 +0,0 @@ -// #ifdef GAMEMODE_PACK_WIZARD -// todo: add wizard gamemode define check once it's modularized -/decl/modpack/cult/post_initialize() - . = ..() - global.artefact_feedback[/obj/structure/closet/wizard/souls] = "SS" - -/datum/spellbook/standard/New() - spells[/obj/structure/closet/wizard/souls] = 1 - ..() - -/datum/spellbook/druid/New() - spells[/obj/structure/closet/wizard/souls] = 1 - ..() - -/obj/structure/closet/wizard/souls - name = "Soul Shard Belt" - desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot. This also includes the spell Artificer, used to create the shells used in construct creation." - -/obj/structure/closet/wizard/souls/WillContain() - return list( - /obj/item/contract/boon/wizard/artificer, - /obj/item/belt/soulstone/full, - ) - -/datum/storage/belt/soulstone - can_hold = list( - /obj/item/soulstone - ) - -/obj/item/belt/soulstone - name = "soul stone belt" - desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away." - icon = 'icons/clothing/belt/soulstones.dmi' - storage = /datum/storage/belt/soulstone - -/obj/item/belt/soulstone/full/WillContain() - return list(/obj/item/soulstone = max(1, storage?.storage_slots)) - -/obj/item/contract/boon/wizard/artificer - path = /spell/aoe_turf/conjure/construct - desc = "This contract has a passage dedicated to an entity known as 'Nar-Sie'." - -/obj/item/magic_rock - material = /decl/material/solid/stone/cult - -/obj/item/summoning_stone - material = /decl/material/solid/stone/cult \ No newline at end of file diff --git a/mods/species/bayliens/tajaran/machinery/suit_cycler.dm b/mods/species/bayliens/tajaran/machinery/suit_cycler.dm index b6c5366944c3..de0b3b76a702 100644 --- a/mods/species/bayliens/tajaran/machinery/suit_cycler.dm +++ b/mods/species/bayliens/tajaran/machinery/suit_cycler.dm @@ -47,8 +47,5 @@ /obj/item/clothing/suit/space/void _feline_onmob_icon = 'mods/species/bayliens/tajaran/icons/clothing/nasa/suit.dmi' -/obj/item/clothing/suit/space/void/wizard - _feline_onmob_icon = 'mods/species/bayliens/tajaran/icons/clothing/wizard/suit.dmi' - /obj/item/clothing/suit/space/void/excavation _feline_onmob_icon = 'mods/species/bayliens/tajaran/icons/clothing/excavation/suit.dmi' diff --git a/mods/species/vox/_vox.dme b/mods/species/vox/_vox.dme index 99bd0717bac5..83d61f50f51f 100644 --- a/mods/species/vox/_vox.dme +++ b/mods/species/vox/_vox.dme @@ -5,7 +5,6 @@ #include "mobs_vox.dm" #include "organs_vox.dm" #include "datum\accessories.dm" -#include "datum\antagonism.dm" #include "datum\cultures_vox.dm" #include "datum\descriptors_vox.dm" #include "datum\factions_vox.dm" diff --git a/mods/species/vox/datum/antagonism.dm b/mods/species/vox/datum/antagonism.dm deleted file mode 100644 index 4b8c182ee3a0..000000000000 --- a/mods/species/vox/datum/antagonism.dm +++ /dev/null @@ -1,4 +0,0 @@ -// Wizard -/obj/item/magic_rock/Initialize(ml, material_key) - LAZYSET(potentials, SPECIES_VOX, /spell/targeted/shapeshift/true_form) - . = ..() diff --git a/mods/species/vox/gear/gun.dm b/mods/species/vox/gear/gun.dm index c4f62db86c9c..a2e5706de5d8 100644 --- a/mods/species/vox/gear/gun.dm +++ b/mods/species/vox/gear/gun.dm @@ -78,27 +78,3 @@ /decl/material/liquid/sedatives, /decl/material/liquid/paralytics ) - -/spell/targeted/shapeshift/true_form - name = "True Form" - desc = "Pay respect to your heritage. Become what you once were." - - school = "racial" - spell_flags = INCLUDEUSER - invocation_type = SpI_EMOTE - range = -1 - invocation = "begins to grow!" - charge_max = 1200 //2 minutes - duration = 300 //30 seconds - - smoke_amt = 5 - smoke_spread = 1 - - possible_transformations = list(/mob/living/simple_animal/hostile/parrot/space/lesser) - - hud_state = "wiz_vox" - - cast_sound = 'sound/voice/shriek1.ogg' - revert_sound = 'sound/voice/shriek1.ogg' - - drop_items = 0 diff --git a/nebula.dme b/nebula.dme index d286bdf0899f..04deff7ede21 100644 --- a/nebula.dme +++ b/nebula.dme @@ -765,7 +765,6 @@ #include "code\game\antagonist\outsider\actors.dm" #include "code\game\antagonist\outsider\ert.dm" #include "code\game\antagonist\outsider\mercenary.dm" -#include "code\game\antagonist\outsider\wizard.dm" #include "code\game\antagonist\station\provocateur.dm" #include "code\game\antagonist\station\thrall.dm" #include "code\game\area\area_abstract.dm" @@ -801,14 +800,6 @@ #include "code\game\gamemodes\objectives\objective_protect.dm" #include "code\game\gamemodes\objectives\objective_rev.dm" #include "code\game\gamemodes\objectives\objective_steal.dm" -#include "code\game\gamemodes\wizard\wizard.dm" -#include "code\game\gamemodes\wizard\wizard_props.dm" -#include "code\game\gamemodes\wizard\servant_items\caretaker.dm" -#include "code\game\gamemodes\wizard\servant_items\champion.dm" -#include "code\game\gamemodes\wizard\servant_items\familiar.dm" -#include "code\game\gamemodes\wizard\servant_items\fiend.dm" -#include "code\game\gamemodes\wizard\servant_items\infiltrator.dm" -#include "code\game\gamemodes\wizard\servant_items\overseer.dm" #include "code\game\jobs\_access_defs.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\access_datum.dm" @@ -1260,7 +1251,6 @@ #include "code\game\objects\items\weapons\RCD.dm" #include "code\game\objects\items\weapons\RPD.dm" #include "code\game\objects\items\weapons\RSF.dm" -#include "code\game\objects\items\weapons\scrolls.dm" #include "code\game\objects\items\weapons\secrets_disk.dm" #include "code\game\objects\items\weapons\shields.dm" #include "code\game\objects\items\weapons\soap.dm" @@ -2007,6 +1997,7 @@ #include "code\modules\clothing\head\misc_special.dm" #include "code\modules\clothing\head\security.dm" #include "code\modules\clothing\head\soft_caps.dm" +#include "code\modules\clothing\head\wizard.dm" #include "code\modules\clothing\jumpsuits\_jumpsuit.dm" #include "code\modules\clothing\jumpsuits\color.dm" #include "code\modules\clothing\jumpsuits\job.dm" @@ -2097,7 +2088,6 @@ #include "code\modules\clothing\spacesuits\void\misc.dm" #include "code\modules\clothing\spacesuits\void\station.dm" #include "code\modules\clothing\spacesuits\void\void.dm" -#include "code\modules\clothing\spacesuits\void\wizard.dm" #include "code\modules\clothing\suits\_suit.dm" #include "code\modules\clothing\suits\_suit_hood.dm" #include "code\modules\clothing\suits\alien.dm" @@ -2108,6 +2098,7 @@ #include "code\modules\clothing\suits\jobs.dm" #include "code\modules\clothing\suits\labcoat.dm" #include "code\modules\clothing\suits\mantle.dm" +#include "code\modules\clothing\suits\misc.dm" #include "code\modules\clothing\suits\miscellaneous.dm" #include "code\modules\clothing\suits\poncho.dm" #include "code\modules\clothing\suits\robes.dm" @@ -2116,7 +2107,7 @@ #include "code\modules\clothing\suits\straightjacket.dm" #include "code\modules\clothing\suits\toggles.dm" #include "code\modules\clothing\suits\utility.dm" -#include "code\modules\clothing\suits\wiz_robe.dm" +#include "code\modules\clothing\suits\wizard.dm" #include "code\modules\clothing\suits\armor\_armor.dm" #include "code\modules\clothing\suits\armor\adminbus_and_memes.dm" #include "code\modules\clothing\suits\armor\bulletproof.dm" @@ -3008,7 +2999,6 @@ #include "code\modules\mob\living\simple_animal\aquatic\aquatic_fish.dm" #include "code\modules\mob\living\simple_animal\aquatic\aquatic_sharks.dm" #include "code\modules\mob\living\simple_animal\crow\crow.dm" -#include "code\modules\mob\living\simple_animal\familiars\familiars.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\crab.dm" @@ -3773,84 +3763,14 @@ #include "code\modules\species\station\human_bodytypes.dm" #include "code\modules\species\station\monkey.dm" #include "code\modules\species\station\monkey_bodytypes.dm" -#include "code\modules\spells\artifacts.dm" #include "code\modules\spells\construct_spells.dm" -#include "code\modules\spells\contracts.dm" -#include "code\modules\spells\no_clothes.dm" -#include "code\modules\spells\racial_wizard.dm" #include "code\modules\spells\spell_code.dm" -#include "code\modules\spells\spell_projectile.dm" -#include "code\modules\spells\spellbook.dm" #include "code\modules\spells\spells.dm" #include "code\modules\spells\aoe_turf\aoe_turf.dm" -#include "code\modules\spells\aoe_turf\blink.dm" -#include "code\modules\spells\aoe_turf\charge.dm" -#include "code\modules\spells\aoe_turf\disable_tech.dm" -#include "code\modules\spells\aoe_turf\drain_blood.dm" -#include "code\modules\spells\aoe_turf\exchange_wounds.dm" -#include "code\modules\spells\aoe_turf\knock.dm" -#include "code\modules\spells\aoe_turf\smoke.dm" -#include "code\modules\spells\aoe_turf\summons.dm" #include "code\modules\spells\aoe_turf\conjure\conjure.dm" -#include "code\modules\spells\aoe_turf\conjure\druidic_spells.dm" -#include "code\modules\spells\aoe_turf\conjure\faithful_hound.dm" -#include "code\modules\spells\aoe_turf\conjure\force_portal.dm" -#include "code\modules\spells\aoe_turf\conjure\forcewall.dm" -#include "code\modules\spells\aoe_turf\conjure\grove.dm" -#include "code\modules\spells\artifacts\spellbound_servants.dm" -#include "code\modules\spells\artifacts\storage.dm" -#include "code\modules\spells\general\acid_spray.dm" -#include "code\modules\spells\general\area_teleport.dm" -#include "code\modules\spells\general\camera_vision.dm" -#include "code\modules\spells\general\contract_spells.dm" -#include "code\modules\spells\general\create_air.dm" -#include "code\modules\spells\general\invisibility.dm" -#include "code\modules\spells\general\mark_recall.dm" -#include "code\modules\spells\general\portal_teleport.dm" -#include "code\modules\spells\general\radiant_aura.dm" -#include "code\modules\spells\general\return_master.dm" -#include "code\modules\spells\general\toggle_armor.dm" -#include "code\modules\spells\hand\blood_shards.dm" -#include "code\modules\spells\hand\burning_grip.dm" -#include "code\modules\spells\hand\entangle.dm" -#include "code\modules\spells\hand\hand.dm" -#include "code\modules\spells\hand\hand_item.dm" -#include "code\modules\spells\hand\slippery_surface.dm" -#include "code\modules\spells\hand\sunwrath.dm" -#include "code\modules\spells\spellbook\battlemage.dm" -#include "code\modules\spells\spellbook\cleric.dm" -#include "code\modules\spells\spellbook\druid.dm" -#include "code\modules\spells\spellbook\spatial.dm" -#include "code\modules\spells\spellbook\standard.dm" -#include "code\modules\spells\spellbook\student.dm" -#include "code\modules\spells\targeted\analyze.dm" -#include "code\modules\spells\targeted\blood_boil.dm" -#include "code\modules\spells\targeted\cleric_spells.dm" #include "code\modules\spells\targeted\ethereal_jaunt.dm" -#include "code\modules\spells\targeted\exude_pleasantness.dm" -#include "code\modules\spells\targeted\genetic.dm" -#include "code\modules\spells\targeted\glimpse_of_eternity.dm" -#include "code\modules\spells\targeted\shapeshift.dm" -#include "code\modules\spells\targeted\shatter_mind.dm" #include "code\modules\spells\targeted\shift.dm" -#include "code\modules\spells\targeted\subjugate.dm" -#include "code\modules\spells\targeted\swap.dm" #include "code\modules\spells\targeted\targeted.dm" -#include "code\modules\spells\targeted\torment.dm" -#include "code\modules\spells\targeted\equip\burning_touch.dm" -#include "code\modules\spells\targeted\equip\dyrnwyn.dm" -#include "code\modules\spells\targeted\equip\equip.dm" -#include "code\modules\spells\targeted\equip\holy_relic.dm" -#include "code\modules\spells\targeted\equip\horsemask.dm" -#include "code\modules\spells\targeted\equip\party_hardy.dm" -#include "code\modules\spells\targeted\equip\seed.dm" -#include "code\modules\spells\targeted\equip\shield.dm" -#include "code\modules\spells\targeted\projectile\dumbfire.dm" -#include "code\modules\spells\targeted\projectile\fireball.dm" -#include "code\modules\spells\targeted\projectile\magic_missile.dm" -#include "code\modules\spells\targeted\projectile\passage.dm" -#include "code\modules\spells\targeted\projectile\projectile.dm" -#include "code\modules\spells\targeted\projectile\stuncuff.dm" #include "code\modules\sprite_accessories\_accessory.dm" #include "code\modules\sprite_accessories\_accessory_category.dm" #include "code\modules\sprite_accessories\cosmetics\_accessory_cosmetics.dm" @@ -4126,7 +4046,6 @@ #include "maps\_map_include.dm" #include "maps\antag_spawn\ert\ert.dm" #include "maps\antag_spawn\mercenary\mercenary.dm" -#include "maps\antag_spawn\wizard\wizard.dm" #include "maps\away_sites_testing\away_sites_testing_define.dm" #include "maps\example\example_define.dm" #include "maps\exodus\exodus_define.dm" From 3a46a3b09fdf3338cb2814e2a0fa797683f4fcd9 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sat, 7 Dec 2024 22:04:10 -0500 Subject: [PATCH 23/90] Removes unnecessary pronouns --- code/_onclick/ghost.dm | 3 +++ code/_onclick/other_mobs.dm | 4 ++-- code/game/objects/items/__item.dm | 5 ----- code/modules/mob/living/human/examine.dm | 12 ++++++------ code/modules/mob/living/human/human.dm | 6 +++--- code/modules/mob/living/human/human_verbs.dm | 4 ++-- code/modules/mob/living/silicon/robot/drone/drone.dm | 4 ++-- code/modules/power/lighting.dm | 4 ++-- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/code/_onclick/ghost.dm b/code/_onclick/ghost.dm index da5d187674d6..7bee520bdb59 100644 --- a/code/_onclick/ghost.dm +++ b/code/_onclick/ghost.dm @@ -45,6 +45,9 @@ return if(user.client && user.client.inquisitive_ghost) user.examinate(src) + return + if(user.client?.holder || user.antagHUD) + storage?.show_to(user) return // --------------------------------------- diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 0e4a32796d59..77c594dd3750 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -66,9 +66,9 @@ var/obj/item/organ/external/hand/O = GET_EXTERNAL_ORGAN(src, get_active_held_item_slot()) if(!istype(O)) return FALSE - var/decl/pronouns/G = get_pronouns() + var/decl/pronouns/pronouns = get_pronouns() visible_message( - SPAN_DANGER("\The [src] chews on [G.his] [O.name]"), + SPAN_DANGER("\The [src] chews on [pronouns.his] [O.name]"), SPAN_DANGER("You chew on your [O.name]!") ) admin_attacker_log(src, "chewed on their [O.name]!") diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm index 69b1449b4193..85b58c597ffd 100644 --- a/code/game/objects/items/__item.dm +++ b/code/game/objects/items/__item.dm @@ -581,11 +581,6 @@ return ..() -/obj/item/attack_ghost(mob/user) - var/mob/observer/ghost/pronouns = user - if(pronouns.client?.holder || pronouns.antagHUD) - storage?.show_to(user) - /obj/item/proc/talk_into(mob/living/M, message, message_mode, var/verb = "says", var/decl/language/speaking = null) return diff --git a/code/modules/mob/living/human/examine.dm b/code/modules/mob/living/human/examine.dm index db61156edfce..389e209440cf 100644 --- a/code/modules/mob/living/human/examine.dm +++ b/code/modules/mob/living/human/examine.dm @@ -268,13 +268,13 @@ return /mob/living/human/getHUDsource(hudtype) - var/obj/item/clothing/glasses/pronouns = get_equipped_item(slot_glasses_str) - if(!istype(pronouns)) + var/obj/item/clothing/glasses/glasses = get_equipped_item(slot_glasses_str) + if(!istype(glasses)) return ..() - if(pronouns.glasses_hud_type & hudtype) - return pronouns - if(pronouns.hud && (pronouns.hud.glasses_hud_type & hudtype)) - return pronouns.hud + if(glasses.glasses_hud_type & hudtype) + return glasses + if(glasses.hud && (glasses.hud.glasses_hud_type & hudtype)) + return glasses.hud /mob/living/silicon/robot/getHUDsource(hudtype) for(var/obj/item/borg/sight/sight in list(module_state_1, module_state_2, module_state_3)) diff --git a/code/modules/mob/living/human/human.dm b/code/modules/mob/living/human/human.dm index 024189fd6740..7902a3391e6c 100644 --- a/code/modules/mob/living/human/human.dm +++ b/code/modules/mob/living/human/human.dm @@ -84,9 +84,9 @@ . = ..() if(statpanel("Status")) - var/obj/item/gps/pronouns = get_active_held_item() - if(istype(pronouns)) - stat("Coordinates:", "[pronouns.get_coordinates()]") + var/obj/item/gps/gps = get_active_held_item() + if(istype(gps)) + stat("Coordinates:", "[gps.get_coordinates()]") stat("Intent:", "[a_intent]") stat("Move Mode:", "[move_intent.name]") diff --git a/code/modules/mob/living/human/human_verbs.dm b/code/modules/mob/living/human/human_verbs.dm index 90c8db6b47ab..c8f5f9083922 100644 --- a/code/modules/mob/living/human/human_verbs.dm +++ b/code/modules/mob/living/human/human_verbs.dm @@ -97,8 +97,8 @@ target.show_message("You hear a voice that seems to echo around the room: [say]") usr.show_message("You project your mind into [target.real_name]: [say]") log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]") - for(var/mob/observer/ghost/pronouns in global.player_list) - pronouns.show_message("Telepathic message from [src] to [target]: [say]") + for(var/mob/observer/ghost/ghost in global.player_list) + ghost.show_message("Telepathic message from [src] to [target]: [say]") /mob/living/human/proc/remoteobserve() set name = "Remote View" diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index e8c86f234f85..f9ace0a24f39 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -286,8 +286,8 @@ /mob/living/silicon/robot/drone/proc/request_player() if(too_many_active_drones()) return - var/decl/ghosttrap/pronouns = GET_DECL(/decl/ghosttrap/maintenance_drone) - pronouns.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) + var/decl/ghosttrap/ghosttrap = GET_DECL(/decl/ghosttrap/maintenance_drone) + ghosttrap.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) /mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player) if(!player) return diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 76ea4bb5e1ee..5e1fccf19343 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -329,8 +329,8 @@ var/prot = FALSE var/mob/living/human/H = user if(istype(H)) - var/obj/item/clothing/gloves/pronouns = H.get_equipped_item(slot_gloves_str) - if(istype(pronouns) && pronouns.max_heat_protection_temperature > LIGHT_BULB_TEMPERATURE) + var/obj/item/clothing/gloves/gloves = H.get_equipped_item(slot_gloves_str) + if(istype(gloves) && gloves.max_heat_protection_temperature > LIGHT_BULB_TEMPERATURE) prot = TRUE if(prot > 0 || user.has_genetic_condition(GENE_COND_COLD_RESISTANCE)) From e34ae1bab19275c65936251ca2659e30ba934c44 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 2 Nov 2024 15:05:53 +1100 Subject: [PATCH 24/90] Adding SSpathfinding to handle AStar pathfinding requests. --- .gitignore | 1 + code/__defines/ai.dm | 2 + code/__defines/subsystem-priority.dm | 1 + .../subsystems/mob_ai/auto_movement.dm | 5 +- code/controllers/subsystems/pathfinding.dm | 123 ++++++++++++++ code/datums/ai/_ai.dm | 154 +++--------------- code/datums/ai/_ai_enemies.dm | 35 ++++ code/datums/ai/_ai_friends.dm | 25 +++ code/datums/ai/_ai_memory.dm | 7 + code/datums/ai/_ai_pathfinding.dm | 29 ++++ code/datums/ai/_ai_stance.dm | 39 +++-- code/datums/ai/_ai_targets.dm | 77 +++++++++ code/datums/ai/_ai_wander.dm | 5 + code/datums/ai/aggressive.dm | 104 +++++------- code/datums/ai/beast.dm | 4 +- code/datums/ai/commanded.dm | 10 +- code/datums/movement/automove_controller.dm | 21 ++- code/game/atoms_movable.dm | 3 + code/game/turfs/turf_navigation.dm | 62 +++++++ .../integrated_electronics/subtypes/smart.dm | 46 ++++-- code/modules/mob/living/bot/bot.dm | 101 ++---------- code/modules/mob/living/bot/cleanbot.dm | 9 +- code/modules/mob/living/bot/farmbot.dm | 18 -- code/modules/mob/living/bot/mulebot.dm | 2 +- code/modules/mob/living/living.dm | 5 - .../mob/living/simple_animal/hostile/bear.dm | 4 +- .../hostile/commanded/nanomachines.dm | 4 +- .../hostile/giant_spiders/ai_guard.dm | 2 +- .../simple_animal/hostile/hivebots/megabot.dm | 2 +- .../mob/living/simple_animal/hostile/mimic.dm | 2 +- .../simple_animal/hostile/retaliate/drone.dm | 11 +- .../mob/living/simple_animal/hostile/slug.dm | 13 +- code/modules/mob/mob.dm | 5 + code/modules/mob/mob_automove.dm | 44 ++++- code/procs/{AStar.dm => pathfinding.dm} | 26 ++- nebula.dme | 10 +- 36 files changed, 631 insertions(+), 380 deletions(-) create mode 100644 code/controllers/subsystems/pathfinding.dm create mode 100644 code/datums/ai/_ai_enemies.dm create mode 100644 code/datums/ai/_ai_friends.dm create mode 100644 code/datums/ai/_ai_memory.dm create mode 100644 code/datums/ai/_ai_pathfinding.dm create mode 100644 code/datums/ai/_ai_targets.dm create mode 100644 code/datums/ai/_ai_wander.dm create mode 100644 code/game/turfs/turf_navigation.dm rename code/procs/{AStar.dm => pathfinding.dm} (78%) diff --git a/.gitignore b/.gitignore index 9d2b3ae5aa14..52ee73c38355 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # ignore misc BYOND files Thumbs.db +Thumbs.db:encryptable *.log *.int *.rsc diff --git a/code/__defines/ai.dm b/code/__defines/ai.dm index 2123e2e8839b..03fa03fa9e88 100644 --- a/code/__defines/ai.dm +++ b/code/__defines/ai.dm @@ -6,6 +6,8 @@ #define STANCE_ATTACKING /decl/mob_controller_stance/attacking #define STANCE_TIRED /decl/mob_controller_stance/tired #define STANCE_CONTAINED /decl/mob_controller_stance/contained +#define STANCE_BUSY /decl/mob_controller_stance/busy + //basically 'do nothing' #define STANCE_COMMANDED_STOP /decl/mob_controller_stance/commanded/stop //follows a target diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm index fc69009e88b8..cd44840622aa 100644 --- a/code/__defines/subsystem-priority.dm +++ b/code/__defines/subsystem-priority.dm @@ -39,6 +39,7 @@ #define SS_PRIORITY_GHOST_IMAGES 10 // Updates ghost client images. #define SS_PRIORITY_ZCOPY 10 // Builds appearances for Z-Mimic. #define SS_PRIORITY_PROJECTILES 10 // Projectile processing! +#define SS_PRIORITY_PATHFINDING 10 // Processing pathfinding requests // SS_BACKGROUND #define SS_PRIORITY_OBJECTS 100 // processing_objects processing. diff --git a/code/controllers/subsystems/mob_ai/auto_movement.dm b/code/controllers/subsystems/mob_ai/auto_movement.dm index 7e2990c1cb8d..843f37ab2d05 100644 --- a/code/controllers/subsystems/mob_ai/auto_movement.dm +++ b/code/controllers/subsystems/mob_ai/auto_movement.dm @@ -51,5 +51,8 @@ SUBSYSTEM_DEF(automove) if(controller.handle_mover(mover, moving_metadata[mover]) == PROCESS_KILL && !QDELETED(mover)) mover.stop_automove() if(MC_TICK_CHECK) - processing_atoms.Cut(1, i+1) + if(i >= length(processing_atoms)) + processing_atoms.Cut() + else + processing_atoms.Cut(1, i+1) return diff --git a/code/controllers/subsystems/pathfinding.dm b/code/controllers/subsystems/pathfinding.dm new file mode 100644 index 000000000000..d6e63f4191f1 --- /dev/null +++ b/code/controllers/subsystems/pathfinding.dm @@ -0,0 +1,123 @@ +SUBSYSTEM_DEF(pathfinding) + name = "Pathfinding" + priority = SS_PRIORITY_PATHFINDING + init_order = SS_INIT_MISC_LATE + wait = 1 + + var/list/pending = list() + var/list/processing = list() + var/list/mover_metadata = list() + + VAR_PRIVATE/static/_default_adjacency_call = TYPE_PROC_REF(/turf, CardinalTurfsWithAccess) + VAR_PRIVATE/static/_default_distance_call = TYPE_PROC_REF(/turf, Distance) + +/atom/movable + var/waiting_for_path + +/atom/movable/proc/path_found(list/path) + SHOULD_CALL_PARENT(TRUE) + waiting_for_path = null + +/atom/movable/proc/path_not_found() + SHOULD_CALL_PARENT(TRUE) + waiting_for_path = null + +/datum/controller/subsystem/pathfinding/proc/dequeue_mover(atom/movable/mover, include_processing = TRUE) + if(!istype(mover)) + return + mover.waiting_for_path = null + pending -= mover + mover_metadata -= mover + if(include_processing) + processing -= mover + +// Hook to allow legacy use of AStar* to reuse the callback refs +/datum/controller/subsystem/pathfinding/proc/find_path_immediate(start, end, max_nodes, max_node_depth = 30, min_target_dist = 0, min_node_dist, id, datum/exclude, check_tick = FALSE) + return find_path_astar(start, end, _default_adjacency_call, _default_distance_call, max_nodes, max_node_depth, min_target_dist, min_node_dist, id, exclude, check_tick) + +/datum/controller/subsystem/pathfinding/proc/enqueue_mover(atom/movable/mover, atom/target, datum/pathfinding_metadata/metadata) + if(!istype(mover) || mover.waiting_for_path) + return FALSE + if(!istype(target)) + return FALSE + pending |= mover + pending[mover] = target + if(istype(metadata)) + mover_metadata[mover] = metadata + mover.waiting_for_path = world.time + return TRUE + +/datum/controller/subsystem/pathfinding/stat_entry(msg) + . = ..("Q:[length(pending)] P:[length(processing)]") + +/datum/controller/subsystem/pathfinding/fire(resumed) + + if(!resumed) + processing = pending?.Copy() + + var/atom/movable/mover + var/atom/target + var/datum/pathfinding_metadata/metadata + var/i = 0 + + while(i < processing.len) + + i++ + mover = processing[i] + target = processing[mover] + metadata = mover_metadata[mover] + dequeue_mover(mover, include_processing = FALSE) + + if(!QDELETED(mover) && !QDELETED(target)) + try_find_path(mover, target, metadata) + + if (MC_TICK_CHECK) + processing.Cut(1, i+1) + return + + processing.Cut() + +/datum/controller/subsystem/pathfinding/proc/try_find_path(atom/movable/mover, atom/target, datum/pathfinding_metadata/metadata, adjacency_call = _default_adjacency_call, distance_call = _default_distance_call) + + var/started_pathing = world.time + mover.waiting_for_path = started_pathing + + var/list/path = find_path_astar( + get_turf(mover), + target, + adjacency_call, + distance_call, + (metadata?.max_nodes || null), + (metadata?.max_node_depth || 250), + metadata?.min_target_dist, + metadata?.min_node_depth, + (metadata?.id || mover.GetIdCard()), + metadata?.obstacle, + check_tick = TRUE + ) + if(mover.waiting_for_path == started_pathing) + if(length(path)) + mover.path_found(path) + else + mover.path_not_found() + +/datum/pathfinding_metadata + var/max_nodes = null + var/max_node_depth = 250 + var/atom/id = null + var/min_target_dist = null + var/min_node_depth = null + var/obstacle = null + +/datum/pathfinding_metadata/New(_max_nodes, _max_node_depth, _id, _min_target_dist, _min_node_depth, _obstacle) + + id = _id + obstacle = _obstacle + max_nodes = _max_nodes + + if(!isnull(_max_node_depth)) + max_node_depth = _max_node_depth + if(!isnull(_min_target_dist)) + min_target_dist = _min_target_dist + if(!isnull(_min_node_depth)) + min_node_depth = _min_node_depth diff --git a/code/datums/ai/_ai.dm b/code/datums/ai/_ai.dm index 6e40fd7ab35c..9c943dadb4fb 100644 --- a/code/datums/ai/_ai.dm +++ b/code/datums/ai/_ai.dm @@ -62,6 +62,23 @@ /// Aggressive AI var; defined here for reference without casting. var/try_destroy_surroundings = FALSE + /// Reference to the atom we are targetting. + var/weakref/target_ref + + /// Current path for A* pathfinding. + var/list/executing_path + /// A counter for times we have failed to progress along our path. + var/path_frustration = 0 + /// A list of any obstacles we should path around in future. + var/list/path_obstacles = null + + /// Radius of target scan area when looking for valid targets. Set to 0 to disable target scanning. + var/target_scan_distance = 0 + /// Time tracker for next target scan. + var/next_target_scan_time + /// How long minimum between scans. + var/target_scan_delay = 1 SECOND + /datum/mob_controller/New(var/mob/living/target_body) body = target_body if(expected_type && !istype(body, expected_type)) @@ -71,6 +88,7 @@ /datum/mob_controller/Destroy() LAZYCLEARLIST(_friends) LAZYCLEARLIST(_enemies) + set_target(null) if(is_processing) STOP_PROCESSING(SSmob_ai, src) if(body) @@ -79,12 +97,6 @@ body = null . = ..() -/datum/mob_controller/proc/get_automove_target(datum/automove_metadata/metadata) - return null - -/datum/mob_controller/proc/can_do_automated_move(variant_move_delay) - return body && !body.client - /datum/mob_controller/proc/can_process() if(!body || !body.loc || ((body.client || body.mind) && !(body.status_flags & ENABLE_AI))) return FALSE @@ -111,13 +123,13 @@ // This is the place to actually do work in the AI. /datum/mob_controller/proc/do_process() SHOULD_CALL_PARENT(TRUE) - if(!QDELETED(body) && !QDELETED(src)) + if(get_stance() != STANCE_BUSY && !QDELETED(body) && !QDELETED(src)) if(!body.stat) try_unbuckle() try_wander() try_bark() // Recheck in case we walked into lava or something during wandering. - return !QDELETED(body) && !QDELETED(src) + return get_stance() != STANCE_BUSY && !QDELETED(body) && !QDELETED(src) return TRUE return FALSE @@ -132,16 +144,6 @@ else if(prob(25)) body.visible_message(SPAN_WARNING("\The [body] struggles against \the [body.buckled]!")) - -/datum/mob_controller/proc/get_activity() - return current_activity - -/datum/mob_controller/proc/set_activity(new_activity) - if(current_activity != new_activity) - current_activity = new_activity - return TRUE - return FALSE - // The mob will periodically sit up or step 1 tile in a random direction. /datum/mob_controller/proc/try_wander() //Movement @@ -185,133 +187,17 @@ else if(ispath(do_emote, /decl/emote)) body.emote(do_emote) -/datum/mob_controller/proc/get_target() - return null - -/datum/mob_controller/proc/set_target(atom/new_target) - return - -/datum/mob_controller/proc/find_target() - return - -/datum/mob_controller/proc/valid_target(var/atom/A) - return - -/datum/mob_controller/proc/move_to_target(var/move_only = FALSE) - return - -/datum/mob_controller/proc/stop_wandering() - stop_wander = TRUE - -/datum/mob_controller/proc/resume_wandering() - stop_wander = FALSE - -/datum/mob_controller/proc/set_stance(new_stance) - if(stance != new_stance) - stance = new_stance - return TRUE - return FALSE - -/datum/mob_controller/proc/get_stance() - return stance - -/datum/mob_controller/proc/list_targets(var/dist = 7) - return - -/datum/mob_controller/proc/open_fire() - return - -/datum/mob_controller/proc/startle() - if(QDELETED(body) || body.stat != UNCONSCIOUS) - return - body.set_stat(CONSCIOUS) - if(body.current_posture?.prone) - body.set_posture(/decl/posture/standing) - -/datum/mob_controller/proc/retaliate(atom/source) - SHOULD_CALL_PARENT(TRUE) - if(!istype(body) || body.stat == DEAD) - return FALSE - startle() - if(isliving(source)) - remove_friend(source) - return TRUE - /datum/mob_controller/proc/destroy_surroundings() return -/datum/mob_controller/proc/lose_target() - return - -/datum/mob_controller/proc/lost_target() - return - /datum/mob_controller/proc/handle_death(gibbed) return -/datum/mob_controller/proc/pacify(mob/user) - lose_target() - add_friend(user) - -// General-purpose memorise proc, used by /commanded -/datum/mob_controller/proc/memorise(mob/speaker, message) - return - -// General-purpose memory checking proc, used by /faithful_hound -/datum/mob_controller/proc/check_memory(mob/speaker, message) - return FALSE - /// General-purpose scooping reaction proc, used by /passive. /// Returns TRUE if the scoop should proceed, FALSE if it should be canceled. /datum/mob_controller/proc/scooped_by(mob/initiator) return TRUE -// Enemy tracking - used on /aggressive -/datum/mob_controller/proc/get_enemies() - return _enemies - -/datum/mob_controller/proc/add_enemy(mob/enemy) - if(istype(enemy)) - LAZYDISTINCTADD(_enemies, weakref(enemy)) - -/datum/mob_controller/proc/add_enemies(list/enemies) - for(var/thing in enemies) - if(ismob(thing)) - add_friend(thing) - else if(istype(thing, /weakref)) - LAZYDISTINCTADD(_enemies, thing) - -/datum/mob_controller/proc/remove_enemy(mob/enemy) - LAZYREMOVE(_enemies, weakref(enemy)) - -/datum/mob_controller/proc/set_enemies(list/new_enemies) - _enemies = new_enemies - -/datum/mob_controller/proc/is_enemy(mob/enemy) - . = istype(enemy) && LAZYLEN(_enemies) && (weakref(enemy) in _enemies) - -/datum/mob_controller/proc/clear_enemies() - LAZYCLEARLIST(_enemies) - -// Friend tracking - used on /aggressive. -/datum/mob_controller/proc/get_friends() - return _friends - -/datum/mob_controller/proc/add_friend(mob/friend) - if(istype(friend)) - LAZYDISTINCTADD(_friends, weakref(friend)) - return TRUE - return FALSE - -/datum/mob_controller/proc/remove_friend(mob/friend) - LAZYREMOVE(_friends, weakref(friend)) - -/datum/mob_controller/proc/set_friends(list/new_friends) - _friends = new_friends - -/datum/mob_controller/proc/is_friend(mob/friend) - . = istype(friend) && LAZYLEN(_friends) && (weakref(friend) in _friends) - // By default, randomize the target area a bit to make armor/combat // a bit more dynamic (and avoid constant organ damage to the chest) /datum/mob_controller/proc/update_target_zone() diff --git a/code/datums/ai/_ai_enemies.dm b/code/datums/ai/_ai_enemies.dm new file mode 100644 index 000000000000..cbb7ddf46443 --- /dev/null +++ b/code/datums/ai/_ai_enemies.dm @@ -0,0 +1,35 @@ +// Enemy tracking - used on /aggressive +/datum/mob_controller/proc/get_enemies() + return _enemies + +/datum/mob_controller/proc/add_enemy(mob/enemy) + if(istype(enemy)) + LAZYDISTINCTADD(_enemies, weakref(enemy)) + +/datum/mob_controller/proc/add_enemies(list/enemies) + for(var/thing in enemies) + if(ismob(thing)) + add_friend(thing) + else if(istype(thing, /weakref)) + LAZYDISTINCTADD(_enemies, thing) + +/datum/mob_controller/proc/remove_enemy(mob/enemy) + LAZYREMOVE(_enemies, weakref(enemy)) + +/datum/mob_controller/proc/set_enemies(list/new_enemies) + _enemies = new_enemies + +/datum/mob_controller/proc/is_enemy(mob/enemy) + . = istype(enemy) && LAZYLEN(_enemies) && (weakref(enemy) in _enemies) + +/datum/mob_controller/proc/clear_enemies() + LAZYCLEARLIST(_enemies) + +/datum/mob_controller/proc/retaliate(atom/source) + SHOULD_CALL_PARENT(TRUE) + if(!istype(body) || body.stat == DEAD) + return FALSE + startle() + if(isliving(source)) + remove_friend(source) + return TRUE diff --git a/code/datums/ai/_ai_friends.dm b/code/datums/ai/_ai_friends.dm new file mode 100644 index 000000000000..3cab9046fced --- /dev/null +++ b/code/datums/ai/_ai_friends.dm @@ -0,0 +1,25 @@ +/datum/mob_controller/proc/pacify(mob/user) + lose_target() + add_friend(user) + +// Friend tracking - used on /aggressive. +/datum/mob_controller/proc/get_friends() + return _friends + +/datum/mob_controller/proc/add_friend(mob/friend) + if(istype(friend)) + LAZYDISTINCTADD(_friends, weakref(friend)) + return TRUE + return FALSE + +/datum/mob_controller/proc/remove_friend(mob/friend) + LAZYREMOVE(_friends, weakref(friend)) + +/datum/mob_controller/proc/set_friends(list/new_friends) + _friends = new_friends + +/datum/mob_controller/proc/is_friend(mob/friend) + . = istype(friend) && LAZYLEN(_friends) && (weakref(friend) in _friends) + +/datum/mob_controller/proc/clear_friends() + LAZYCLEARLIST(_friends) diff --git a/code/datums/ai/_ai_memory.dm b/code/datums/ai/_ai_memory.dm new file mode 100644 index 000000000000..f837a58cb8cd --- /dev/null +++ b/code/datums/ai/_ai_memory.dm @@ -0,0 +1,7 @@ +// General-purpose memorise proc, used by /commanded +/datum/mob_controller/proc/memorise(mob/speaker, message) + return + +// General-purpose memory checking proc, used by /faithful_hound +/datum/mob_controller/proc/check_memory(mob/speaker, message) + return FALSE diff --git a/code/datums/ai/_ai_pathfinding.dm b/code/datums/ai/_ai_pathfinding.dm new file mode 100644 index 000000000000..e01abaa05cec --- /dev/null +++ b/code/datums/ai/_ai_pathfinding.dm @@ -0,0 +1,29 @@ +/datum/mob_controller/proc/can_do_automated_move(variant_move_delay) + return body && !body.client + +/datum/mob_controller/proc/clear_paths() + clear_path() + +/datum/mob_controller/proc/clear_path() + executing_path = null + body?.stop_automove() + +/datum/mob_controller/proc/get_automove_target(datum/automove_metadata/metadata) + var/turf/move_target = (islist(executing_path) && length(executing_path)) ? executing_path[1] : null + if(!istype(move_target) || QDELETED(move_target)) + clear_path() + return null + return move_target + +/datum/mob_controller/proc/handle_post_automoved(atom/old_loc) + if(!islist(executing_path) || length(executing_path) <= 0) + return + var/turf/body_turf = get_turf(body) + if(!istype(body_turf)) + return + if(executing_path[1] != body_turf) + return + if(length(executing_path) > 1) + executing_path.Cut(1, 2) + else + clear_path() diff --git a/code/datums/ai/_ai_stance.dm b/code/datums/ai/_ai_stance.dm index ca018169811a..be3b11f94a72 100644 --- a/code/datums/ai/_ai_stance.dm +++ b/code/datums/ai/_ai_stance.dm @@ -1,30 +1,43 @@ // Stub type for future expansion/logic encapsulation. /decl/mob_controller_stance abstract_type = /decl/mob_controller_stance - /decl/mob_controller_stance/none - /decl/mob_controller_stance/idle - /decl/mob_controller_stance/alert - /decl/mob_controller_stance/attack - /decl/mob_controller_stance/attacking - /decl/mob_controller_stance/tired - /decl/mob_controller_stance/contained - /decl/mob_controller_stance/commanded abstract_type = /decl/mob_controller_stance/commanded - /decl/mob_controller_stance/commanded/stop - /decl/mob_controller_stance/commanded/follow - /decl/mob_controller_stance/commanded/misc - /decl/mob_controller_stance/commanded/heal - /decl/mob_controller_stance/commanded/healing +/decl/mob_controller_stance/busy + +/datum/mob_controller/proc/get_activity() + return current_activity + +/datum/mob_controller/proc/set_activity(new_activity) + if(current_activity != new_activity) + current_activity = new_activity + return TRUE + return FALSE + +/datum/mob_controller/proc/set_stance(new_stance) + if(stance != new_stance) + stance = new_stance + return TRUE + return FALSE + +/datum/mob_controller/proc/get_stance() + return stance + +/datum/mob_controller/proc/startle() + if(QDELETED(body) || body.stat != UNCONSCIOUS) + return + body.set_stat(CONSCIOUS) + if(body.current_posture?.prone) + body.set_posture(/decl/posture/standing) diff --git a/code/datums/ai/_ai_targets.dm b/code/datums/ai/_ai_targets.dm new file mode 100644 index 000000000000..49c5acedb094 --- /dev/null +++ b/code/datums/ai/_ai_targets.dm @@ -0,0 +1,77 @@ +/datum/mob_controller/proc/get_target() + if(isnull(target_ref)) + return null + var/atom/target = target_ref?.resolve() + if(!istype(target) || QDELETED(target)) + set_target(null) + return null + return target + +/datum/mob_controller/proc/set_target(atom/new_target) + var/weakref/new_target_ref = weakref(new_target) + if(target_ref != new_target_ref) + target_ref = new_target_ref + return TRUE + return FALSE + +/datum/mob_controller/proc/find_target() + SHOULD_CALL_PARENT(TRUE) + next_target_scan_time = world.time + target_scan_delay + +/datum/mob_controller/proc/valid_target(var/atom/A) + if(!istype(A)) + return FALSE + if(!A.simulated) + return FALSE + if(A == body) + return FALSE + if(A.invisibility > body.see_invisible) + return FALSE + if(LAZYLEN(_friends) && ismob(A) && (weakref(A) in _friends)) + return FALSE + if(!A.loc) + return FALSE + return TRUE + +/datum/mob_controller/proc/lose_target() + path_frustration = 0 + path_obstacles = null + set_target(null) + lost_target() + +/datum/mob_controller/proc/lost_target() + set_stance(STANCE_IDLE) + body.stop_automove() + +/datum/mob_controller/proc/list_targets() + // By default, we only target designated enemies. + var/list/enemies = get_enemies() + if(!LAZYLEN(enemies)) + return + var/list/possible_targets = get_raw_target_list() + if(!length(possible_targets)) + return + for(var/weakref/enemy in enemies) // Remove all entries that aren't in enemies + var/M = enemy.resolve() + if(M in possible_targets) + LAZYDISTINCTADD(., M) + +/datum/mob_controller/proc/do_target_scan() + . = target_scan_distance > 0 && world.time >= next_target_scan_time + +/datum/mob_controller/proc/move_to_target(var/move_only = FALSE) + return + +/datum/mob_controller/proc/get_raw_target_list() + if(target_scan_distance) + return hearers(body, target_scan_distance)-body + return null + +/datum/mob_controller/proc/get_valid_targets() + . = list() + for(var/target in list_targets(target_scan_distance)) + if(valid_target(target)) + . += target + +/datum/mob_controller/proc/handle_ranged_target(atom/ranged_target) + return FALSE diff --git a/code/datums/ai/_ai_wander.dm b/code/datums/ai/_ai_wander.dm new file mode 100644 index 000000000000..705d3fdcef1e --- /dev/null +++ b/code/datums/ai/_ai_wander.dm @@ -0,0 +1,5 @@ +/datum/mob_controller/proc/stop_wandering() + stop_wander = TRUE + +/datum/mob_controller/proc/resume_wandering() + stop_wander = FALSE diff --git a/code/datums/ai/aggressive.dm b/code/datums/ai/aggressive.dm index 62316d4d1977..e50d4e124ae0 100644 --- a/code/datums/ai/aggressive.dm +++ b/code/datums/ai/aggressive.dm @@ -2,36 +2,17 @@ stance = STANCE_IDLE stop_wander_when_pulled = FALSE try_destroy_surroundings = TRUE + target_scan_distance = 10 + var/attack_same_faction = FALSE var/only_attack_enemies = FALSE var/break_stuff_probability = 10 - var/weakref/target_ref /datum/mob_controller/aggressive/New() ..() if(isliving(body) && !QDELETED(body) && !QDELETED(src)) body.set_intent(I_FLAG_HARM) -/datum/mob_controller/aggressive/set_target(atom/new_target) - var/weakref/new_target_ref = weakref(new_target) - if(target_ref != new_target_ref) - target_ref = new_target_ref - return TRUE - return FALSE - -/datum/mob_controller/aggressive/get_target() - if(isnull(target_ref)) - return null - var/atom/target = target_ref?.resolve() - if(!istype(target) || QDELETED(target)) - set_target(null) - return null - return target - -/datum/mob_controller/aggressive/Destroy() - set_target(null) - return ..() - /datum/mob_controller/aggressive/do_process() if(!(. = ..())) @@ -42,24 +23,36 @@ set_stance(get_target() ? STANCE_ATTACK : STANCE_IDLE) return + if(isnull(stance)) + set_stance(get_target() ? STANCE_ATTACK : STANCE_IDLE) + if(isturf(body.loc) && !body.buckled) switch(stance) if(STANCE_IDLE) - set_target(find_target()) - set_stance(STANCE_ATTACK) + if(do_target_scan()) + set_target(find_target()) + if(get_target()) + set_stance(STANCE_ATTACK) if(STANCE_ATTACK) - body.face_atom(get_target()) - if(try_destroy_surroundings) - destroy_surroundings() - move_to_target() + + if(get_target()) + body.face_atom(get_target()) + if(try_destroy_surroundings) + destroy_surroundings() + move_to_target() + else + set_stance(STANCE_IDLE) if(STANCE_ATTACKING) - body.face_atom(get_target()) - if(try_destroy_surroundings) - destroy_surroundings() - handle_attacking_target() + if(get_target()) + body.face_atom(get_target()) + if(try_destroy_surroundings) + destroy_surroundings() + handle_attacking_target() + else + set_stance(STANCE_IDLE) if(STANCE_CONTAINED) //we aren't inside something so just switch set_stance(STANCE_IDLE) @@ -79,7 +72,7 @@ /datum/mob_controller/aggressive/proc/handle_attacking_target() stop_wandering() var/atom/target = get_target() - if(!istype(target) || !attackable(target) || !(target in list_targets(10))) // consider replacing this list_targets() call with a distance or LOS check + if(!istype(target) || !attackable(target) || !(target in get_raw_target_list())) lose_target() return FALSE if (ishuman(target)) @@ -209,51 +202,40 @@ return stop_wandering() var/atom/target = get_target() - if(!istype(target) || !attackable(target) || !(target in list_targets(10))) + if(!istype(target) || !attackable(target) || !(target in get_raw_target_list())) lose_target() return if(body.has_ranged_attack() && get_dist(body, target) <= body.get_ranged_attack_distance() && !move_only) body.stop_automove() - open_fire() + handle_ranged_target(target) return set_stance(STANCE_ATTACKING) body.start_automove(target) -/datum/mob_controller/aggressive/list_targets(var/dist = 7) +/datum/mob_controller/aggressive/list_targets() // Base hostile mobs will just destroy everything in view. // Mobs with an enemy list will filter the view by their enemies. if(!only_attack_enemies) - return hearers(body, dist)-body - var/list/enemies = get_enemies() - if(!LAZYLEN(enemies)) - return - var/list/possible_targets = hearers(body, dist)-body - if(!length(possible_targets)) - return - for(var/weakref/enemy in enemies) // Remove all entries that aren't in enemies - var/M = enemy.resolve() - if(M in possible_targets) - LAZYDISTINCTADD(., M) + return get_raw_target_list() + return ..() /datum/mob_controller/aggressive/find_target() + . = ..() if(!body.can_act() || !body.faction) return null resume_wandering() - for(var/atom/A in list_targets(10)) - if(valid_target(A)) - set_stance(STANCE_ATTACK) - body.face_atom(A) - return A + for(var/atom/A in get_valid_targets()) + set_stance(STANCE_ATTACK) + body.face_atom(A) + return A /datum/mob_controller/aggressive/valid_target(var/atom/A) - if(A == body) + if(!..()) return FALSE if(ismob(A)) var/mob/M = A if(M.faction == body.faction && !attack_same_faction) return FALSE - else if(weakref(M) in get_friends()) - return FALSE if(M.stat) return FALSE if(ishuman(M)) @@ -262,20 +244,12 @@ return FALSE return TRUE -/datum/mob_controller/aggressive/open_fire() - if(!body.can_act()) +/datum/mob_controller/aggressive/handle_ranged_target(atom/ranged_target) + if(!body.can_act() || !ranged_target) return FALSE - body.handle_ranged_attack(get_target()) + body.handle_ranged_attack(ranged_target) return TRUE -/datum/mob_controller/aggressive/lose_target() - set_target(null) - lost_target() - -/datum/mob_controller/aggressive/lost_target() - set_stance(STANCE_IDLE) - body.stop_automove() - /datum/mob_controller/aggressive/pacify(mob/user) ..() attack_same_faction = FALSE diff --git a/code/datums/ai/beast.dm b/code/datums/ai/beast.dm index 91ad1fec7a5a..9090698f55aa 100644 --- a/code/datums/ai/beast.dm +++ b/code/datums/ai/beast.dm @@ -36,7 +36,7 @@ qdel(S) break -/datum/mob_controller/aggressive/beast/list_targets(var/dist = 7) +/datum/mob_controller/aggressive/beast/list_targets() . = ..() if(!length(.)) if(LAZYLEN(prey)) @@ -46,6 +46,6 @@ if(M) . |= M else if(body.get_nutrition() < body.get_max_nutrition() * 0.75) //time to look for some food - for(var/mob/living/L in view(body, dist)) + for(var/mob/living/L in get_raw_target_list()) if(attack_same_faction || L.faction != body.faction) LAZYDISTINCTADD(prey, weakref(L)) diff --git a/code/datums/ai/commanded.dm b/code/datums/ai/commanded.dm index e4452782a84a..c9e1e7f8e979 100644 --- a/code/datums/ai/commanded.dm +++ b/code/datums/ai/commanded.dm @@ -85,8 +85,8 @@ var/list/targets = get_targets_by_name(message) if(LAZYLEN(targets) != 1) //CONFUSED. WHO DO I FOLLOW? return 0 - var/weakref/target_ref = targets[1] - set_target(target_ref.resolve()) //YEAH GOOD IDEA + var/weakref/single_target_ref = targets[1] + set_target(single_target_ref.resolve()) //YEAH GOOD IDEA set_stance(STANCE_COMMANDED_FOLLOW) //GOT SOMEBODY. BETTER FOLLOW EM. return 1 @@ -98,7 +98,7 @@ return stop_wandering() var/atom/target = get_target() - if(istype(target) && (target in list_targets(10))) + if(istype(target) && (target in get_raw_target_list())) body.start_automove(target) /datum/mob_controller/aggressive/commanded/proc/commanded_stop() //basically a proc that runs whenever we are asked to stay put. Probably going to remain unused. @@ -125,12 +125,14 @@ LAZYADD(., weakref(M)) /datum/mob_controller/aggressive/commanded/find_target() + SHOULD_CALL_PARENT(FALSE) + next_target_scan_time = world.time + target_scan_delay if(!LAZYLEN(_allowed_targets)) return null var/mode = "specific" if(LAZYACCESS(_allowed_targets, 1) == "everyone") //we have been given the golden gift of murdering everything. Except our master, of course. And our friends. So just mostly everyone. mode = "everyone" - for(var/atom/A in list_targets(10)) + for(var/atom/A in get_raw_target_list()) if(A == src) continue if(isliving(A)) diff --git a/code/datums/movement/automove_controller.dm b/code/datums/movement/automove_controller.dm index 08dae443f358..b413d9998497 100644 --- a/code/datums/movement/automove_controller.dm +++ b/code/datums/movement/automove_controller.dm @@ -1,7 +1,8 @@ /// Implements automove logic; can be overridden on mob procs if you want to vary the logic from the below. /decl/automove_controller - var/completion_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom reaches its target. - var/failure_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom fails to move. + var/completion_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom reaches its target. + var/failure_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom fails to move. + var/try_avoid_obstacles = TRUE // Will try to move 90 degrees around an obstacle. /decl/automove_controller/proc/handle_mover(atom/movable/mover, datum/automove_metadata/metadata) @@ -49,14 +50,16 @@ return TRUE // no idea how we would get into this position if(mover.SelfMove(target_dir) && (old_loc != mover.loc)) - return TRUE + mover.handle_post_automoved(old_loc) + return (mover.get_automove_target() == mover.loc) // We may have transitioned to the next step in a path. - // Try to move around any obstacle. - var/static/list/_alt_dir_rot = list(45, -45) - for(var/alt_dir in shuffle(_alt_dir_rot)) - mover.reset_movement_delay() - if(mover.SelfMove(turn(target_dir, alt_dir)) && (old_loc != mover.loc)) - return TRUE + if(try_avoid_obstacles) + // Try to move around any obstacle. + var/static/list/_alt_dir_rot = list(45, -45) + for(var/alt_dir in shuffle(_alt_dir_rot)) + mover.reset_movement_delay() + if(mover.SelfMove(turn(target_dir, alt_dir)) && (old_loc != mover.loc)) + return TRUE mover.failed_automove() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d2be93779daa..0c98725538ca 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -581,6 +581,9 @@ if(!.) // If we're under or inside shelter, use the z-level rain (for ambience) . = SSweather.weather_by_z[my_turf.z] +/atom/movable/proc/handle_post_automoved(atom/old_loc) + return + /atom/movable/take_vaporized_reagent(reagent, amount) if(ATOM_IS_OPEN_CONTAINER(src)) return loc?.take_vaporized_reagent(reagent, amount) diff --git a/code/game/turfs/turf_navigation.dm b/code/game/turfs/turf_navigation.dm new file mode 100644 index 000000000000..9085f6b99d9a --- /dev/null +++ b/code/game/turfs/turf_navigation.dm @@ -0,0 +1,62 @@ +/******************************************************************/ +// Navigation procs +// Used for A-star pathfinding + +// Returns the surrounding cardinal turfs with open links +// Including through doors openable with the ID +/turf/proc/CardinalTurfsWithAccess(var/obj/item/card/id/ID) + var/L[] = new() + + for(var/d in global.cardinal) + var/turf/T = get_step(src, d) + if(istype(T) && !T.density && T.simulated && !LinkBlockedWithAccess(src, T, ID)) + L.Add(T) + return L + + +// Returns true if a link between A and B is blocked +// Movement through doors allowed if ID has access +/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/card/id/ID) + + 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(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) + return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) + return 0 + return 1 + + if(DirBlockedWithAccess(A,adir, ID)) + return 1 + + if(DirBlockedWithAccess(B,rdir, ID)) + return 1 + + for(var/obj/O in B) + if(O.density && !istype(O, /obj/machinery/door) && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) + return 1 + + return 0 + +// Returns true if direction is blocked from loc +// Checks doors against access with given ID +/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/card/id/ID) + for(var/obj/structure/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if( dir & D.dir ) return !D.check_access(ID) + + //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) + //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) + else return !D.check_access(ID) // it's a real, air blocking door + return 0 diff --git a/code/modules/integrated_electronics/subtypes/smart.dm b/code/modules/integrated_electronics/subtypes/smart.dm index 25f9dca52a4e..f92af368dcd8 100644 --- a/code/modules/integrated_electronics/subtypes/smart.dm +++ b/code/modules/integrated_electronics/subtypes/smart.dm @@ -96,6 +96,10 @@ return ..() /obj/item/integrated_circuit/smart/advanced_pathfinder/do_work() + + if(waiting_for_path) + return + if(!assembly) activate_pin(3) return @@ -119,20 +123,30 @@ if(Pl&&islist(Pl)) idc.access = Pl var/turf/a_loc = get_turf(assembly) - var/list/P = AStar(a_loc, locate(get_pin_data(IC_INPUT, 1), get_pin_data(IC_INPUT, 2), a_loc.z), TYPE_PROC_REF(/turf, CardinalTurfsWithAccess), TYPE_PROC_REF(/turf, Distance), 0, 200, id=idc, exclude=get_turf(get_pin_data_as_type(IC_INPUT, 3, /atom))) + SSpathfinding.enqueue_mover( + src, + locate(get_pin_data(IC_INPUT, 1), get_pin_data(IC_INPUT, 2), a_loc.z), + new /datum/pathfinding_metadata( + _max_node_depth = 200, + _id = idc, + _obstacle = get_turf(get_pin_data_as_type(IC_INPUT, 3, /atom)) + ) + ) - if(!P) - activate_pin(3) - return - else - var/list/Xn = new/list(P.len) - var/list/Yn = new/list(P.len) - var/turf/T - for(var/i =1 to P.len) - T=P[i] - Xn[i] = T.x - Yn[i] = T.y - set_pin_data(IC_OUTPUT, 1, Xn) - set_pin_data(IC_OUTPUT, 2, Yn) - push_data() - activate_pin(2) +/obj/item/integrated_circuit/smart/advanced_pathfinder/path_not_found() + ..() + activate_pin(3) + +/obj/item/integrated_circuit/smart/advanced_pathfinder/path_found(list/path) + ..() + var/list/Xn = new/list(path.len) + var/list/Yn = new/list(path.len) + var/turf/T + for(var/i = 1 to path.len) + T=path[i] + Xn[i] = T.x + Yn[i] = T.y + set_pin_data(IC_OUTPUT, 1, Xn) + set_pin_data(IC_OUTPUT, 2, Yn) + push_data() + activate_pin(2) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index fab8219c1698..cfe9577d41c3 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -242,7 +242,7 @@ resetTarget() lookForTargets() if(will_patrol && !LAZYLEN(grabbed_by) && !target) - if(patrol_path && patrol_path.len) + if(length(patrol_path)) for(var/i = 1 to patrol_speed) sleep(20 / (patrol_speed + 1)) handlePatrol() @@ -266,7 +266,7 @@ if(!target || !target.loc) return if(get_dist(src, target) > min_target_dist) - if(!target_path.len || get_turf(target) != target_path[target_path.len]) + if(!length(target_path) || get_turf(target) != target_path[target_path.len]) calcTargetPath() if(makeStep(target_path)) frustration = 0 @@ -297,9 +297,9 @@ return /mob/living/bot/proc/startPatrol() - var/turf/T = getPatrolTurf() - if(T) - patrol_path = AStar(get_turf(loc), T, TYPE_PROC_REF(/turf, CardinalTurfsWithAccess), TYPE_PROC_REF(/turf, Distance), 0, max_patrol_dist, id = botcard, exclude = obstacle) + var/turf/target_turf = getPatrolTurf() + if(target_turf) + patrol_path = SSpathfinding.find_path_immediate(start = get_turf(loc), end = target_turf, max_node_depth = max_patrol_dist, id = botcard, exclude = obstacle, check_tick = TRUE) if(!patrol_path) patrol_path = list() obstacle = null @@ -331,23 +331,22 @@ return /mob/living/bot/proc/calcTargetPath() - target_path = AStar(get_turf(loc), get_turf(target), TYPE_PROC_REF(/turf, CardinalTurfsWithAccess), TYPE_PROC_REF(/turf, Distance), 0, max_target_dist, id = botcard, exclude = obstacle) - if(!target_path) - if(target && target.loc) - ignore_list |= target - resetTarget() - obstacle = null - return + target_path = SSpathfinding.find_path_immediate(start = get_turf(loc), end = get_turf(target), max_node_depth = max_target_dist, min_target_dist = min_target_dist, id = botcard, exclude = obstacle, check_tick = TRUE) + if(length(target_path)) + return + if(target?.loc) + ignore_list |= target + resetTarget() + obstacle = null /mob/living/bot/proc/makeStep(var/list/path) - if(!path.len) - return 0 - var/turf/T = path[1] - if(get_turf(src) == T) - path -= T + if(!length(path)) + return FALSE + var/turf/target_turf = path[1] + if(get_turf(src) == target_turf) + path -= target_turf return makeStep(path) - - return step_towards(src, T) + return step_towards(src, target_turf) /mob/living/bot/proc/resetTarget() target = null @@ -371,70 +370,6 @@ set_light(0) update_icon() -/******************************************************************/ -// Navigation procs -// Used for A-star pathfinding - - -// Returns the surrounding cardinal turfs with open links -// Including through doors openable with the ID -/turf/proc/CardinalTurfsWithAccess(var/obj/item/card/id/ID) - var/L[] = new() - - for(var/d in global.cardinal) - var/turf/T = get_step(src, d) - if(istype(T) && !T.density && T.simulated && !LinkBlockedWithAccess(src, T, ID)) - L.Add(T) - return L - - -// Returns true if a link between A and B is blocked -// Movement through doors allowed if ID has access -/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/card/id/ID) - - 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(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) - return 0 - - var/pStep = get_step(A,adir&(EAST|WEST)) - if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) - return 0 - return 1 - - if(DirBlockedWithAccess(A,adir, ID)) - return 1 - - if(DirBlockedWithAccess(B,rdir, ID)) - return 1 - - for(var/obj/O in B) - if(O.density && !istype(O, /obj/machinery/door) && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) - return 1 - - return 0 - -// Returns true if direction is blocked from loc -// Checks doors against access with given ID -/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/card/id/ID) - for(var/obj/structure/window/D in loc) - if(!D.density) continue - if(D.dir == SOUTHWEST) return 1 - if(D.dir == dir) return 1 - - for(var/obj/machinery/door/D in loc) - if(!D.density) continue - if(istype(D, /obj/machinery/door/window)) - if( dir & D.dir ) return !D.check_access(ID) - - //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) - //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) - else return !D.check_access(ID) // it's a real, air blocking door - return 0 - /mob/living/bot/GetIdCards(list/exceptions) . = ..() if(istype(botcard) && !is_type_in_list(botcard, exceptions)) diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index e989ba53b320..0381d5de33f7 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -43,11 +43,14 @@ /mob/living/bot/cleanbot/confirmTarget(var/obj/effect/decal/cleanable/D) if(!..()) - return 0 + return FALSE + if(istype(D, /obj/effect/decal/cleanable/dirt)) + var/obj/effect/decal/cleanable/dirt/dirt = D + return dirt.dirt_amount >= 25 for(var/T in target_types) if(istype(D, T)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/bot/cleanbot/handleAdjacentTarget() if(get_turf(target) == src.loc) diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm index 86a8a9411890..0e027aa687ba 100644 --- a/code/modules/mob/living/bot/farmbot.dm +++ b/code/modules/mob/living/bot/farmbot.dm @@ -123,24 +123,6 @@ target = source return -/mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable - for(var/trayDir in list(NORTH, SOUTH, EAST, WEST)) - target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), TYPE_PROC_REF(/turf, CardinalTurfsWithAccess), TYPE_PROC_REF(/turf, Distance), 0, max_target_dist, id = botcard) - if(target_path) - break - if(!target_path) - ignore_list |= target - target = null - target_path = list() - return - -/mob/living/bot/farmbot/stepToTarget() // Same reason - var/turf/T = get_turf(target) - if(!target_path.len || !T.Adjacent(target_path[target_path.len])) - calcTargetPath() - makeStep(target_path) - return - /mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity) . = ..() if(.) diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm index bb9cf31e58e4..437ef6164511 100644 --- a/code/modules/mob/living/bot/mulebot.dm +++ b/code/modules/mob/living/bot/mulebot.dm @@ -183,7 +183,7 @@ /mob/living/bot/mulebot/calcTargetPath() ..() - if(!target_path.len && target != home) // I presume that target is not null + if(!length(target_path) && target != home) // I presume that target is not null resetTarget() target = home targetName = "Home" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4ca6afa75455..49300a21f14b 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1359,11 +1359,6 @@ default behaviour is: return FALSE return TRUE -//gets name from ID or PDA itself, ID inside PDA doesn't matter -//Useful when player is being seen by other mobs -/mob/living/proc/get_id_name(if_no_id = "Unknown") - return GetIdCard(exceptions = list(/obj/item/holder))?.registered_name || if_no_id - /mob/living/get_default_temperature_threshold(threshold) if(isSynthetic()) switch(threshold) diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index c32b39b1a426..2f79162b6c92 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -64,7 +64,7 @@ stop_wandering() stance_step++ if(stance_step >= 20) - if(target && (target in list_targets(10))) + if(target && (target in get_raw_target_list())) set_stance(STANCE_ATTACK) //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. else set_stance(STANCE_IDLE) @@ -72,7 +72,7 @@ if(STANCE_ALERT) stop_wandering() var/found_mob = 0 - if(target && (target in list_targets(10))) + if(target && (target in get_raw_target_list())) if(!attackable(target)) stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. stance_step++ diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm index f504d63398e2..1145b90b6e8b 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm @@ -52,8 +52,8 @@ if(LAZYLEN(targets) != 1) body.say("ERROR. TARGET COULD NOT BE PARSED.") return 0 - var/weakref/target_ref = targets[1] - set_target(target_ref.resolve()) + var/weakref/single_target_ref = targets[1] + set_target(single_target_ref.resolve()) set_stance(STANCE_COMMANDED_HEAL) return 1 if(findtext(text,"emergency protocol")) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm index be65f62f7076..b828ae9e7b09 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm @@ -23,7 +23,7 @@ paired_nurse = null /datum/mob_controller/aggressive/giant_spider/guard/proc/find_nurse() - for(var/mob/living/simple_animal/hostile/giant_spider/nurse/nurse in list_targets(10)) + for(var/mob/living/simple_animal/hostile/giant_spider/nurse/nurse in get_raw_target_list()) if(nurse.stat || !istype(nurse.ai, /datum/mob_controller/aggressive/giant_spider/nurse)) continue var/datum/mob_controller/aggressive/giant_spider/nurse/nurse_ai = nurse.ai diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm index 091230eca451..ead786ab340c 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm @@ -26,7 +26,7 @@ /datum/mob_controller/aggressive/megahivebot can_escape_buckles = TRUE -/datum/mob_controller/aggressive/megahivebot/open_fire() +/datum/mob_controller/aggressive/megahivebot/handle_ranged_target(atom/ranged_target) var/mob/living/simple_animal/hostile/hivebot/mega/megabot = body if(!istype(megabot)) return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index c2e2b3c5a18a..88defeeaf285 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -45,7 +45,7 @@ var/global/list/protected_objects = list( var/awake = TRUE // Return a list of targets that isn't the creator -/datum/mob_controller/aggressive/mimic/list_targets(var/dist = 7) +/datum/mob_controller/aggressive/mimic/get_valid_targets() var/mob/living/simple_animal/hostile/mimic/mimic = body . = istype(mimic) && mimic.awake && ..() if(length(.) && mimic.creator) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index 498adac96b38..e3f5b4fe9ff0 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -54,8 +54,15 @@ /mob/living/simple_animal/hostile/malf_drone/has_ranged_attack() return TRUE -/datum/mob_controller/aggressive/malf_drone/list_targets(var/dist = 7) - . = ..(hostile_drone ? hostile_range : dist) +/datum/mob_controller/aggressive/malf_drone/get_raw_target_list() + if(hostile_drone) + target_scan_distance = hostile_range + else + target_scan_distance = initial(target_scan_distance) + . = ..() + +/datum/mob_controller/aggressive/malf_drone/get_valid_targets() + . = ..() for(var/mob/M in .) if(istype(M, body.type)) . -= M diff --git a/code/modules/mob/living/simple_animal/hostile/slug.dm b/code/modules/mob/living/simple_animal/hostile/slug.dm index 8384fc93a6cd..4218f9176bfa 100644 --- a/code/modules/mob/living/simple_animal/hostile/slug.dm +++ b/code/modules/mob/living/simple_animal/hostile/slug.dm @@ -23,13 +23,14 @@ try_destroy_surroundings = FALSE can_escape_buckles = TRUE -/datum/mob_controller/aggressive/slug/list_targets(var/dist = 7) +/datum/mob_controller/aggressive/slug/valid_target(atom/A) . = ..() - var/mob/living/simple_animal/hostile/slug/slug = body - if(istype(slug)) - for(var/mob/living/M in .) - if(slug.check_friendly_species(M)) - . -= M + if(.) + if(!ismob(A)) + return FALSE + var/mob/living/simple_animal/hostile/slug/slug = body + if(slug.check_friendly_species(A)) + return FALSE /mob/living/simple_animal/hostile/slug/proc/check_friendly_species(var/mob/living/M) return istype(M) && M.faction == faction diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index edf74c14dd0f..35df33c80fa8 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1395,5 +1395,10 @@ /mob/proc/handle_footsteps() return +//gets name from ID or PDA itself, ID inside PDA doesn't matter +//Useful when player is being seen by other mobs +/mob/proc/get_id_name(if_no_id = "Unknown") + return GetIdCard(exceptions = list(/obj/item/holder))?.registered_name || if_no_id + /mob/proc/can_twohand_item(obj/item/item) return FALSE diff --git a/code/modules/mob/mob_automove.dm b/code/modules/mob/mob_automove.dm index ff8d1a6d7bae..f552d4f7c1e6 100644 --- a/code/modules/mob/mob_automove.dm +++ b/code/modules/mob/mob_automove.dm @@ -6,18 +6,60 @@ _automove_target = null return ..() +/mob/path_found(list/path) + ..() + if(islist(path) && length(path) > 1) + path.Cut(1, 2) // Remove the first turf since it's going to be our origin. + if(length(path)) + start_automove(path) + +/mob/path_not_found() + ..() + stop_automove() + /// Called by get_movement_delay() to override the current move intent, in cases where an automove has a delay override. /mob/proc/get_automove_delay() var/datum/automove_metadata/metadata = SSautomove.moving_metadata[src] return metadata?.move_delay +/mob/failed_automove() + ..() + stop_automove() + _automove_target = null + return FALSE + /mob/start_automove(target, movement_type, datum/automove_metadata/metadata) _automove_target = target return ..() // The AI datum may decide to track a target instead of using the mob reference. /mob/get_automove_target(datum/automove_metadata/metadata) - . = (istype(ai) && ai.get_automove_target()) || _automove_target || ..() + . = _automove_target || (istype(ai) && ai.get_automove_target()) || ..() + if(islist(.)) + var/list/path = . + while(length(path) && path[1] == get_turf(src)) + path.Cut(1,2) + if(length(path)) + return path[1] + return null + +/mob/handle_post_automoved(atom/old_loc) + if(istype(ai)) + ai.handle_post_automoved(old_loc) + return + if(!islist(_automove_target) || length(_automove_target) <= 0) + return + var/turf/body_turf = get_turf(src) + if(!istype(body_turf)) + return + var/list/_automove_target_list = _automove_target + if(_automove_target_list[1] != body_turf) + return + if(length(_automove_target_list) > 1) + _automove_target_list.Cut(1, 2) + else + _automove_target_list = null + stop_automove() // We do some early checking here to avoid doing the same checks repeatedly by calling SelfMove(). /mob/can_do_automated_move(variant_move_delay) diff --git a/code/procs/AStar.dm b/code/procs/pathfinding.dm similarity index 78% rename from code/procs/AStar.dm rename to code/procs/pathfinding.dm index 01e4213f805d..7732761b8d3c 100644 --- a/code/procs/AStar.dm +++ b/code/procs/pathfinding.dm @@ -5,14 +5,14 @@ A Star pathfinding algorithm Returns a list of tiles forming a path from A to B, taking dense objects as well as walls, and the orientation of windows along the route into account. Use: -your_list = AStar(start location, end location, adjacent turf proc, distance proc) +your_list = find_path_astar(start location, end location, adjacent turf proc, distance proc) For the adjacent turf proc i wrote: /turf/proc/AdjacentTurfs And for the distance one i wrote: /turf/proc/Distance So an example use might be: -src.path_list = AStar(src.loc, target.loc, TYPE_PROC_REF(/turf, AdjacentTurfs), TYPE_PROC_REF(/turf, Distance)) +src.path_list = find_path_astar(src.loc, target.loc, TYPE_PROC_REF(/turf, AdjacentTurfs), TYPE_PROC_REF(/turf, Distance)) Note: The path is returned starting at the END node, so i wrote reverselist to reverse it for ease of use. @@ -60,7 +60,12 @@ length to avoid portals or something i guess?? Not that they're counted right no /proc/PathWeightCompare(PathNode/a, PathNode/b) return a.estimated_cost - b.estimated_cost -/proc/AStar(var/start, var/end, adjacent, dist, var/max_nodes, var/max_node_depth = 30, var/min_target_dist = 0, var/min_node_dist, var/id, var/datum/exclude) +/proc/find_path_astar_async(start, end, adjacent, dist, max_nodes, max_node_depth = 30, min_target_dist = 0, min_node_dist, id, datum/exclude) + set waitfor = FALSE + return find_path_astar(start, end, adjacent, dist, max_nodes, max_node_depth, min_target_dist, min_node_dist, id, exclude, check_tick = TRUE) + +/proc/find_path_astar(start, end, adjacent, dist, max_nodes, max_node_depth = 30, min_target_dist = 0, min_node_dist, id, datum/exclude, check_tick = FALSE) + var/datum/priority_queue/open = new /datum/priority_queue(/proc/PathWeightCompare) var/list/closed = list() var/list/path @@ -85,13 +90,11 @@ length to avoid portals or something i guess?? Not that they're counted right no path[index--] = current.position break - if(min_node_dist && max_node_depth) - if(call(current.position, min_node_dist)(end) + current.nodes_traversed >= max_node_depth) - continue + if(min_node_dist && max_node_depth && (call(current.position, min_node_dist)(end) + current.nodes_traversed >= max_node_depth)) + continue - if(max_node_depth) - if(current.nodes_traversed >= max_node_depth) - continue + if(max_node_depth && current.nodes_traversed >= max_node_depth) + continue for(var/datum/datum in call(current.position, adjacent)(id)) if(datum == exclude) @@ -115,4 +118,9 @@ length to avoid portals or something i guess?? Not that they're counted right no if(max_nodes && open.Length() > max_nodes) open.Remove(open.Length()) + if(check_tick) + CHECK_TICK + if(check_tick) + CHECK_TICK + return path diff --git a/nebula.dme b/nebula.dme index d286bdf0899f..4ea2a638823c 100644 --- a/nebula.dme +++ b/nebula.dme @@ -283,6 +283,7 @@ #include "code\controllers\subsystems\mapping.dm" #include "code\controllers\subsystems\misc_late.dm" #include "code\controllers\subsystems\overlays.dm" +#include "code\controllers\subsystems\pathfinding.dm" #include "code\controllers\subsystems\plants.dm" #include "code\controllers\subsystems\radiation.dm" #include "code\controllers\subsystems\shuttle.dm" @@ -357,7 +358,13 @@ #include "code\datums\type_cloning.dm" #include "code\datums\weakref.dm" #include "code\datums\ai\_ai.dm" +#include "code\datums\ai\_ai_enemies.dm" +#include "code\datums\ai\_ai_friends.dm" +#include "code\datums\ai\_ai_memory.dm" +#include "code\datums\ai\_ai_pathfinding.dm" #include "code\datums\ai\_ai_stance.dm" +#include "code\datums\ai\_ai_targets.dm" +#include "code\datums\ai\_ai_wander.dm" #include "code\datums\ai\aggressive.dm" #include "code\datums\ai\beast.dm" #include "code\datums\ai\commanded.dm" @@ -1574,6 +1581,7 @@ #include "code\game\turfs\turf_footsteps.dm" #include "code\game\turfs\turf_height.dm" #include "code\game\turfs\turf_material.dm" +#include "code\game\turfs\turf_navigation.dm" #include "code\game\turfs\turf_ramps.dm" #include "code\game\turfs\unsimulated.dm" #include "code\game\turfs\flooring\_flooring.dm" @@ -4070,9 +4078,9 @@ #include "code\modules\ZAS\Variable Settings.dm" #include "code\modules\ZAS\Zone.dm" #include "code\procs\announce.dm" -#include "code\procs\AStar.dm" #include "code\procs\dbcore.dm" #include "code\procs\hud.dm" +#include "code\procs\pathfinding.dm" #include "code\procs\radio.dm" #include "code\unit_tests\_defines.dm" #include "code\unit_tests\_includes.dm" From c1e1e68dff6b8e915648310e1c51401896ad1abc Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 14:56:13 +1100 Subject: [PATCH 25/90] Adds a grandfather clock. --- .../objects/structures/grandfather_clock.dm | 63 ++++++++++++++++++ icons/obj/structures/grandfather_clock.dmi | Bin 0 -> 721 bytes nebula.dme | 1 + 3 files changed, 64 insertions(+) create mode 100644 code/game/objects/structures/grandfather_clock.dm create mode 100644 icons/obj/structures/grandfather_clock.dmi diff --git a/code/game/objects/structures/grandfather_clock.dm b/code/game/objects/structures/grandfather_clock.dm new file mode 100644 index 000000000000..b1dadeb884a6 --- /dev/null +++ b/code/game/objects/structures/grandfather_clock.dm @@ -0,0 +1,63 @@ +// TODO: buildable with artifice? +// TODO: looping 2 second tick tock sound, somehow aligned with pendulum (may not be possible in DM) +/obj/structure/grandfather_clock + name = "grandfather clock" + desc = "A tall, stately timepiece." + icon = 'icons/obj/structures/grandfather_clock.dmi' + icon_state = ICON_STATE_WORLD + density = TRUE + material = /decl/material/solid/organic/wood/mahogany + var/face_color = "#f0edc7" + var/last_time + var/decl/material/clockwork_mat = /decl/material/solid/metal/brass + +/obj/structure/grandfather_clock/Initialize(ml, _mat, _reinf_mat) + if(ispath(clockwork_mat)) + clockwork_mat = GET_DECL(clockwork_mat) + . = ..() + START_PROCESSING(SSobj, src) + update_icon() + +/obj/structure/grandfather_clock/examine(mob/user, distance, infix, suffix) + . = ..() + // TODO: check literacy? + if(isnull(last_time)) + last_time = stationtime2text() + to_chat(user, SPAN_NOTICE("The face of \the [src] reads [last_time].")) + +// TODO: don't magically make the time update when swinging is restarted +// TODO: alt interaction to interfere with the clock? +/obj/structure/grandfather_clock/attack_hand(mob/user) + . = ..() + if(!.) + if(is_processing) + STOP_PROCESSING(SSobj, src) + user.visible_message(SPAN_NOTICE("\The [user] reaches into \the [src] and stops the pendulum.")) + else + START_PROCESSING(SSobj, src) + user.visible_message(SPAN_NOTICE("\The [user] reaches into \the [src] and sets the pendulum swinging.")) + update_icon() + return TRUE + +/obj/structure/grandfather_clock/Process() + ..() + var/new_time = stationtime2text() + if(new_time != last_time) + last_time = new_time + update_icon() + +/obj/structure/grandfather_clock/on_update_icon() + . = ..() + if(isnull(last_time)) + last_time = stationtime2text() + if(face_color) + add_overlay(overlay_image(icon, "[icon_state]-face", face_color, RESET_COLOR)) + if(!clockwork_mat) + return + if(is_processing) + add_overlay(overlay_image(icon, "[icon_state]-pendulum-swing", clockwork_mat.color, RESET_COLOR)) + else + add_overlay(overlay_image(icon, "[icon_state]-pendulum", clockwork_mat.color, RESET_COLOR)) + var/list/time_stats = splittext(last_time, ":") + add_overlay(overlay_image(icon, "[icon_state]-hour[round(((text2num(time_stats[1]) / 24) * 360) / 45) * 45]"), clockwork_mat.color, RESET_COLOR) + add_overlay(overlay_image(icon, "[icon_state]-minute[round(((text2num(time_stats[2]) / 60) * 360) / 45) * 45]"), clockwork_mat.color, RESET_COLOR) diff --git a/icons/obj/structures/grandfather_clock.dmi b/icons/obj/structures/grandfather_clock.dmi new file mode 100644 index 0000000000000000000000000000000000000000..cbef65c5ac440ee9343dc9001a6fdbbf2aac640a GIT binary patch literal 721 zcmV;?0xtcDP)fFDZ*Bkp zc$}4!F%E+u6hLP<1<_R-MVs28OQUHV>K#l$AyI4qYkK>V;?ktUXX1bIc*9GG$+fw) z9jWgvesOK&qR54mhYX`lGArCtP>ckZqp*H4wzu4k(YEM`MHn%ujoWjK2Hnrx&%abU z^bZb1#j@%wfGv*!@Hxbs7a{7r3UN~!;-;q%cacNgvsA0)P`9VSy*&;t?s0hYod;L< zJiPnPgUfp!-u}rITc>pn#8b0LHU588xm!NY*do4}q!>>xW>80`dNb@L&pblN*=<-Lx#u5(REc_Z2QH$z$c((T~%o zK;y?l1#W})!>2%u?P^7XTP$AKq`i&4{S=7t>ckR(B(|IRyn|xa+xedX`&&f+9W*|K zW6uPrXJclnfHTHX1>_(rF!nvwf&1?J`Od3fyQc%91?PhIv*THC?)g{26c~*$SEfKb zp?F3-fv16JfhX`X;QfOp(7hZOOB3kd@C1Yqhmg$Kdk1fut9OAo*Z=p0>yv>6FIZe4 zgb+dqA%yr9_G7tpJg6E2G3K}9`kGmvy#@4~++i_wNhpL6LI@#*5aLMA Date: Mon, 9 Dec 2024 10:19:51 +1100 Subject: [PATCH 26/90] Fixing issues with ammo magazine contents init. --- code/modules/projectiles/ammunition.dm | 1 + code/modules/projectiles/ammunition/boxes.dm | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index a26611bd8949..f163d0f64c76 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -167,6 +167,7 @@ return for(var/i in 1 to initial_ammo) stored_ammo += new ammo_type(src) + contents_initialized = TRUE /obj/item/ammo_magazine/proc/get_stored_ammo_count() . = length(stored_ammo) diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index 43f6f7fb6c1a..962cdda36769 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -18,14 +18,16 @@ /obj/item/ammo_magazine/speedloader/on_update_icon() . = ..() - if(!length(stored_ammo)) + var/ammo_count = get_stored_ammo_count() + if(!ammo_count) return + create_initial_contents() // Not ideal, but we need instances for the icon gen. switch(icon_state) if("world") var/ammo_state = "world-some" - if(length(stored_ammo) == 1) + if(ammo_count == 1) ammo_state = "world-one" - else if(length(stored_ammo) == max_ammo) + else if(ammo_count == max_ammo) ammo_state = "world-full" var/obj/item/ammo_casing/A = stored_ammo[1] add_overlay(overlay_image(icon, ammo_state, A.color, RESET_COLOR)) From 1a9c1db9c20f1bae4b3ae70965ab7fd56d424437 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Mon, 9 Dec 2024 10:25:25 +1100 Subject: [PATCH 27/90] Synthetics do not get hungry or thirsty. --- code/modules/mob/living/life.dm | 2 +- code/modules/mob/living/living.dm | 4 ++-- code/modules/mob/living/silicon/silicon.dm | 9 --------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index e73ef41b016b..f81a0412fcce 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -121,7 +121,7 @@ return TRUE /mob/living/proc/experiences_hunger_and_thirst() - return TRUE + return !isSynthetic() // Doesn't really apply to robots. Maybe unify this with cells in the future. /mob/living/proc/get_hunger_factor() var/decl/species/my_species = get_species() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4796744c4417..6889922700ef 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -920,7 +920,7 @@ default behaviour is: nutrition = clamp(amt, 0, get_max_nutrition()) /mob/living/proc/get_nutrition() - return nutrition + return isSynthetic() ? get_max_nutrition() : nutrition /mob/living/proc/adjust_nutrition(var/amt) set_nutrition(get_nutrition() + amt) @@ -929,7 +929,7 @@ default behaviour is: return 500 /mob/living/proc/get_hydration(var/amt) - return hydration + return isSynthetic() ? get_max_hydration() : hydration /mob/living/proc/set_hydration(var/amt) hydration = clamp(amt, 0, get_max_hydration()) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index ebcd89aaf521..21a5b1be638b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -71,15 +71,6 @@ /mob/living/silicon/get_dexterity(silent) return dexterity -/mob/living/silicon/experiences_hunger_and_thirst() - return FALSE // Doesn't really apply to robots. Maybe unify this with cells in the future. - -/mob/living/silicon/get_nutrition() - return get_max_nutrition() - -/mob/living/silicon/get_hydration() - return get_max_hydration() - /mob/living/silicon/fully_replace_character_name(new_name) ..() create_or_update_account(new_name) From ef86cd4fe6d769ceaa7e9e5323b3b659a75006b3 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 11:18:14 +1100 Subject: [PATCH 28/90] Various clothing and equipment tweaks for Karzerfeste. --- code/datums/outfits/outfit.dm | 173 +++++++++++------- code/modules/clothing/neck/jewelry.dm | 3 + code/modules/clothing/suits/armor/_armor.dm | 9 +- .../clothing/suits/armor/forged/brigandine.dm | 1 + code/modules/clothing/suits/hooded_cloak.dm | 3 +- code/modules/clothing/suits/mantle.dm | 7 +- code/modules/clothing/suits/robes.dm | 7 + code/modules/tools/subtypes/axes.dm | 3 + code/modules/tools/subtypes/pickaxes.dm | 4 + icons/clothing/suits/sleeved_robe.dmi | Bin 0 -> 1083 bytes maps/shaded_hills/outfits/_outfits.dm | 7 +- mods/content/fantasy/_fantasy.dme | 1 + mods/content/fantasy/datum/outfits.dm | 15 +- .../content/fantasy/icons/clothing/jerkin.dmi | Bin 1075 -> 1100 bytes .../fantasy/icons/clothing/trousers.dmi | Bin 939 -> 948 bytes .../fantasy/items/clothing/_loadout.dm | 21 +++ .../fantasy/items/clothing/_recipes.dm | 2 +- mods/content/fantasy/items/clothing/armor.dm | 2 +- mods/content/fantasy/items/clothing/cloak.dm | 17 ++ mods/content/fantasy/items/clothing/jerkin.dm | 12 ++ .../fantasy/items/clothing/trousers.dm | 9 +- 21 files changed, 205 insertions(+), 91 deletions(-) create mode 100644 icons/clothing/suits/sleeved_robe.dmi create mode 100644 mods/content/fantasy/items/clothing/cloak.dm diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm index 572306145f56..c3728f48a2a5 100644 --- a/code/datums/outfits/outfit.dm +++ b/code/datums/outfits/outfit.dm @@ -1,24 +1,26 @@ /decl/outfit abstract_type = /decl/outfit - var/name = "Naked" - var/uniform = null - var/suit = null - var/back = null - var/belt = null - var/gloves = null - var/shoes = null - var/head = null - var/mask = null - var/l_ear = null - var/r_ear = null - var/glasses = null - var/id = null - var/l_pocket = null - var/r_pocket = null + var/name = "Naked And Afraid" + var/uniform = null + var/suit = null + var/back = null + var/belt = null + var/gloves = null + var/shoes = null + var/head = null + var/mask = null + var/l_ear = null + var/r_ear = null + var/glasses = null + var/id = null + var/l_pocket = null + var/r_pocket = null var/suit_store = null - var/holster = null + var/holster = null + /// Linear list of types. Will attempt to place items in hands. var/list/hands - var/list/backpack_contents = list() // In the list(path=count,otherpath=count) format + //. An associative list in list(path=count,otherpath=count) format. Will attempt to place items in storage. + var/list/backpack_contents var/id_type var/id_desc @@ -36,16 +38,21 @@ . = ..() backpack_overrides = backpack_overrides || list() -// This proc is structured slightly strangely because I will be adding pants to it. +// Used for slightly cleaner code around multi-equip records. +/decl/outfit/proc/resolve_equip_to_list(check_type) + if(islist(check_type)) + return check_type + if(ispath(check_type)) + return list(check_type) + return null + /decl/outfit/validate() . = ..() for(var/check_type in list(uniform, suit, back, belt, gloves, shoes, head, mask, l_ear, r_ear, glasses, id, l_pocket, r_pocket, suit_store, pda_type, id_type)) - var/obj/item/thing = check_type - if(isnull(thing)) - continue - if(TYPE_IS_ABSTRACT(thing)) - . += "equipment includes abstract type '[thing]'" + for(var/obj/item/thing as anything in resolve_equip_to_list(check_type)) + if(TYPE_IS_ABSTRACT(thing)) + . += "equipment includes abstract type '[thing]'" for(var/check_type in hands) var/obj/item/thing = check_type @@ -62,18 +69,27 @@ . += "backpack includes abstract type '[thing]'" if(uniform && (outfit_flags & OUTFIT_HAS_VITALS_SENSOR)) - if(!ispath(uniform, /obj/item/clothing)) - . += "outfit is flagged for sensors, but uniform cannot take accessories" - var/succeeded = FALSE - var/obj/item/sensor = new /obj/item/clothing/sensor/vitals - if(uniform) - var/obj/item/clothing/wear_uniform = new uniform // sadly we need to read a list - if(wear_uniform.can_attach_accessory(sensor)) - succeeded = TRUE - qdel(wear_uniform) - if(!succeeded) - . += "outfit is flagged for sensors, but uniform does not accept sensors" - qdel(sensor) + var/list/uniforms = resolve_equip_to_list(uniform) + if(!length(uniforms)) + . += "outfit is flagged for sensors, but has no uniform" + else + var/succeeded = FALSE + var/obj/item/sensor = new /obj/item/clothing/sensor/vitals + for(var/thing in uniforms) + if(!ispath(thing, /obj/item/clothing)) + . += "outfit is flagged for sensors, but uniform [thing] cannot take accessories" + if(thing) + var/obj/item/clothing/wear_uniform = new thing // sadly we need to read a list + if(wear_uniform.can_attach_accessory(sensor)) + succeeded = TRUE + if(!QDELETED(wear_uniform)) + qdel(wear_uniform) + if(succeeded) + break + if(!QDELETED(sensor)) + qdel(sensor) + if(!succeeded) + . += "outfit is flagged for sensors, but uniform does not accept sensors" /decl/outfit/proc/pre_equip(mob/living/wearer) if(outfit_flags & OUTFIT_RESET_EQUIPMENT) @@ -91,8 +107,8 @@ equip_base(wearer, equip_adjustments) equip_id(wearer, assignment, equip_adjustments, job, rank) for(var/path in backpack_contents) - var/number = backpack_contents[path] - for(var/i=0,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 diff --git a/mods/content/fantasy/items/clothing/_loadout.dm b/mods/content/fantasy/items/clothing/_loadout.dm index 9d7f449a9f5c..7815b308a50b 100644 --- a/mods/content/fantasy/items/clothing/_loadout.dm +++ b/mods/content/fantasy/items/clothing/_loadout.dm @@ -34,10 +34,26 @@ slot = slot_w_uniform_str uid = "gear_fantasy_loincloth" +/decl/loadout_option/fantasy/uniform/shirt + name = "shirt" + path = /obj/item/clothing/shirt/crafted + uid = "gear_fantasy_shirt" + available_materials = list( + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/cloth/hemp, + /decl/material/solid/organic/cloth/linen + ) + /decl/loadout_option/fantasy/uniform/jerkin name = "jerkin" path = /obj/item/clothing/shirt/jerkin uid = "gear_fantasy_jerkin" + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/skin/feathers, + /decl/material/solid/organic/skin/fur + ) /decl/loadout_option/fantasy/uniform/tunic name = "tunic" @@ -102,6 +118,11 @@ path = /obj/item/clothing/suit/hooded_cloak uid = "gear_fantasy_cloak_hooded" +/decl/loadout_option/fantasy/suit/winter_cloak + name = "cloak, winter" + path = /obj/item/clothing/suit/hooded_cloak/winter + uid = "gear_fantasy_cloak_hooded_winter" + /decl/loadout_option/fantasy/suit/poncho name = "poncho" path = /obj/item/clothing/suit/poncho/colored diff --git a/mods/content/fantasy/items/clothing/_recipes.dm b/mods/content/fantasy/items/clothing/_recipes.dm index 219a875f5bd0..99942d8918ed 100644 --- a/mods/content/fantasy/items/clothing/_recipes.dm +++ b/mods/content/fantasy/items/clothing/_recipes.dm @@ -1,5 +1,5 @@ /decl/stack_recipe/textiles/jerkin - result_type = /obj/item/clothing/shirt/jerkin + result_type = /obj/item/clothing/shirt/crafted category = "clothing" /decl/stack_recipe/textiles/gown diff --git a/mods/content/fantasy/items/clothing/armor.dm b/mods/content/fantasy/items/clothing/armor.dm index fd475c07f32a..22651d3243d5 100644 --- a/mods/content/fantasy/items/clothing/armor.dm +++ b/mods/content/fantasy/items/clothing/armor.dm @@ -1,3 +1,3 @@ // Override of the base item to add lore to the desc. /obj/item/clothing/suit/armor/forged/banded - desc = "A suit of overlapping armoured plates that covers the upper and lower body. Favoured by the Aegis and many Splinter Kingdoms." + desc = "A suit of overlapping armoured plates that covers the upper and lower body. Historically favoured by the Aegis and loyally adopted by many Splinter Kingdoms." diff --git a/mods/content/fantasy/items/clothing/cloak.dm b/mods/content/fantasy/items/clothing/cloak.dm new file mode 100644 index 000000000000..f61d886efe5a --- /dev/null +++ b/mods/content/fantasy/items/clothing/cloak.dm @@ -0,0 +1,17 @@ +// TODO: big fuckoff fur collar icons +/obj/item/clothing/head/hood/cloak/winter + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/suit/hooded_cloak/winter + cold_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_LEGS|SLOT_HANDS|SLOT_FEET + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + hood = /obj/item/clothing/head/hood/cloak/winter + protects_against_weather = TRUE + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/suit/robe/sleeved/shrine + material = /decl/material/solid/organic/cloth/linen + paint_color = COLOR_DARK_RED + markings_color = COLOR_OFF_WHITE + markings_state_modifier = "_sleeves" diff --git a/mods/content/fantasy/items/clothing/jerkin.dm b/mods/content/fantasy/items/clothing/jerkin.dm index dc437db931dd..942a871a81cb 100644 --- a/mods/content/fantasy/items/clothing/jerkin.dm +++ b/mods/content/fantasy/items/clothing/jerkin.dm @@ -5,3 +5,15 @@ _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi' material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC material = /decl/material/solid/organic/leather + +/obj/item/clothing/shirt/crafted + desc = "A simple shirt, worn on the upper body." + icon = 'mods/content/fantasy/icons/clothing/jerkin.dmi' // TODO state with sleeves + sprite_sheets = list(BODYTYPE_HNOLL = 'mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi') + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/clothing/shirt/crafted/wool + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/shirt/crafted/linen + material = /decl/material/solid/organic/cloth/linen diff --git a/mods/content/fantasy/items/clothing/trousers.dm b/mods/content/fantasy/items/clothing/trousers.dm index cbe30375bff0..4fac34236e9b 100644 --- a/mods/content/fantasy/items/clothing/trousers.dm +++ b/mods/content/fantasy/items/clothing/trousers.dm @@ -7,12 +7,9 @@ color = /decl/material/solid/organic/leather::color _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/trousers_hnoll.dmi' -/obj/item/clothing/pants/trousers/jerkin/Initialize() - . = ..() - var/obj/item/clothing/shirt/jerkin/jerkin = new - attach_accessory(null, jerkin) - if(!(jerkin in accessories)) - qdel(jerkin) +/obj/item/clothing/pants/trousers/linen + material = /decl/material/solid/organic/cloth/linen + color = /decl/material/solid/organic/cloth/linen::color /obj/item/clothing/pants/trousers/braies name = "braies" From 5bf0757d2fa0e1ddd73f7b3bd8738228b21c3746 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Sat, 7 Dec 2024 14:01:37 +1100 Subject: [PATCH 29/90] Adding several low tech armor/weapon props. --- code/datums/weakref.dm | 7 +- code/game/objects/structures/armor_stand.dm | 75 ++++++++++++++++++ .../objects/structures/training_dummies.dm | 30 +++++++ .../crafting/stack_recipes/recipes_planks.dm | 4 + icons/obj/structures/archery_butt.dmi | Bin 0 -> 450 bytes icons/obj/structures/armor_stand.dmi | Bin 0 -> 278 bytes icons/obj/structures/training_dummy.dmi | Bin 0 -> 429 bytes nebula.dme | 2 + 8 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 code/game/objects/structures/armor_stand.dm create mode 100644 code/game/objects/structures/training_dummies.dm create mode 100644 icons/obj/structures/archery_butt.dmi create mode 100644 icons/obj/structures/armor_stand.dmi create mode 100644 icons/obj/structures/training_dummy.dmi diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm index a613528d27cb..ab0ecb9c6e2e 100644 --- a/code/datums/weakref.dm +++ b/code/datums/weakref.dm @@ -15,14 +15,15 @@ /weakref var/ref + var/name // Useful for input() on lists of weakrefs. // Handy info for debugging - var/tmp/ref_name + var/tmp/name var/tmp/ref_type /weakref/New(datum/D) ref = "\ref[D]" - ref_name = "[D]" + name = "[D]" ref_type = D.type /weakref/Destroy() @@ -38,7 +39,7 @@ return null /weakref/get_log_info_line() - return "[ref_name] ([ref_type]) ([ref]) (WEAKREF)" + return "[name] ([ref_type]) ([ref]) (WEAKREF)" /weakref/CanClone() return FALSE //Pass weakref as references since they're unique per atom instance \ No newline at end of file diff --git a/code/game/objects/structures/armor_stand.dm b/code/game/objects/structures/armor_stand.dm new file mode 100644 index 000000000000..96b52bc8266a --- /dev/null +++ b/code/game/objects/structures/armor_stand.dm @@ -0,0 +1,75 @@ +/obj/structure/armor_stand + name = "armor stand" + desc = "A simple stand used to hold armor and helmets for display." + icon = 'icons/obj/structures/armor_stand.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + var/list/slots_to_gear = list( + (slot_wear_suit_str) = null, + (slot_head_str) = null, + (slot_belt_str) = null, + (slot_shoes_str) = null, + (slot_gloves_str) = null + ) + var/list/gear_to_slot + +/obj/structure/armor_stand/Exited(atom/movable/AM, atom/new_loc) + . = ..() + var/weakref/atom_ref = weakref(AM) + if(atom_ref in gear_to_slot) + var/slot = gear_to_slot[atom_ref] + slots_to_gear[slot] = null + LAZYREMOVE(gear_to_slot, atom_ref) + update_icon() + +/obj/structure/armor_stand/Destroy() + slots_to_gear.Cut() + LAZYCLEARLIST(gear_to_slot) + . = ..() + +/obj/structure/armor_stand/attack_hand(mob/user) + . = ..() + if(. || !LAZYLEN(gear_to_slot)) + return + if(LAZYLEN(gear_to_slot) == 1) + var/weakref/removed_item_ref = gear_to_slot[1] + else + removed_item_ref = input(user, "Which piece of equipment would you like to remove?", "Armor Stand") as null|anything in gear_to_slot + if(!CanPhysicallyInteract(user) || QDELETED(src) || QDELETED(user) || !(removed_item_ref in gear_to_slot)) + return TRUE + var/obj/item/removed_item = removed_item_ref?.resolve() + if(istype(removed_item) && !QDELETED(removed_item) && removed_item.loc == src) + removed_item.dropInto(loc) + user.put_in_hands(removed_item) + return TRUE + +/obj/structure/armor_stand/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/clothing)) + var/obj/item/clothing/clothes = used_item + if(!(clothes.fallback_slot in slots_to_gear)) + to_chat(user, SPAN_WARNING("\The [src] cannot hold \the [used_item].")) + else if(slots_to_gear[clothes.fallback_slot]) + var/weakref/atom_ref = slots_to_gear[clothes.fallback_slot] + to_chat(user, SPAN_WARNING("\The [src] is already holding \the [atom_ref.resolve()].")) + else if(user.try_unequip(clothes, src)) + var/weakref/atom_ref = weakref(clothes) + slots_to_gear[clothes.fallback_slot] = atom_ref + LAZYSET(gear_to_slot, atom_ref, clothes.fallback_slot) + to_chat(user, SPAN_NOTICE("You hang \the [clothes] from \the [src].")) + update_icon() + return TRUE + return ..() + +/obj/structure/armor_stand/on_update_icon() + . = ..() + for(var/slot in slots_to_gear) + var/weakref/atom_ref = slots_to_gear[slot] + var/obj/item/thing = atom_ref?.resolve() + if(istype(thing)) + var/image/mob_overlay = thing.get_mob_overlay(null, slot) + mob_overlay.appearance_flags |= RESET_COLOR + add_overlay(mob_overlay) + compile_overlays() diff --git a/code/game/objects/structures/training_dummies.dm b/code/game/objects/structures/training_dummies.dm new file mode 100644 index 000000000000..ed0e7fc0d94f --- /dev/null +++ b/code/game/objects/structures/training_dummies.dm @@ -0,0 +1,30 @@ +// TODO: skill check on melee/ranged hit to show bullseye/heart shot/etc +// TODO: craft the base frame, add cloth/dry grass to replace dummy, remove dummy on damage. +// TODO: add a modern-style version, merge with and replace the magnet dummies? + +/obj/structure/training_dummy + name = "training dummy" + desc = "A simple stand used to prop up a training dummy for practice." + icon = 'icons/obj/structures/training_dummy.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + var/decl/material/dummy_mat = /decl/material/solid/organic/plantmatter/grass/dry + +/obj/structure/training_dummy/Initialize(ml, _mat, _reinf_mat) + if(ispath(dummy_mat)) + dummy_mat = GET_DECL(dummy_mat) + . = ..() + update_icon() + +/obj/structure/training_dummy/on_update_icon() + . = ..() + if(dummy_mat) + add_overlay(overlay_image(icon, "[icon_state]-dummy", dummy_mat.color, RESET_COLOR)) + +/obj/structure/training_dummy/archery + name = "archery butt" + desc = "A heavy circular target used for practicing archery." + icon = 'icons/obj/structures/archery_butt.dmi' diff --git a/code/modules/crafting/stack_recipes/recipes_planks.dm b/code/modules/crafting/stack_recipes/recipes_planks.dm index f58f931cf5bb..de760228f25b 100644 --- a/code/modules/crafting/stack_recipes/recipes_planks.dm +++ b/code/modules/crafting/stack_recipes/recipes_planks.dm @@ -227,3 +227,7 @@ result_type = /obj/structure/divider difficulty = MAT_VALUE_HARD_DIY +/decl/stack_recipe/planks/furniture/armor_stand + result_type = /obj/structure/armor_stand + difficulty = MAT_VALUE_NORMAL_DIY + diff --git a/icons/obj/structures/archery_butt.dmi b/icons/obj/structures/archery_butt.dmi new file mode 100644 index 0000000000000000000000000000000000000000..45bbb36c105fbcec1583a324f7fb80fb68061e3b GIT binary patch literal 450 zcmV;z0X_bSP)p8x;fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@**gRq3Xb=H^!7Qmd@s>gNJ>0stc0CsMiP z?$Q7N0N+VOK~y-6)sjgL!ypVrLx+6~K0t{$Kv6DGqjcXzx&KuP!47H~s!Cb)Z!F=b z?*Vt+p9uOA75ok;kjJdyQsQA)@@5=;C8k@6r)kN108@z|fa3?_^)y-I1t0;CAH22z z+L{F*n1u`|wAn$E)SxiTats_bW(TrY0q$|ulL4@l9Z<{I>mIzd*+Fa508$EEfP^&w z#N?jp5VZkBqJ6;k66+?RZn6xnWX!$^@S+$Pf~?x{LCC7Pg&1VjE^?RrSxrEd?`|JV sB9cQrxldqqv>U*?_5<-z;yG?4Urd%W0d9rr*#H0l07*qoM6N<$g8g&BtN;K2 literal 0 HcmV?d00001 diff --git a/icons/obj/structures/armor_stand.dmi b/icons/obj/structures/armor_stand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0431f7f626cc5d7b2d58d74dbb040a759f0f10c1 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*8>L*96ES1HL0wtYo4cj z%%A49M}Sg{B|(0{3=Yq3qyagZRUr{2E~&-IMVSR9nfZAP3>9;N!wQN@zkdlX`1tjS zmbb3fxija3H-s8oG=A_%=e&>RNrs}H-W?XkLB^Mjy%gp=nsj7Rh(hp6oBbN?&t;ucLK6TI-eUFu literal 0 HcmV?d00001 diff --git a/icons/obj/structures/training_dummy.dmi b/icons/obj/structures/training_dummy.dmi new file mode 100644 index 0000000000000000000000000000000000000000..54cf40de1c9347e605aa2f23069c6ff6f270a8a1 GIT binary patch literal 429 zcmV;e0aE^nP)Z8+u;BJ00DGTPE!Ct=GbNc0047(R9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@**gRq3Xb=H^!7Qmd@s>gNJ>0stc0CsMiP z?$Q7N0Ln>3K~y-6#gj1(gD?z5i4^wIngbLr&|b9Rhx Xr^Y7VG6Jm+00000NkvXXu0mjfJaM&C literal 0 HcmV?d00001 diff --git a/nebula.dme b/nebula.dme index c635f6a07559..3a5a07def65d 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1427,6 +1427,7 @@ #include "code\game\objects\structures\_structure_icon.dm" #include "code\game\objects\structures\_structure_materials.dm" #include "code\game\objects\structures\ai_decoy.dm" +#include "code\game\objects\structures\armor_stand.dm" #include "code\game\objects\structures\barricade.dm" #include "code\game\objects\structures\barsign.dm" #include "code\game\objects\structures\bedsheet_bin.dm" @@ -1493,6 +1494,7 @@ #include "code\game\objects\structures\tank_dispenser.dm" #include "code\game\objects\structures\target_stake.dm" #include "code\game\objects\structures\town_bell.dm" +#include "code\game\objects\structures\training_dummies.dm" #include "code\game\objects\structures\transit_tubes.dm" #include "code\game\objects\structures\under_wardrobe.dm" #include "code\game\objects\structures\wall_frame.dm" From 91220810eef3ece20f9c484c506e070c1bed640d Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Mon, 9 Dec 2024 17:31:29 +1100 Subject: [PATCH 30/90] Cleaning up/rewriting target dummies. --- code/__defines/structures.dm | 5 +- code/datums/trading/traders/ai.dm | 44 +- code/datums/weakref.dm | 13 +- code/game/atoms_movable.dm | 3 + code/game/machinery/magnet.dm | 391 ------------------ code/game/objects/items/shooting_range.dm | 142 ------- code/game/objects/items/training_dummy.dm | 176 ++++++++ code/game/objects/objs.dm | 1 - code/game/objects/structures/__structure.dm | 7 + code/game/objects/structures/armor_stand.dm | 3 +- code/game/objects/structures/doors/_door.dm | 26 +- code/game/objects/structures/target_stake.dm | 134 ++++-- .../objects/structures/training_dummies.dm | 30 -- .../crafting/stack_recipes/recipes_grass.dm | 3 + .../crafting/stack_recipes/recipes_planks.dm | 3 + .../crafting/stack_recipes/recipes_steel.dm | 8 + icons/obj/items/training_dummies/alien.dmi | Bin 0 -> 377 bytes icons/obj/items/training_dummies/archery.dmi | Bin 0 -> 352 bytes icons/obj/items/training_dummies/damage.dmi | Bin 0 -> 767 bytes icons/obj/items/training_dummies/standard.dmi | Bin 0 -> 338 bytes icons/obj/items/training_dummies/straw.dmi | Bin 0 -> 358 bytes .../obj/items/training_dummies/syndicate.dmi | Bin 0 -> 368 bytes icons/obj/objects.dmi | Bin 127225 -> 125130 bytes icons/obj/structures/archery_butt.dmi | Bin 450 -> 0 bytes .../structures/target_stakes/archery_butt.dmi | Bin 0 -> 317 bytes .../structures/target_stakes/target_stake.dmi | Bin 0 -> 301 bytes icons/obj/structures/training_dummy.dmi | Bin 429 -> 0 bytes maps/exodus/exodus-2.dmm | 12 +- maps/ministation/ministation-1.dmm | 20 +- maps/ministation/ministation-2.dmm | 2 +- .../government/away_sites/icarus/icarus-1.dmm | 2 +- nebula.dme | 4 +- tools/map_migrations/4615_target_stakes.txt | 2 + 33 files changed, 359 insertions(+), 672 deletions(-) delete mode 100644 code/game/machinery/magnet.dm delete mode 100644 code/game/objects/items/shooting_range.dm create mode 100644 code/game/objects/items/training_dummy.dm delete mode 100644 code/game/objects/structures/training_dummies.dm create mode 100644 icons/obj/items/training_dummies/alien.dmi create mode 100644 icons/obj/items/training_dummies/archery.dmi create mode 100644 icons/obj/items/training_dummies/damage.dmi create mode 100644 icons/obj/items/training_dummies/standard.dmi create mode 100644 icons/obj/items/training_dummies/straw.dmi create mode 100644 icons/obj/items/training_dummies/syndicate.dmi delete mode 100644 icons/obj/structures/archery_butt.dmi create mode 100644 icons/obj/structures/target_stakes/archery_butt.dmi create mode 100644 icons/obj/structures/target_stakes/target_stake.dmi delete mode 100644 icons/obj/structures/training_dummy.dmi create mode 100644 tools/map_migrations/4615_target_stakes.txt diff --git a/code/__defines/structures.dm b/code/__defines/structures.dm index f91ed7aed08f..39849cecebc9 100644 --- a/code/__defines/structures.dm +++ b/code/__defines/structures.dm @@ -1 +1,4 @@ -#define STRUCTURE_FLAG_SURFACE BITFLAG(0) \ No newline at end of file +// Structure counts as a surface for the purposes of placing items on. +#define STRUCTURE_FLAG_SURFACE BITFLAG(0) +// Structure takes damage from thrown objects colliding with it. +#define STRUCTURE_FLAG_THROWN_DAMAGE BITFLAG(1) \ No newline at end of file diff --git a/code/datums/trading/traders/ai.dm b/code/datums/trading/traders/ai.dm index ca86637d32d7..5c7866db044b 100644 --- a/code/datums/trading/traders/ai.dm +++ b/code/datums/trading/traders/ai.dm @@ -98,25 +98,27 @@ They sell generic supplies and ask for generic supplies. origin = "Manifacturing Beacon" possible_trading_items = list( - /obj/structure/aicore = TRADER_THIS_TYPE, - /obj/structure/girder = TRADER_THIS_TYPE, - /obj/structure/grille = TRADER_THIS_TYPE, - /obj/structure/mopbucket = TRADER_THIS_TYPE, - /obj/structure/ore_box = TRADER_THIS_TYPE, - /obj/structure/coatrack = TRADER_THIS_TYPE, - /obj/structure/bookcase = TRADER_THIS_TYPE, - /obj/item/bee_pack = TRADER_THIS_TYPE, - /obj/item/bee_smoker = TRADER_THIS_TYPE, - /obj/item/beehive_assembly = TRADER_THIS_TYPE, - /obj/item/glass_jar = TRADER_THIS_TYPE, - /obj/item/honey_frame = TRADER_THIS_TYPE, - /obj/item/target = TRADER_ALL, - /obj/structure/tank_rack = TRADER_SUBTYPES_ONLY, - /obj/structure/filing_cabinet = TRADER_THIS_TYPE, - /obj/structure/safe = TRADER_THIS_TYPE, - /obj/structure/plushie = TRADER_SUBTYPES_ONLY, - /obj/structure/sign = TRADER_SUBTYPES_ONLY, - /obj/structure/sign/double = TRADER_BLACKLIST_ALL, - /obj/structure/sign/plaque/golden = TRADER_BLACKLIST_ALL, - /obj/structure/sign/poster = TRADER_BLACKLIST + /obj/structure/aicore = TRADER_THIS_TYPE, + /obj/structure/girder = TRADER_THIS_TYPE, + /obj/structure/grille = TRADER_THIS_TYPE, + /obj/structure/mopbucket = TRADER_THIS_TYPE, + /obj/structure/ore_box = TRADER_THIS_TYPE, + /obj/structure/coatrack = TRADER_THIS_TYPE, + /obj/structure/bookcase = TRADER_THIS_TYPE, + /obj/item/bee_pack = TRADER_THIS_TYPE, + /obj/item/bee_smoker = TRADER_THIS_TYPE, + /obj/item/beehive_assembly = TRADER_THIS_TYPE, + /obj/item/glass_jar = TRADER_THIS_TYPE, + /obj/item/honey_frame = TRADER_THIS_TYPE, + /obj/item/training_dummy = TRADER_THIS_TYPE, + /obj/item/training_dummy/syndicate = TRADER_THIS_TYPE, + /obj/item/training_dummy/alien = TRADER_THIS_TYPE, + /obj/structure/tank_rack = TRADER_SUBTYPES_ONLY, + /obj/structure/filing_cabinet = TRADER_THIS_TYPE, + /obj/structure/safe = TRADER_THIS_TYPE, + /obj/structure/plushie = TRADER_SUBTYPES_ONLY, + /obj/structure/sign = TRADER_SUBTYPES_ONLY, + /obj/structure/sign/double = TRADER_BLACKLIST_ALL, + /obj/structure/sign/plaque/golden = TRADER_BLACKLIST_ALL, + /obj/structure/sign/poster = TRADER_BLACKLIST ) \ No newline at end of file diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm index ab0ecb9c6e2e..ce8a7fa4ba63 100644 --- a/code/datums/weakref.dm +++ b/code/datums/weakref.dm @@ -14,16 +14,13 @@ return D.weakref /weakref - var/ref - var/name // Useful for input() on lists of weakrefs. - - // Handy info for debugging - var/tmp/name - var/tmp/ref_type + var/ref //- Actual datum ref. + var/name //- Useful for input() on lists of weakrefs. + var/tmp/ref_type //- Handy info for debugging /weakref/New(datum/D) - ref = "\ref[D]" - name = "[D]" + ref = "\ref[D]" + name = "[D]" ref_type = D.type /weakref/Destroy() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d2be93779daa..674a0c21f38e 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -40,6 +40,9 @@ // Marker for alpha mask update process. null == never update, TRUE == currently updating, FALSE == finished updating. var/updating_turf_alpha_mask = null + // Damage type from using or throwing this atom. + var/atom_damage_type = BRUTE + // This proc determines if the instance is preserved when the process() despawn of crypods occurs. /atom/movable/proc/preserve_in_cryopod(var/obj/machinery/cryopod/pod) return FALSE diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm deleted file mode 100644 index 87285e914033..000000000000 --- a/code/game/machinery/magnet.dm +++ /dev/null @@ -1,391 +0,0 @@ -// Magnetic attractor, creates variable magnetic fields and attraction. -// Can also be used to emit electron/proton beams to create a center of magnetism on another tile - -// tl;dr: it's magnets lol -// This was created for firing ranges, but I suppose this could have other applications - Doohl - -var/global/list/magnetic_modules = list() - -/obj/machinery/magnetic_module - - icon = 'icons/obj/objects.dmi' - icon_state = "floor_magnet-f" - name = "Electromagnetic Generator" - desc = "A device that uses powernet to create points of magnetic energy." - level = LEVEL_BELOW_PLATING - layer = ABOVE_WIRE_LAYER - anchored = TRUE - idle_power_usage = 50 - - var/freq = 1449 // radio frequency - var/electricity_level = 1 // intensity of the magnetic pull - var/magnetic_field = 1 // the range of magnetic attraction - var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something - var/turf/center // the center of magnetic attraction - var/on = 0 - var/pulling = 0 - - // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down - var/center_x = 0 - var/center_y = 0 - var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer - -/obj/machinery/magnetic_module/Initialize() - . = ..() - global.magnetic_modules += src - var/turf/T = loc - if(!T) - return INITIALIZE_HINT_QDEL - hide(!T.is_plating()) - center = T - - if(radio_controller) - radio_controller.add_object(src, freq, RADIO_MAGNETS) - - magnetic_process() - - // update the invisibility and icon -/obj/machinery/magnetic_module/hide(var/intact) - set_invisibility(intact ? 101 : 0) - update_icon() - - // update the icon_state -/obj/machinery/magnetic_module/on_update_icon() - var/state="floor_magnet" - var/onstate="" - if(!on) - onstate="0" - - if(invisibility) - icon_state = "[state][onstate]-f" // if invisible, set icon to faded version - // in case of being revealed by T-scanner - else - icon_state = "[state][onstate]" - -/obj/machinery/magnetic_module/receive_signal(datum/signal/signal) - - var/command = signal.data["command"] - var/modifier = signal.data["modifier"] - var/signal_code = signal.data["code"] - if(command && (signal_code == code)) - - Cmd(command, modifier) - - - -/obj/machinery/magnetic_module/proc/Cmd(var/command, var/modifier) - - if(command) - switch(command) - if("set-electriclevel") - if(modifier) electricity_level = modifier - if("set-magneticfield") - if(modifier) magnetic_field = modifier - - if("add-elec") - electricity_level++ - if(electricity_level > 12) - electricity_level = 12 - if("sub-elec") - electricity_level-- - if(electricity_level <= 0) - electricity_level = 1 - if("add-mag") - magnetic_field++ - if(magnetic_field > 4) - magnetic_field = 4 - if("sub-mag") - magnetic_field-- - if(magnetic_field <= 0) - magnetic_field = 1 - - if("set-x") - if(modifier) center_x = modifier - if("set-y") - if(modifier) center_y = modifier - - if("N") // NORTH - center_y++ - if("S") // SOUTH - center_y-- - if("E") // EAST - center_x++ - if("W") // WEST - center_x-- - if("C") // CENTER - center_x = 0 - center_y = 0 - if("R") // RANDOM - center_x = rand(-max_dist, max_dist) - center_y = rand(-max_dist, max_dist) - - if("set-code") - if(modifier) code = modifier - if("toggle-power") - on = !on - - if(on) - spawn() - magnetic_process() - - - -/obj/machinery/magnetic_module/Process() - if(stat & NOPOWER) - on = 0 - - // Sanity checks: - if(electricity_level <= 0) - electricity_level = 1 - if(magnetic_field <= 0) - magnetic_field = 1 - - - // Limitations: - if(abs(center_x) > max_dist) - center_x = max_dist - if(abs(center_y) > max_dist) - center_y = max_dist - if(magnetic_field > 4) - magnetic_field = 4 - if(electricity_level > 12) - electricity_level = 12 - - // Update power usage: - if(on) - update_use_power(POWER_USE_ACTIVE) - change_power_consumption(electricity_level*15, POWER_USE_ACTIVE) - else - update_use_power(POWER_USE_IDLE) - -/obj/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling - set waitfor = FALSE - if(pulling) return - while(on) - - pulling = 1 - center = locate(x+center_x, y+center_y, z) - if(center) - for(var/obj/M in orange(magnetic_field, center)) - if(!M.anchored && (M.obj_flags & OBJ_FLAG_CONDUCTIBLE)) - step_towards(M, center) - - for(var/mob/living/silicon/S in orange(magnetic_field, center)) - if(isAI(S)) continue - step_towards(S, center) - - use_power_oneoff(electricity_level * 5) - sleep(13 - electricity_level) - - pulling = 0 - -/obj/machinery/magnetic_module/Destroy() - if(radio_controller) - radio_controller.remove_object(src, freq) - global.magnetic_modules -= src - return ..() - -/obj/machinery/magnetic_controller // TODO: IMPLEMENT OR REMOVE - name = "magnetic control console" - icon = 'icons/obj/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING! - icon_state = "airlock_control_off" - density = TRUE - anchored = TRUE - idle_power_usage = 45 - var/frequency = 1449 - var/code = 0 - var/list/magnets = list() - var/title = "Magnetic Control Console" - var/autolink = 0 // if set to 1, can't probe for other magnets! - - var/pathpos = 1 // position in the path - var/path = "NULL" // text path of the magnet - var/speed = 1 // lowest = 1, highest = 10 - var/list/rpath = list() // real path of the magnet, used in iterator - - var/moving = 0 // 1 if scheduled to loop - var/looping = 0 // 1 if looping - - var/datum/radio_frequency/radio_connection - - -/obj/machinery/magnetic_controller/Initialize() - . = ..() - if(autolink) - for(var/obj/machinery/magnetic_module/M in global.magnetic_modules) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - - if(radio_controller) - radio_connection = radio_controller.add_object(src, frequency, RADIO_MAGNETS) - - if(path) // check for default path - filter_path() // renders rpath - - -/obj/machinery/magnetic_controller/Process() - if(magnets.len == 0 && autolink) - for(var/obj/machinery/magnetic_module/M in global.magnetic_modules) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - -/obj/machinery/magnetic_controller/interface_interact(user) - interact(user) - return TRUE - -/obj/machinery/magnetic_controller/interact(mob/user) - if(stat & (BROKEN|NOPOWER)) - return - user.set_machine(src) - var/dat = "[title]

" - if(!autolink) - dat += {" - Frequency: [frequency]
- Code: [code]
- Probe Generators
- "} - - if(magnets.len >= 1) - - dat += "Magnets confirmed:
" - var/i = 0 - for(var/obj/machinery/magnetic_module/M in magnets) - i++ - dat += "     < \[[i]\] ([M.on ? "On":"Off"]) | Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
" - - dat += "
Speed: - [speed] +
" - dat += "Path: {[path]}
" - dat += "Moving: [moving ? "Enabled":"Disabled"]" - - - show_browser(user, dat, "window=magnet;size=400x500") - onclose(user, "magnet") - -/obj/machinery/magnetic_controller/Topic(href, href_list) - if(..()) - return 1 - if(stat & (BROKEN|NOPOWER)) - return - usr.set_machine(src) - - if(href_list["radio-op"]) - - // Prepare signal beforehand, because this is a radio operation - var/datum/signal/signal = new - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - // Apply any necessary commands - switch(href_list["radio-op"]) - if("togglepower") - signal.data["command"] = "toggle-power" - - if("minuselec") - signal.data["command"] = "sub-elec" - if("pluselec") - signal.data["command"] = "add-elec" - - if("minusmag") - signal.data["command"] = "sub-mag" - if("plusmag") - signal.data["command"] = "add-mag" - - - // Broadcast the signal - - radio_connection.post_signal(src, signal, radio_filter = RADIO_MAGNETS) - - spawn(1) - updateUsrDialog() // pretty sure this increases responsiveness - - if(href_list["operation"]) - switch(href_list["operation"]) - if("plusspeed") - speed ++ - if(speed > 10) - speed = 10 - if("minusspeed") - speed -- - if(speed <= 0) - speed = 1 - if("setpath") - var/newpath = sanitize(input(usr, "Please define a new path!",,path) as text|null) - if(newpath && newpath != "") - moving = 0 // stop moving - path = newpath - pathpos = 1 // reset position - filter_path() // renders rpath - - if("togglemoving") - moving = !moving - if(moving) - spawn() MagnetMove() - - - updateUsrDialog() - -/obj/machinery/magnetic_controller/proc/MagnetMove() - if(looping) return - - while(moving && rpath.len >= 1) - - if(stat & (BROKEN|NOPOWER)) - break - - looping = 1 - - // Prepare the radio signal - var/datum/signal/signal = new - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list! - pathpos = 1 - - var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive - - if(!(nextmove in list("N","S","E","W","C","R"))) - // N, S, E, W are directional - // C is center - // R is random (in magnetic field's bounds) - qdel(signal) - break // break the loop if the character located is invalid - - signal.data["command"] = nextmove - - - pathpos++ // increase iterator - - // Broadcast the signal - spawn() - radio_connection.post_signal(src, signal, radio_filter = RADIO_MAGNETS) - - if(speed == 10) - sleep(1) - else - sleep(12-speed) - - looping = 0 - - -/obj/machinery/magnetic_controller/proc/filter_path() - // Generates the rpath variable using the path string, think of this as "string2list" - // Doesn't use params2list() because of the akward way it stacks entities - rpath = list() // clear rpath - var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length - - for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path - - var/nextchar = copytext(path, i, i+1) // find next character - - if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore - rpath += copytext(path, i, i+1) // else, add to list - - // there doesn't HAVE to be separators but it makes paths syntatically visible - -/obj/machinery/magnetic_controller/Destroy() - if(radio_controller) - radio_controller.remove_object(src, frequency) - return ..() \ No newline at end of file diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm deleted file mode 100644 index 18dce99c9e59..000000000000 --- a/code/game/objects/items/shooting_range.dm +++ /dev/null @@ -1,142 +0,0 @@ -// Targets, the things that actually get shot! -/obj/item/target - name = "shooting target" - desc = "A shooting target." - icon = 'icons/obj/objects.dmi' - icon_state = "target_h" - density = FALSE - material = /decl/material/solid/organic/plastic - var/obj/structure/target_stake/stake - var/hp = 1800 - var/icon/virtualIcon - var/list/bulletholes = list() - -/obj/item/target/Destroy() - . = ..() - if (stake) - stake.set_target(null) - -/obj/item/target/attackby(var/obj/item/W, var/mob/user) - if(IS_WELDER(W)) - var/obj/item/weldingtool/WT = W - if(WT.weld(0, user)) - overlays.Cut() - bulletholes.Cut() - hp = initial(hp) - to_chat(user, "You slice off [src]'s uneven chunks of aluminium and scorch marks.") - return TRUE - return ..() - -/obj/item/target/attack_hand(var/mob/user) - // taking pinned targets off! - if(!stake || !user.check_dexterity(DEXTERITY_HOLD_ITEM)) - return ..() - return stake.attack_hand(user) - -/obj/item/target/syndicate - icon_state = "target_s" - desc = "A shooting target that looks like a hostile agent." - hp = 2600 // i guess syndie targets are sturdier? -/obj/item/target/alien - icon_state = "target_q" - desc = "A shooting target with a threatening silhouette." - hp = 2350 // alium onest too kinda - -/obj/item/target/bullet_act(var/obj/item/projectile/Proj) - var/p_x = Proj.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset Proj.p_x!" - var/p_y = Proj.p_y + pick(0,0,0,0,0,-1,1) - var/decaltype = 1 // 1 - scorch, 2 - bullet - - if(istype(/obj/item/projectile/bullet, Proj)) - decaltype = 2 - - - virtualIcon = new(icon, icon_state) - - if( virtualIcon.GetPixel(p_x, p_y) ) // if the located pixel isn't blank (null) - - hp -= Proj.damage - if(hp <= 0) - visible_message(SPAN_WARNING("\The [src] breaks into tiny pieces and collapses!")) - qdel(src) - - // Create a temporary object to represent the damage - var/obj/bmark = new - bmark.pixel_x = p_x - bmark.pixel_y = p_y - bmark.icon = 'icons/effects/effects.dmi' - bmark.layer = ABOVE_OBJ_LAYER - bmark.icon_state = "scorch" - - if(decaltype == 1) - // Energy weapons are hot. they scorch! - - // offset correction - bmark.pixel_x-- - bmark.pixel_y-- - - if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/beam/practice)) - bmark.icon_state = "scorch" - bmark.set_dir(pick(NORTH,SOUTH,EAST,WEST)) // random scorch design - - - else - bmark.icon_state = "light_scorch" - else - - // Bullets are hard. They make dents! - bmark.icon_state = "dent" - - if(Proj.damage >= 10 && bulletholes.len <= 35) // maximum of 35 bullet holes - if(decaltype == 2) // bullet - if(prob(Proj.damage+30)) // bullets make holes more commonly! - new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole - else // Lasers! - if(prob(Proj.damage-10)) // lasers make holes less commonly - new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole - - // draw bullet holes - for(var/datum/bullethole/B in bulletholes) - - virtualIcon.DrawBox(null, B.b1x1, B.b1y, B.b1x2, B.b1y) // horizontal line, left to right - virtualIcon.DrawBox(null, B.b2x, B.b2y1, B.b2x, B.b2y2) // vertical line, top to bottom - - overlays += bmark // add the decal - - icon = virtualIcon // apply bulletholes over decals - - return - - return PROJECTILE_CONTINUE // the bullet/projectile goes through the target! - - -// Small memory holder entity for transparent bullet holes -/datum/bullethole - // First box - var/b1x1 = 0 - var/b1x2 = 0 - var/b1y = 0 - - // Second box - var/b2x = 0 - var/b2y1 = 0 - var/b2y2 = 0 - -/datum/bullethole/New(var/obj/item/target/Target, var/pixel_x = 0, var/pixel_y = 0) - if(!Target) return - - // Randomize the first box - b1x1 = pixel_x - pick(1,1,1,1,2,2,3,3,4) - b1x2 = pixel_x + pick(1,1,1,1,2,2,3,3,4) - b1y = pixel_y - if(prob(35)) - b1y += rand(-4,4) - - // Randomize the second box - b2x = pixel_x - if(prob(35)) - b2x += rand(-4,4) - b2y1 = pixel_y + pick(1,1,1,1,2,2,3,3,4) - b2y2 = pixel_y - pick(1,1,1,1,2,2,3,3,4) - - Target.bulletholes.Add(src) \ No newline at end of file diff --git a/code/game/objects/items/training_dummy.dm b/code/game/objects/items/training_dummy.dm new file mode 100644 index 000000000000..d870699ddd1d --- /dev/null +++ b/code/game/objects/items/training_dummy.dm @@ -0,0 +1,176 @@ +// Used in conjunction with /obj/structure/target_stake. +/obj/item/training_dummy + name = "shooting target" + desc = "A shooting target." + icon = 'icons/obj/items/training_dummies/standard.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/aluminium + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + max_health = 1800 + appearance_flags = KEEP_TOGETHER // Needed for BLEND_INSET_OVERLAY on the decals. + + // Burn/bullet hole/dent decals to apply to our icon. + var/list/decals + var/const/MAX_DECALS = 250 + + // Very crude bounding box; we do pixel-precise checking within these ranges. + var/decal_min_x = 7 + var/decal_min_y = 3 + var/decal_range_x = 17 + var/decal_range_y = 25 + +/obj/item/training_dummy/proc/get_damage_decal_icon() + return 'icons/obj/items/training_dummies/damage.dmi' + +// Can't repair cloth, straw or plastic targets currently. +/obj/item/training_dummy/proc/can_repair_with(obj/item/thing) + return IS_WELDER(thing) && istype(material, /decl/material/solid/metal) + +/obj/item/training_dummy/proc/perform_repair(mob/user, obj/item/tool) + var/obj/item/weldingtool/welder = tool + if(!istype(welder) || !welder.isOn()) + to_chat(user, SPAN_WARNING("Turn \the [welder] on first.")) + return FALSE + return tool.do_tool_interaction(TOOL_WELDER, user, src, 2 SECONDS) + +/obj/item/training_dummy/proc/repair_target_dummy(obj/item/used_item, mob/user) + + if(!can_repair_with(used_item)) + return FALSE + + var/max_health = get_max_health() + if(current_health >= max_health) + to_chat(user, SPAN_NOTICE("\The [src] doesn't need repairs.")) + return TRUE + + if(perform_repair(user, used_item)) + current_health += rand(100,200) // They have a lot of HP. + if(LAZYLEN(decals)) + if(current_health >= get_max_health()) + current_health = get_max_health() + LAZYCLEARLIST(decals) + else + var/remove_decal = pick(decals) + LAZYREMOVE(decals, remove_decal) + update_icon() + return TRUE + + return FALSE + +/obj/item/training_dummy/attackby(obj/item/used_item, mob/user) + if(repair_target_dummy(used_item, user)) + return TRUE + return ..() + +/obj/item/training_dummy/take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + + var/old_health = current_health + . = ..() + if(QDELETED(src) || old_health == current_health) + return + + if(damage <= 0) + update_icon() + return + + if(LAZYLEN(decals) >= MAX_DECALS) + return + + var/decal_icon = get_damage_decal_icon() + if(!decal_icon) + return + + var/decal_state + if(damage_type == BURN) + if(damage < 10) + decal_state = "light_scorch" + else + decal_state = "scorch" + else if(damage_type == BRUTE) + if(damage < 10) + decal_state = "dent" + else + decal_state = "bhole" + else + return + + var/image/new_decal = image(decal_icon, decal_state) + new_decal.blend_mode = BLEND_INSET_OVERLAY + new_decal = apply_decal_offsets(new_decal) + if(new_decal) + LAZYADD(decals, new_decal) + update_icon() + +/obj/item/training_dummy/proc/apply_decal_offsets(image/decal) + + // Static list cache for this broke immediately, so seems like we need a fresh icon every time. + // At least it isn't being assigned anywhere so shouldn't cause network overhead. + var/icon/check_icon = icon(icon, icon_state) + if(!check_icon) + return + + var/use_pixel_x + var/use_pixel_y + var/sanity = 100 + while(sanity) + sanity-- + use_pixel_x = decal_min_x + rand(decal_range_x) + use_pixel_y = decal_min_y + rand(decal_range_y) + var/check_pixel = check_icon.GetPixel(use_pixel_x, use_pixel_y) + // Pixel has a colour and no alpha component; we are good. + if(istext(check_pixel) && length(check_pixel) == 7) + break + + if(!sanity || !isnum(use_pixel_x) || use_pixel_x < 0 || !isnum(use_pixel_y) || use_pixel_y < 0) + return + + decal.pixel_x = use_pixel_x + decal.pixel_y = use_pixel_y + return decal + +/obj/item/training_dummy/on_update_icon() + . = ..() + if(LAZYLEN(decals)) + if(current_health >= get_max_health()) + LAZYCLEARLIST(decals) + else + set_overlays(decals.Copy()) + if(istype(loc, /obj/structure/target_stake)) + compile_overlays() // We need to update our loc immediately. + loc.update_icon() + +/obj/item/training_dummy/syndicate + icon = 'icons/obj/items/training_dummies/syndicate.dmi' + desc = "A shooting target that looks like a hostile agent." + decal_min_x = 7 + decal_min_y = 2 + decal_range_x = 18 + decal_range_y = 30 + +/obj/item/training_dummy/alien + icon = 'icons/obj/items/training_dummies/alien.dmi' + desc = "A shooting target with a threatening silhouette." + decal_min_x = 7 + decal_min_y = 2 + decal_range_x = 18 + decal_range_y = 30 + +/obj/item/training_dummy/straw + name = "training dummy" + icon = 'icons/obj/items/training_dummies/straw.dmi' + desc = "A roughly humanoid shape used for melee practice." + material = /decl/material/solid/organic/plantmatter/grass/dry + material_alteration = MAT_FLAG_ALTERATION_ALL + decal_min_x = 8 + decal_min_y = 12 + decal_range_x = 16 + decal_range_y = 17 + +/obj/item/training_dummy/straw/archery + name = "archery butt" + icon = 'icons/obj/items/training_dummies/archery.dmi' + desc = "A thick circular mat used for archery practice." + decal_min_x = 7 + decal_min_y = 5 + decal_range_x = 19 + decal_range_y = 21 diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index b9966cf27e9d..f1838fcfa065 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -17,7 +17,6 @@ var/sharp = 0 // whether this object cuts var/edge = 0 // whether this object is more likely to dismember var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! - var/atom_damage_type = BRUTE var/armor_penetration = 0 var/anchor_fall = FALSE var/holographic = 0 //if the obj is a holographic object spawned by the holodeck diff --git a/code/game/objects/structures/__structure.dm b/code/game/objects/structures/__structure.dm index b1764d52754a..29c20b4b6d9a 100644 --- a/code/game/objects/structures/__structure.dm +++ b/code/game/objects/structures/__structure.dm @@ -322,3 +322,10 @@ Note: This proc can be overwritten to allow for different types of auto-alignmen W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] W.pixel_z = 0 + +/obj/structure/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) + . = ..() + if(. && (structure_flags & STRUCTURE_FLAG_THROWN_DAMAGE)) + visible_message(SPAN_DANGER("\The [src] was hit by \the [AM].")) + playsound(src.loc, hitsound, 100, 1) + take_damage(AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR), AM.atom_damage_type) diff --git a/code/game/objects/structures/armor_stand.dm b/code/game/objects/structures/armor_stand.dm index 96b52bc8266a..7dabc4c24f02 100644 --- a/code/game/objects/structures/armor_stand.dm +++ b/code/game/objects/structures/armor_stand.dm @@ -34,8 +34,9 @@ . = ..() if(. || !LAZYLEN(gear_to_slot)) return + var/weakref/removed_item_ref if(LAZYLEN(gear_to_slot) == 1) - var/weakref/removed_item_ref = gear_to_slot[1] + removed_item_ref = gear_to_slot[1] else removed_item_ref = input(user, "Which piece of equipment would you like to remove?", "Armor Stand") as null|anything in gear_to_slot if(!CanPhysicallyInteract(user) || QDELETED(src) || QDELETED(user) || !(removed_item_ref in gear_to_slot)) diff --git a/code/game/objects/structures/doors/_door.dm b/code/game/objects/structures/doors/_door.dm index 9079662e2438..745ad4bea2d6 100644 --- a/code/game/objects/structures/doors/_door.dm +++ b/code/game/objects/structures/doors/_door.dm @@ -1,18 +1,18 @@ /obj/structure/door - name = "door" - icon = 'icons/obj/doors/material_doors.dmi' - icon_state = "metal" - hitsound = 'sound/weapons/genhit.ogg' - material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR - max_health = 50 - density = TRUE - anchored = TRUE - opacity = TRUE - - var/has_window = FALSE - var/changing_state = FALSE - var/icon_base + name = "door" + icon = 'icons/obj/doors/material_doors.dmi' + icon_state = "metal" + hitsound = 'sound/weapons/genhit.ogg' + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + max_health = 50 + density = TRUE + anchored = TRUE + opacity = TRUE + structure_flags = STRUCTURE_FLAG_THROWN_DAMAGE + var/has_window = FALSE + var/changing_state = FALSE var/door_sound_volume = 25 + var/icon_base /obj/structure/door/Initialize() ..() diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index d1e4d36df79d..0dc8afefce6a 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -1,49 +1,97 @@ -// Target stakes for the firing range. +// TODO: skill check on melee/ranged hit to show bullseye/heart shot/etc /obj/structure/target_stake - name = "target stake" - desc = "A thin platform with negatively-magnetized wheels." - icon = 'icons/obj/objects.dmi' - icon_state = "target_stake" - density = TRUE - obj_flags = OBJ_FLAG_CONDUCTIBLE - var/obj/item/target/pinned_target - -/obj/structure/target_stake/attackby(var/obj/item/W, var/mob/user) - if (!pinned_target && istype(W, /obj/item/target) && user.try_unequip(W, get_turf(src))) - to_chat(user, "You slide [W] into the stake.") - set_target(W) + name = "target stake" + desc = "A simple stand used to prop up a target for practice." + icon = 'icons/obj/structures/target_stakes/target_stake.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + structure_flags = STRUCTURE_FLAG_THROWN_DAMAGE + var/obj/item/training_dummy/dummy + +/obj/structure/target_stake/Destroy() + dummy = null + . = ..() + +/obj/structure/target_stake/attackby(obj/item/used_item, mob/user) + if(dummy?.repair_target_dummy(used_item, user)) return TRUE return ..() -/obj/structure/target_stake/attack_hand(var/mob/user) - if (!pinned_target || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) - return ..() - to_chat(user, SPAN_NOTICE("You take \the [pinned_target] off the stake.")) - user.put_in_hands(pinned_target) - set_target(null) - return TRUE - -/obj/structure/target_stake/proc/set_target(var/obj/item/target/T) - if (T) - set_density(0) - T.set_density(1) - T.pixel_x = 0 - T.pixel_y = 0 - T.layer = ABOVE_OBJ_LAYER - events_repository.register(/decl/observ/moved, T, src, TYPE_PROC_REF(/atom/movable, move_to_turf)) - events_repository.register(/decl/observ/moved, src, T, TYPE_PROC_REF(/atom/movable, move_to_turf)) - T.stake = src - pinned_target = T - else - set_density(1) - if(pinned_target) - pinned_target.set_density(0) - pinned_target.layer = OBJ_LAYER - events_repository.unregister(/decl/observ/moved, pinned_target, src) - events_repository.unregister(/decl/observ/moved, src, pinned_target) - pinned_target.stake = null - pinned_target = null +/obj/structure/target_stake/take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + if(dummy) + . = dummy.take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + if(QDELETED(dummy)) + dummy = null + update_icon() + return + return ..() -/obj/structure/target_stake/Destroy() +/obj/structure/target_stake/proc/can_hold_dummy(mob/user, obj/item/training_dummy/new_dummy) + return istype(new_dummy) && !istype(new_dummy, /obj/item/training_dummy/straw/archery) + +/obj/structure/target_stake/attack_hand(mob/user) + if(dummy) + dummy.dropInto(loc) + user.put_in_hands(dummy) + dummy = null + update_icon() + return TRUE + return ..() + +/obj/structure/target_stake/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/training_dummy) && can_hold_dummy(user, used_item)) + if(dummy) + to_chat(user, SPAN_WARNING("\The [src] is already holding \the [dummy].")) + else if(user.try_unequip(used_item, src)) + dummy = used_item + visible_message(SPAN_NOTICE("\The [user] places \the [dummy] onto \the [src].")) + update_icon() + return TRUE + return ..() + +/obj/structure/target_stake/Initialize(ml, _mat, _reinf_mat) + if(ispath(dummy)) + dummy = new dummy(src) + . = ..() + update_icon() + +/obj/structure/target_stake/on_update_icon() . = ..() - set_target(null) \ No newline at end of file + if(dummy) + // WTB way to stop vis_contents inheriting atom color + var/image/dummy_overlay = new /image + dummy_overlay.appearance = dummy + dummy_overlay.pixel_x = 0 + dummy_overlay.pixel_y = 0 + dummy_overlay.pixel_z = 0 + dummy_overlay.pixel_w = 0 + dummy_overlay.plane = FLOAT_PLANE + dummy_overlay.layer = FLOAT_LAYER + dummy_overlay.appearance_flags |= RESET_COLOR + add_overlay(dummy_overlay) + +// Subtypes below. +/obj/structure/target_stake/steel + material = /decl/material/solid/metal/steel + +/obj/structure/target_stake/archery + name = "archery butt" + desc = "A heavy circular target used for practicing archery." + icon = 'icons/obj/structures/target_stakes/archery_butt.dmi' + +/obj/structure/target_stake/archery/can_hold_dummy(mob/user, obj/item/training_dummy/new_dummy) + return istype(new_dummy, /obj/item/training_dummy/straw/archery) + +// Subtypes with/for dummies. +/obj/structure/target_stake/mapped + dummy = /obj/item/training_dummy/straw + +/obj/structure/target_stake/steel/mapped/Initialize() + dummy = pick(/obj/item/training_dummy, /obj/item/training_dummy/alien, /obj/item/training_dummy/syndicate) + return ..() + +/obj/structure/target_stake/archery/mapped + dummy = /obj/item/training_dummy/straw/archery diff --git a/code/game/objects/structures/training_dummies.dm b/code/game/objects/structures/training_dummies.dm deleted file mode 100644 index ed0e7fc0d94f..000000000000 --- a/code/game/objects/structures/training_dummies.dm +++ /dev/null @@ -1,30 +0,0 @@ -// TODO: skill check on melee/ranged hit to show bullseye/heart shot/etc -// TODO: craft the base frame, add cloth/dry grass to replace dummy, remove dummy on damage. -// TODO: add a modern-style version, merge with and replace the magnet dummies? - -/obj/structure/training_dummy - name = "training dummy" - desc = "A simple stand used to prop up a training dummy for practice." - icon = 'icons/obj/structures/training_dummy.dmi' - icon_state = ICON_STATE_WORLD - anchored = TRUE - density = TRUE - material = /decl/material/solid/organic/wood/oak - material_alteration = MAT_FLAG_ALTERATION_ALL - var/decl/material/dummy_mat = /decl/material/solid/organic/plantmatter/grass/dry - -/obj/structure/training_dummy/Initialize(ml, _mat, _reinf_mat) - if(ispath(dummy_mat)) - dummy_mat = GET_DECL(dummy_mat) - . = ..() - update_icon() - -/obj/structure/training_dummy/on_update_icon() - . = ..() - if(dummy_mat) - add_overlay(overlay_image(icon, "[icon_state]-dummy", dummy_mat.color, RESET_COLOR)) - -/obj/structure/training_dummy/archery - name = "archery butt" - desc = "A heavy circular target used for practicing archery." - icon = 'icons/obj/structures/archery_butt.dmi' diff --git a/code/modules/crafting/stack_recipes/recipes_grass.dm b/code/modules/crafting/stack_recipes/recipes_grass.dm index 398b3ec168b0..badba30d8a47 100644 --- a/code/modules/crafting/stack_recipes/recipes_grass.dm +++ b/code/modules/crafting/stack_recipes/recipes_grass.dm @@ -41,3 +41,6 @@ /obj/item/stack/material/bundle, /obj/item/stack/material/thread ) + +/decl/stack_recipe/woven/dummy + result_type = /obj/item/training_dummy/straw diff --git a/code/modules/crafting/stack_recipes/recipes_planks.dm b/code/modules/crafting/stack_recipes/recipes_planks.dm index de760228f25b..4d72d242bc60 100644 --- a/code/modules/crafting/stack_recipes/recipes_planks.dm +++ b/code/modules/crafting/stack_recipes/recipes_planks.dm @@ -231,3 +231,6 @@ result_type = /obj/structure/armor_stand difficulty = MAT_VALUE_NORMAL_DIY +/decl/stack_recipe/planks/furniture/target_stake + result_type = /obj/structure/target_stake + difficulty = MAT_VALUE_NORMAL_DIY diff --git a/code/modules/crafting/stack_recipes/recipes_steel.dm b/code/modules/crafting/stack_recipes/recipes_steel.dm index 8f15300c3677..9befbe3d3f12 100644 --- a/code/modules/crafting/stack_recipes/recipes_steel.dm +++ b/code/modules/crafting/stack_recipes/recipes_steel.dm @@ -108,3 +108,11 @@ /decl/stack_recipe/steel/furniture/drill_brace result_type = /obj/structure/drill_brace + +/decl/stack_recipe/steel/furniture/armor_stand + result_type = /obj/structure/armor_stand + difficulty = MAT_VALUE_NORMAL_DIY + +/decl/stack_recipe/steel/furniture/target_stake + result_type = /obj/structure/target_stake + difficulty = MAT_VALUE_NORMAL_DIY diff --git a/icons/obj/items/training_dummies/alien.dmi b/icons/obj/items/training_dummies/alien.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a08ae3ce7fa2246caf256a8a3a130f904bc5776b GIT binary patch literal 377 zcmV-<0fzpGP)V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zsXV_ZCq;>iGbOXA7|1u|;!G<_%uR)`l@(n5T)@Tx06PL2GXQEU^ zks6blaB;H9G~p2BV()*Q?o(k2tfB)fJy{|*(+Ew z=Ol@#bVv05zK`LRDxV&K0SMnF9t)6(Jf2mLi(?Z=igjdVlEgi`T(`oy6{(jKQU zm{q}`ZJ`993-~|ak^@J`wM_-?lrq#{9!kI5a^YY90SJeF1-_nkA7uj`rLF1T#=q+Y X31t_O{b;8400000NkvXXu0mjfMX8tX literal 0 HcmV?d00001 diff --git a/icons/obj/items/training_dummies/archery.dmi b/icons/obj/items/training_dummies/archery.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b3e58a34a26c6675d645a6d2b1942223b6170483 GIT binary patch literal 352 zcmV-m0iXVfP)V=-0C=2J zR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5 zsXV_ZCq;>iGbOXA7|1u|;!G<_%uR)`l@(n5T)@Tx06PL2GXQEUnR?nbEn}|$4TO}B z!$><&Hh_)#gjgupbLPPk3b$tiFb{<=a)ntam~%;eVt=9H21Kg5&bePe#Qi&%M?RLW y`EBW-9oFsU>D_Iby8?RKA0rFJ9O^CP-|7UHa2PGP@3?FL0000 zT2F1{I%FWg_Q3MHi2Yl=u-$1Br%YN{%ewOHP3|jflbqx4A9NHr`muTav6Zj?a+p`_ zD%La1-H=gUZPYIjl2B+fL9nm;1-GkuYD7q?U*)tepN^de7O57Wz1+*KGpjuMu~OB) zGiSfcR9xQwQYrIk{AxFIs~ra~3vW`jl@R{0JcogS$-vXaF{EP7+uMqLN{%A!AFt09 z@|d(%Z1FV{&NN#|XX`UNb}}^eJYq<_ew8tR#Za7KE8F!fy$x+FXI6>EGFdK~9J_IY z`-=W0|LvP=^#3ls{48)wZuS;|LmJ0^c)oYkkW)M`Vd@tq=j99rtPPqBK8y)m48aUD zm=1_AEF)5ALpz6nlf*^qfUcW4-yY40{$9Jk)9~Mky$&1?HJ5JresBLViTdaB_D8L? z+w=YSluJq5Z`(ef7jO0a+VaaUXBX$qt==&+(krumZ`}T6Q@-uI-y(46M0Ne17`^;^ zzmw11EKj}vefGk#-2YvB86*9#B=^kMT;b@qA7Z$>||vu`n2xhm^s>D}s{k8`T+*6z7~eD+Q0jSiuq-tYfT zU$tu5kw2e**33BnoIPpV%$dfUb7QZU?e70Suex#F>w9N&Du17SSMcNe8}-SYhV%Z{ zJ6tw-Q8UZ#5Sn$whcis$(wUK$P3m8`wyiSQ{GWe+?ro*-OwIfI_Su&_df0t4eo0Dm Vn%s2<2Vjb3@O1TaS?83{1OOfwMh5@@ literal 0 HcmV?d00001 diff --git a/icons/obj/items/training_dummies/standard.dmi b/icons/obj/items/training_dummies/standard.dmi new file mode 100644 index 0000000000000000000000000000000000000000..d4b367b4db8429c70e6ab26cf917ad1119ef2bd3 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*8>L*XliOMUAiZ8+u;BJ00DGTPE!Ct=GbNc003!vR9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*+P6OZW^*7W$JrO+8 z02Z&z8Gx|>aAbz5zJg(_v@S8f{yNZoFik|w(lPVgWFQhX**V5sdCo24*CP9tZR*1E z2JlfuP-KG5x}v4R>c{h)Um;?L*Br!8jV_;}#Xy{>J z*yy7Y0F+`Z3GxeOaCmkj4amu?3W+FjNi9w;$}A|!%+F(BsF)KRR!~&>{Y!Ac$FEPc zymhtCojD)8A=Kca@qggEfts*E$mTBV83ZXWgmy8b_k8I%4-R-*e zDTCQ@w#L;=m-P*=?)2VoJ4ert(lqT>y3t+E%=Qm@BQE{-^DL8v)Z&>59mq; MPgg&ebxsLQ0P$6bP5=M^ literal 0 HcmV?d00001 diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 4705a37d998f32d2ff382b7d0b67b31e0a5e0ff7..ec7ad98c685e4799fb99ef98a614d4f843dd5743 100644 GIT binary patch delta 51252 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 diff --git a/icons/obj/structures/archery_butt.dmi b/icons/obj/structures/archery_butt.dmi deleted file mode 100644 index 45bbb36c105fbcec1583a324f7fb80fb68061e3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 450 zcmV;z0X_bSP)p8x;fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@**gRq3Xb=H^!7Qmd@s>gNJ>0stc0CsMiP z?$Q7N0N+VOK~y-6)sjgL!ypVrLx+6~K0t{$Kv6DGqjcXzx&KuP!47H~s!Cb)Z!F=b z?*Vt+p9uOA75ok;kjJdyQsQA)@@5=;C8k@6r)kN108@z|fa3?_^)y-I1t0;CAH22z z+L{F*n1u`|wAn$E)SxiTats_bW(TrY0q$|ulL4@l9Z<{I>mIzd*+Fa508$EEfP^&w z#N?jp5VZkBqJ6;k66+?RZn6xnWX!$^@S+$Pf~?x{LCC7Pg&1VjE^?RrSxrEd?`|JV sB9cQrxldqqv>U*?_5<-z;yG?4Urd%W0d9rr*#H0l07*qoM6N<$g8g&BtN;K2 diff --git a/icons/obj/structures/target_stakes/archery_butt.dmi b/icons/obj/structures/target_stakes/archery_butt.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b2e7253cf4bd7a2578f501365c7f8b67f559c538 GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*8>L*96ETit7~3rQkkcF z%vA2mBS0y}k|4ie28U-i(tw=Is*s2hm(=3qqRfJl%=|nChKf1CVFg8{-@gPGeEj-E z%Uf6L+?n&i8$t~(8b5fXbKXbuBtub8?+y#&Amhu%UJ7#_O*%3uL?L*k&3+Aa*UoNZ z)y*p;PMAM=e0iKqJOm1EY3wXp03K^Nx6X&E| zaCQ)Q807ed$;-`PxwbRYk)s^XN>at&FwJ0e;bjzO=Qzu>iG^W7hj@{@Nu@2&N(N6? KKbLh*2~7aM`)@h` literal 0 HcmV?d00001 diff --git a/icons/obj/structures/target_stakes/target_stake.dmi b/icons/obj/structures/target_stakes/target_stake.dmi new file mode 100644 index 0000000000000000000000000000000000000000..7423233493f0af48c8b52886f7bb4c8cee2a3547 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*8>L*bal-;bns+qQkkcF z%r7qCvp^}vk|4ie28U-i(tw=Is*s2hm(=3qqRfJl%=|nChKf1CVFg8{-@gPGeEj-E z%Uf6L+?n&i8$t~(8b5fXbKXbuBtub8?+y#&Amhu%UJ7#_O*%3uL?L*k&3+Aa*UoNZ z)y*p;PMAM=FxJ6? z!S}!ghMCVbG&FQHG+r=>8Z8+u;BJ00DGTPE!Ct=GbNc0047(R9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@**gRq3Xb=H^!7Qmd@s>gNJ>0stc0CsMiP z?$Q7N0Ln>3K~y-6#gj1(gD?z5i4^wIngbLr&|b9Rhx Xr^Y7VG6Jm+00000NkvXXu0mjfJaM&C diff --git a/maps/exodus/exodus-2.dmm b/maps/exodus/exodus-2.dmm index ae068ece7af6..f94748891179 100644 --- a/maps/exodus/exodus-2.dmm +++ b/maps/exodus/exodus-2.dmm @@ -200,7 +200,7 @@ /turf/floor/tiled/steel_grid, /area/exodus/security/range) "aaD" = ( -/obj/structure/target_stake, +/obj/structure/target_stake/steel, /obj/effect/floor_decal/industrial/hatch/yellow, /turf/floor/tiled/steel_grid, /area/exodus/security/range) @@ -344,11 +344,11 @@ /area/exodus/security/range) "aaV" = ( /obj/structure/closet/crate, -/obj/item/target, -/obj/item/target, -/obj/item/target, -/obj/item/target, -/obj/item/target, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, /obj/machinery/light, /turf/floor/tiled/steel_grid, /area/exodus/security/range) diff --git a/maps/ministation/ministation-1.dmm b/maps/ministation/ministation-1.dmm index 9aac14f4417d..23ce124bb76e 100644 --- a/maps/ministation/ministation-1.dmm +++ b/maps/ministation/ministation-1.dmm @@ -7240,7 +7240,7 @@ /turf/floor/tiled/white, /area/ministation/medical) "Ft" = ( -/obj/structure/target_stake, +/obj/structure/target_stake/steel, /turf/floor/tiled, /area/ministation/security) "Fy" = ( @@ -8356,18 +8356,18 @@ /area/ministation/medical) "Me" = ( /obj/structure/rack, -/obj/item/target, -/obj/item/target/alien, -/obj/item/target/syndicate, +/obj/item/training_dummy, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/syndicate, /obj/effect/floor_decal/industrial/warning{ dir = 8 }, -/obj/item/target/syndicate, -/obj/item/target/syndicate, -/obj/item/target/syndicate, -/obj/item/target/alien, -/obj/item/target/alien, -/obj/item/target/alien, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/alien, /turf/floor/tiled, /area/ministation/security) "Mp" = ( diff --git a/maps/ministation/ministation-2.dmm b/maps/ministation/ministation-2.dmm index f70c0d369261..feaf95611ccf 100644 --- a/maps/ministation/ministation-2.dmm +++ b/maps/ministation/ministation-2.dmm @@ -3345,7 +3345,7 @@ /turf/floor/plating, /area/ministation/maint/l3nw) "qj" = ( -/obj/structure/target_stake, +/obj/structure/target_stake/steel, /obj/item/toy/figure/clown, /turf/floor/reinforced/airless, /area/space) diff --git a/mods/content/government/away_sites/icarus/icarus-1.dmm b/mods/content/government/away_sites/icarus/icarus-1.dmm index 8779b3ce78de..1be37c41159b 100644 --- a/mods/content/government/away_sites/icarus/icarus-1.dmm +++ b/mods/content/government/away_sites/icarus/icarus-1.dmm @@ -1931,7 +1931,7 @@ /turf/floor/plating, /area/icarus/vessel) "go" = ( -/obj/structure/target_stake, +/obj/structure/target_stake/steel, /turf/floor/plating, /area/icarus/vessel) "gp" = ( diff --git a/nebula.dme b/nebula.dme index 3a5a07def65d..fd1d6d087a12 100644 --- a/nebula.dme +++ b/nebula.dme @@ -842,7 +842,6 @@ #include "code\game\machinery\igniter.dm" #include "code\game\machinery\jukebox.dm" #include "code\game\machinery\lightswitch.dm" -#include "code\game\machinery\magnet.dm" #include "code\game\machinery\mass_driver.dm" #include "code\game\machinery\mech_recharger.dm" #include "code\game\machinery\message_server.dm" @@ -1109,10 +1108,10 @@ #include "code\game\objects\items\rescuebag.dm" #include "code\game\objects\items\rock.dm" #include "code\game\objects\items\saddle.dm" -#include "code\game\objects\items\shooting_range.dm" #include "code\game\objects\items\silencer.dm" #include "code\game\objects\items\spirit_board.dm" #include "code\game\objects\items\toys.dm" +#include "code\game\objects\items\training_dummy.dm" #include "code\game\objects\items\trash.dm" #include "code\game\objects\items\umbrella.dm" #include "code\game\objects\items\waterskin.dm" @@ -1494,7 +1493,6 @@ #include "code\game\objects\structures\tank_dispenser.dm" #include "code\game\objects\structures\target_stake.dm" #include "code\game\objects\structures\town_bell.dm" -#include "code\game\objects\structures\training_dummies.dm" #include "code\game\objects\structures\transit_tubes.dm" #include "code\game\objects\structures\under_wardrobe.dm" #include "code\game\objects\structures\wall_frame.dm" diff --git a/tools/map_migrations/4615_target_stakes.txt b/tools/map_migrations/4615_target_stakes.txt new file mode 100644 index 000000000000..8e4677a219f1 --- /dev/null +++ b/tools/map_migrations/4615_target_stakes.txt @@ -0,0 +1,2 @@ +/obj/item/target/@SUBTYPES : /obj/item/target_dummy/@SUBTYPES{@OLD} +/obj/structure/target_stake/@SUBTYPES : /obj/structure/target_stake/steel/@SUBTYPES{@OLD} From 6cbf766e752b1609ba70707683ad7152fce39e56 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Mon, 9 Dec 2024 21:35:14 +1100 Subject: [PATCH 31/90] Removed slavers' den. --- maps/away/slavers/icons/abolitionist.dmi | Bin 1391 -> 0 bytes maps/away/slavers/icons/areas.dmi | Bin 1878 -> 0 bytes maps/away/slavers/icons/uniform.dmi | Bin 781 -> 0 bytes maps/away/slavers/slavers_base.dm | 185 - maps/away/slavers/slavers_base.dmm | 44306 ---------------- maps/away/slavers/slavers_base_areas.dm | 42 - maps/away_sites_testing/away_sites_testing.dm | 1 - maps/exodus/exodus.dm | 1 - maps/ministation/ministation.dm | 1 - maps/tradeship/tradeship.dm | 1 - 10 files changed, 44537 deletions(-) delete mode 100644 maps/away/slavers/icons/abolitionist.dmi delete mode 100644 maps/away/slavers/icons/areas.dmi delete mode 100644 maps/away/slavers/icons/uniform.dmi delete mode 100644 maps/away/slavers/slavers_base.dm delete mode 100644 maps/away/slavers/slavers_base.dmm delete mode 100644 maps/away/slavers/slavers_base_areas.dm diff --git a/maps/away/slavers/icons/abolitionist.dmi b/maps/away/slavers/icons/abolitionist.dmi deleted file mode 100644 index b56da3bc706557a762e6dc2a9ce92292db970f64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1391 zcmV-#1(5oQP)l}Nj5e%4Gj%CI5-_09fN^^Qc_YR zBO@Ff99&#nz`(%&05ktHGu|Q)ZvX%Q0d!JMQvg8b*k%9#0Caj(Sad{Xb7OL8aCB*J zZU6vyoKseCa&`CgQ*iP1C^0t`#5P1zrJItPh@{jIMX9oatDg(l1pw~y zCb#l?ci#X21MEpeK~z|U-Ir@uqdF9Z6NxDSL!3fFo2o5CXXYHOf}M^o&;S2nXD85l zAz_9p^TEAPT)gl;*)f+Lgg#Z^CcOGd6J9;A(c|B|5cmiLqLuz>j7lL7jISdt_R?(S$h2y*Zl1cA-KlK?`~G!;UmeCpA8YJ+p10peNK z=P&Wp1eR_BmsmEJkDzdtWrF(Xxs(+Asg$|P!RQ#zFd*`|+h4&lkY(CUn9pe{sl@ZS zmpQ(wUAd`R9fHZ^9e| zRSL117Fu^QxCVd55WgYBTpY3Pbbr7Fxuf~`(W8Ej_+5qnA@(Bzpf(l-4a0Z{OdkC>7whXYs#0Q=lMe!_S{ zm|*JZKdCTieDo{{sNM x=Zp8pPjg1tj_03MyOXpY5%6fs`;YCS{{e43X;9b=+i3s*002ovPDHLkV1hK7ac}?t diff --git a/maps/away/slavers/icons/areas.dmi b/maps/away/slavers/icons/areas.dmi deleted file mode 100644 index cc911c14cd2cad34a0f950ba2da383087477268c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1878 zcmah~X;hQf7QJ5>0?1IN7BD=ZAmEY$B0fHWmw+;bA=;=EWp0p3hA;()KoDt^L1Y0X ztxX^bJVdFeg))f-Xc?pgfdUn%2?PmafFffU-e;|=>-~A}$G&IXeeOL!&e?b0tTO~> z1vxD_0DuDC#es;#bOZr1(#SeQrQ(rLPCe%p?{F!O6dOj44~vchAc=Xi&ql7@Tt0o` z74|Ea^?{MO3IjEzZf%F^QE6OuWH?oOS+v8Amxbn7lLmB8jxVb}ha zFhw;VE)o7?xGuFy;o#K_y}PF)^V>Fw_O1AA=T;Z-&Ur(I*M;+8^Vkc+Kl^M>Iq5Cq zuj|F9tl}+p3e}F~lr)lZXyad-6#GYHCbI%A*6sjC(3RMmP76l>kdDMV*q=*cF0wu^ zD1+tcy`H=-W?-r+tU8|guTv?8>w#_#!!8=6YayQ7_kC0!c(~LB&DIyVD~YG}DcYKh zlEg$)Zt24fo?vuskCxEV+|San)f{PP74%KD&({QRzUD11@pv`uG5hdh4Ud+)y0Nju z_(DXJ}N=8Us@Knzv!iAH;lmgZ3$u#VH9R(qt_fsVg6*9Yp__ z(2=sE(g8=CmnYF?|lsZyFE=Dzo}zCV6*5~F--K*ZaaJU1x4r%lj|$<$gP ziW<;Gl2EFj19vvMB3cx>VTqSzSLyUUz9-o0^`*%kt|%R%V2nfNPrs02l=MZ^y1S%8 zSyRc~N0+l#1BLZ6YMv6InQ=ZWCrf6gz;pxNo~^EF6*nqvX+)4h>bY_ z-gp7yPL$n=kHL$_;7p!WdaMa3`a2~InGySCuBOdV_b+AnF5wa>>6gG8109(ak$C0) zjP=ewI7W@WlDtIvoMWBaxm&rry1lEvy(?y3P@q{}9_preqj=7`QXgr7qXgeh`c&pnF3PAb# zk^49!LmIRcKN}O3M)9Q|dExh@&RC}aOf7^UsZS4QN%JMyK{x^TxW_$P?EpRJ#RB-L zzSbcFNQM&8ephMC)zM%K%}#ilWL0WA5?P)G5~z+JkrT8->ju4B!_sYhwxa^7R9CoW zO+OCd*%mUc3(=tYTkB@W%H_vq*9TPFD{{C^G!@pZThYrwZr^+c5u42V!Ev)WmHfTg zqsxJ5l@>2E^d(%vyq}ysSi&=fFq=lkFe=$ zkbLj|7SDg{ik|A<^i2CHCCw(DA}W1o#y(aI6&0o!k})rN>{m7^I9}sYJ()SbuIKK7 zfy@z|Ll=lkUq6LIz86UsLd;TESSmyLGkCp0^8zNm6hY3*3WIi-=8 zeE!0yvKwIR@woC0|8^skb#lhzZY#QM`R{He#YLSMMk8ImqxpZ|=-+MTK5yH)RsGv1 SqAld31b9b+!^4vS8UF!Hwr>;w diff --git a/maps/away/slavers/icons/uniform.dmi b/maps/away/slavers/icons/uniform.dmi deleted file mode 100644 index 841007db55fbe81af2043694a4cf714a65d8003c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 781 zcmV+o1M>WdP)fFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33t zGfE(w;*!LYR3KBSJijO>MTv_uC9|j)$T#HTOe;#vO@*-GsxnG*6Z7&jQxuZ&Qz~_f zbMi~#%i~M)GSl*lauJ$MP&6wmxca$(-2?zv%`O`gxq+_$00GrWL_t(oh3%JdZ^9rD z#cA&jT4&1?gZlly=nk4WlX9GE{bR{^sZI19_j^z+MLa(|@0 z>$;v$Aau)EF+i95ivhtRx>SH@K?;ykN&x@~m#a8@7+jAIX&4Y(iJ%2YKG8^wutUio z20%x2U;w&x2Q2_t_G!eCC*VHT1aOA~qz3!}C}h+E0FPt9m;lFP!N(qQ14;l`Eu$8I z7YJbD?levS$92G&x7VYAS#LHqK=LPk2!vC~H}gCj|E>J(cLCBbFfjqADf^$RMKVu- zwX^^U@Z*<{+X>Dgqzg_3R|)Wnf8vdR=@I~105za_6l@Jp_w!a>3bqAMeFGQAJFNIW z@mc`I=fiRVQv+xLY~AMu!~nX;4U_;3sQFxw0hJkO0qWxo&kvT{#sC^XlNvzro0^)M zn%<=7Sha%W#~uA6IpPiigAKMRZYM-%ZS-Es7@hag+8tA1Kt%8DwQOIl_ZZ&+kY?~6 z0Fn&g_pg0`5JId2a>-^uUi*L~0SLpRY&+l_ZW7=Y&ieqlvHS+{?d*95yh3$As@Qdu z