diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 14c9e46c2b69..365e246d5c54 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -1,4 +1,4 @@ -var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/disintegrate,/obj/spell/ethereal_jaunt,/obj/spell/fireball,/obj/spell/forcewall,/obj/spell/knock,/obj/spell/magic_missile,/obj/spell/mutate,/obj/spell/teleport) //needed for the badmin verb for now +var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/conjure,/obj/spell/disintegrate,/obj/spell/ethereal_jaunt,/obj/spell/fireball,/obj/spell/forcewall,/obj/spell/knock,/obj/spell/magic_missile,/obj/spell/mutate,/obj/spell/teleport) //needed for the badmin verb for now /obj/spell name = "Spell" @@ -7,6 +7,7 @@ var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/disintegrate var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? var/recharge = 100 //recharge time in deciseconds var/clothes_req = 1 //see if it requires clothes + var/stat_allowed = 0 //see if it requires being conscious var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell var/invocation_type = "none" //can be none, whisper and shout var/range = 7 //the range of the spell @@ -20,7 +21,7 @@ var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/disintegrate if(cast) usr << "[name] is still recharging." return 0 - if(usr.stat) + if(usr.stat && !stat_allowed) usr << "Not when you're incapacitated." return 0 if(clothes_req) //clothes check diff --git a/code/datums/spells/conjure.dm b/code/datums/spells/conjure.dm new file mode 100644 index 000000000000..116f89336df2 --- /dev/null +++ b/code/datums/spells/conjure.dm @@ -0,0 +1,44 @@ +/obj/spell/conjure + name = "Summon Bigger Carp" + desc = "This spell conjures an elite carp." + + school = "conjuration" + recharge = 1200 + clothes_req = 1 + invocation = "NOUK FHUNMM SACP RISSKA" + invocation_type = "shout" + range = 1 //radius in which objects are randomly summoned + var/list/summon_type = list("/obj/livestock/spesscarp/elite") //determines what exactly will be summoned + var/summon_duration = 0 // 0=permanent, any other time in deciseconds + var/summon_amt = 1 //amount of objects summoned + var/summon_ignore_density = 0 //if set to 1, adds dense tiles to possible spawn places + var/summon_ignore_prev_spawn_points = 0 //if set to 1, each new object is summoned on a new spawn point + +/obj/spell/conjure/Click() + ..() + + if(!cast_check()) + return + + invocation() + + var/list/possible_spawn_points = list() + + for(var/turf/T in oview(usr,range)) + if(!T.density || summon_ignore_density) + possible_spawn_points += T + + for(var/i=0,i0) + M.bruteloss++ + else + M.bruteloss-- if("toxin") - M.toxloss++ + if(damage_amount>0) + M.toxloss++ + else + M.toxloss-- if("oxygen") - M.oxyloss++ + if(damage_amount>0) + M.oxyloss++ + else + M.oxyloss-- if("fire") - M.fireloss++ \ No newline at end of file + if(damage_amount>0) + M.fireloss++ + else + M.fireloss-- \ No newline at end of file diff --git a/code/datums/spells/forcewall.dm b/code/datums/spells/forcewall.dm index 0e9d5a98da7e..be9486ceee61 100644 --- a/code/datums/spells/forcewall.dm +++ b/code/datums/spells/forcewall.dm @@ -25,6 +25,8 @@ forcefields += new /obj/forcefield(T) spawn (wall_lifespan) - del (forcefields) + for(var/obj/forcefield/F in forcefields) + del(F) + del(forcefields) return \ No newline at end of file diff --git a/code/datums/spells/teleport.dm b/code/datums/spells/teleport.dm index 066adaf2f117..db68b3b6ec1b 100644 --- a/code/datums/spells/teleport.dm +++ b/code/datums/spells/teleport.dm @@ -31,7 +31,7 @@ var/area/thearea = teleportlocs[A] - usr.say("SCYAR NILA [uppertext(A)]") + usr.say("[invocation] [uppertext(A)]") if(usr.gender=="male") playsound(usr.loc, pick('vs_chant_conj_hm.wav','vs_chant_conj_lm.wav','vs_chant_ench_hm.wav','vs_chant_ench_lm.wav','vs_chant_evoc_hm.wav','vs_chant_evoc_lm.wav','vs_chant_illu_hm.wav','vs_chant_illu_lm.wav','vs_chant_necr_hm.wav','vs_chant_necr_lm.wav'), 100, 1) else diff --git a/code/game/objects/traps.dm b/code/game/objects/traps.dm index 5583e0376bfa..cb07593cd942 100644 --- a/code/game/objects/traps.dm +++ b/code/game/objects/traps.dm @@ -1,75 +1,216 @@ -/obj/trap +/obj/pressure_plate + name = "pressure plate" + desc = "A pressure plate that triggers a trap or a few of them." + density = 0 + var/list/connected_traps_names = list() //mappers, edit this when you place pressure plates on the map. don't forget to make the connected traps have an UNIQUE name + var/list/connected_traps = list() //actual references to the connected traps. leave empty, it is generated at runtime from connected_traps_names + var/trigger_type = "mob and obj" //can be "mob", "obj" or "mob and obj", the only moveable types + +/obj/pressure_plate/New() + ..() + src:visibility = 0 + refresh() + +/obj/pressure_plate/verb/refresh() + set src in view() + connected_traps = list() //emptying the list first + for(var/trap_name in connected_traps_names) + for(var/obj/trap/the_trap in world) + if(the_trap.name == trap_name) + connected_traps += the_trap //adding the trap with the matching name + +/obj/pressure_plate/HasEntered(atom/victim as mob|obj) + if(victim.density && (trigger_type == "mob and obj" || (trigger_type == "mob" && istype(victim,/mob)) || (trigger_type == "obj" && istype(victim,/obj)))) + for(var/obj/trap/T in connected_traps) + T.trigger(victim) + +/obj/pressure_plate/Bumped(atom/victim as mob|obj) + if(victim.density && (trigger_type == "mob and obj" || (trigger_type == "mob" && istype(victim,/mob)) || (trigger_type == "obj" && istype(victim,/obj)))) + for(var/obj/trap/T in connected_traps) + T.trigger(victim) + +/obj/trap //has three subtypes - /aoe, /area (ie affects an entire area), /single (only the victim is affected) name = "trap" desc = "It's a trap!" density = 0 var/uses = 1 //how many times it can be triggered + var/trigger_type = "mob and obj" //can be "mob", "obj" or "mob and obj", the only moveable types. can also be "none" to not be triggered by entering its square (needs to have a pressure plate attached in that case) + var/target_type = "mob" //if it targets mobs, turfs or objs + var/include_dense = 1 //if it includes dense targets in the aoe (may be important for some reason). you'll probably want to change it to 1 if you target mobs or objs /obj/trap/New() ..() src:visibility = 0 //seriously, it keeps saying "undefined var" when I try to do it in the define /obj/trap/HasEntered(victim as mob|obj) - trigger(victim) + if(trigger_type == "mob and obj" || (trigger_type == "mob" && istype(victim,/mob)) || (trigger_type == "obj" && istype(victim,/obj))) + trigger(victim) /obj/trap/Bumped(victim as mob|obj) - trigger(victim) + if(trigger_type == "mob and obj" || (trigger_type == "mob" && istype(victim,/mob)) || (trigger_type == "obj" && istype(victim,/obj))) + trigger(victim) /obj/trap/proc/trigger(victim) if(!uses) return uses-- + activate(victim) -/obj/trap/rocksfall - name = "rocks fall trap" - desc = "Your DM must really hate you." - var/aoe_radius = 3 //radius of rocks falling - var/aoe_include_dense = 0 //if it includes dense tiles in the aoe +/obj/trap/proc/activate() + +/obj/trap/aoe + name = "aoe trap" + desc = "This trap affects a number of mobs, turfs or objs in an aoe" + var/aoe_radius = 3 //radius of aoe var/aoe_range_or_view = "view" //if it includes all tiles in [radius] range or view - var/rocks_amt = 10 //amount of rocks falling - var/rocks_seeking = 0 //if 1, rocks fall only on mobs, otherwise it picks the turfs in the area at random - var/rocks_min_dmg = 50 //min damage per rock - var/rocks_max_dmg = 100 //max damage per rock - var/rocks_hit_chance = 100 //the chance for a rock to hit you -/obj/trap/rocksfall/trigger() - - ..() +/obj/trap/aoe/proc/picktargets() var/list/targets = list() - if(!rocks_seeking) - switch(aoe_range_or_view) - if("view") - for(var/turf/T in view(src,aoe_radius)) - if(!T.density || aoe_include_dense) - targets += T - if("range") - for(var/turf/T in range(src,aoe_radius)) - if(!T.density || aoe_include_dense) - targets += T + switch(target_type) + if("turf") + switch(aoe_range_or_view) + if("view") + for(var/turf/T in view(src,aoe_radius)) + if(!T.density || include_dense) + targets += T + if("range") + for(var/turf/T in range(src,aoe_radius)) + if(!T.density || include_dense) + targets += T + if("mob") + switch(aoe_range_or_view) + if("view") + for(var/mob/living/M in view(src,aoe_radius)) + if(!M.density || include_dense) + targets += M + if("range") + for(var/mob/living/M in range(src,aoe_radius)) + if(!M.density || include_dense) + targets += M + if("obj") + switch(aoe_range_or_view) + if("view") + for(var/obj/O in view(src,aoe_radius)) + if(!O.density || include_dense) + targets += O + if("range") + for(var/obj/O in range(src,aoe_radius)) + if(!O.density || include_dense) + targets += O + return targets + +/obj/trap/aoe/rocksfall + name = "rocks fall trap" + desc = "Your DM must really hate you." + target_type = "turf" + include_dense = 0 + var/rocks_amt = 10 //amount of rocks falling + var/rocks_min_dmg = 50 //min damage per rock + var/rocks_max_dmg = 100 //max damage per rock + var/rocks_hit_chance = 100 //the chance for a rock to hit you + var/list/rocks_type = list() //what rocks might it drop on the target. with var editing, not even limited to rocks. + +/obj/trap/aoe/rocksfall/New() + + ..() + + rocks_type = pick_rock_types() + +/obj/trap/aoe/rocksfall/proc/pick_rock_types() //since we may want subtypes of the trap with completely different rock types, which is best done this way + + var/list/varieties = list() + + varieties = typesof(/obj/item/weapon/ore) + varieties -= /obj/item/weapon/ore/diamond //don't want easily available rare ores, hmm? + varieties -= /obj/item/weapon/ore/uranium + varieties -= /obj/item/weapon/ore/slag //that'd be just stupid + + return varieties + +/obj/trap/aoe/rocksfall/activate() + + var/list/targets = list() + targets = picktargets() + + if(target_type == "turf") for(var/i=0,i