diff --git a/code/__DEFINES.dm b/code/__DEFINES.dm index c108b270202..242b17f8ef3 100644 --- a/code/__DEFINES.dm +++ b/code/__DEFINES.dm @@ -456,4 +456,14 @@ var/list/be_special_flags = list( #define DNA_HAIR_STYLE_BLOCK 7 #define DNA_STRUC_ENZYMES_BLOCKS 14 -#define DNA_UNIQUE_ENZYMES_LEN 32 \ No newline at end of file +#define DNA_UNIQUE_ENZYMES_LEN 32 + +//Transformation proc stuff +#define TR_KEEPITEMS 1 +#define TR_KEEPVIRUS 2 +#define TR_KEEPDAMAGE 4 +#define TR_HASHNAME 8 // hashing names (e.g. monkey(e34f)) (only in monkeyize) +#define TR_KEEPIMPLANTS 16 +#define TR_KEEPSE 32 // changelings shouldn't edit the DNA's SE when turning into a monkey +#define TR_DEFAULTMSG 64 +#define TR_KEEPSRC 128 diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 9123dbbd15e..7613e40f383 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -649,6 +649,20 @@ client if("left") A.dir = turn(A.dir, 45) href_list["datumrefresh"] = href_list["rotatedatum"] + else if(href_list["makehuman"]) + if(!check_rights(0)) return + + var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) + if(!istype(Mo)) + usr << "This can only be done to instances of type /mob/living/carbon/monkey" + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return + if(!Mo) + usr << "Mob doesn't exist anymore" + return + holder.Topic(href, list("humanone"=href_list["makehuman"])) + else if(href_list["makemonkey"]) if(!check_rights(0)) return diff --git a/code/datums/mind.dm b/code/datums/mind.dm index cbd1d07eade..a30866ccc60 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -765,7 +765,7 @@ datum/mind return switch(href_list["monkey"]) if("healthy") - if (usr.client.holder.rights & R_ADMIN) + if (check_rights(R_ADMIN)) var/mob/living/carbon/human/H = current var/mob/living/carbon/monkey/M = current if (istype(H)) @@ -780,7 +780,7 @@ datum/mind D.cure(0) sleep(0) //because deleting of virus is done through spawn(0) if("infected") - if (usr.client.holder.rights & R_ADMIN) + if (check_rights(R_ADMIN, 0)) var/mob/living/carbon/human/H = current var/mob/living/carbon/monkey/M = current if (istype(H)) @@ -793,21 +793,18 @@ datum/mind else if (istype(M)) current.contract_disease(new /datum/disease/jungle_fever,1,0) if("human") - var/mob/living/carbon/monkey/M = current - if (istype(M)) - for(var/datum/disease/D in M.viruses) - if (istype(D,/datum/disease/jungle_fever)) - D.cure(0) - sleep(0) //because deleting of virus is doing throught spawn(0) - log_admin("[key_name(usr)] attempting to humanize [key_name(current)]") - message_admins("\blue [key_name_admin(usr)] attempting to humanize [key_name_admin(current)]") - var/obj/item/weapon/dnainjector/m2h/m2h = new - var/obj/item/weapon/implant/mobfinder = new(M) //hack because humanizing deletes mind --rastaf0 - src = null - m2h.inject(M) - src = mobfinder.loc:mind - del(mobfinder) - current.radiation -= 50 + if (check_rights(R_ADMIN, 0)) + var/mob/living/carbon/human/H = current + var/mob/living/carbon/monkey/M = current + if (istype(M)) + for(var/datum/disease/D in M.viruses) + if (istype(D,/datum/disease/jungle_fever)) + D.cure(0) + sleep(0) //because deleting of virus is doing throught spawn(0) + log_admin("[key_name(usr)] attempting to humanize [key_name(current)]") + message_admins("\blue [key_name_admin(usr)] attempting to humanize [key_name_admin(current)]") + H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG) + src = H.mind else if (href_list["silicon"]) switch(href_list["silicon"]) diff --git a/code/game/dna.dm b/code/game/dna.dm index 043c8a20032..bb5f61d9b3a 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -298,136 +298,25 @@ //////////////////////////////////////////////////////////// Monkey Block if(blocks[RACEBLOCK]) if(istype(M, /mob/living/carbon/human)) // human > monkey - var/mob/living/carbon/human/H = M - H.monkeyizing = 1 - var/list/implants = list() //Try to preserve implants. - for(var/obj/item/weapon/implant/W in H) - implants += W - W.loc = null - - if(!connected) - for(var/obj/item/W in (H.contents-implants)) - if(W==H.w_uniform) // will be teared - continue - H.drop_from_inventory(W) - M.monkeyizing = 1 - M.canmove = 0 - M.icon = null - M.invisibility = 101 - var/atom/movable/overlay/animation = new( M.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("h2monkey", animation) - sleep(48) - del(animation) - - var/mob/living/carbon/monkey/O = new(src) - - if(M) - if(M.dna) - O.dna = M.dna - M.dna = null - - if(M.suiciding) - O.suiciding = M.suiciding - M.suiciding = null - - - for(var/datum/disease/D in M.viruses) - O.viruses += D - D.affected_mob = O - M.viruses -= D - - - for(var/obj/T in (M.contents-implants)) - del(T) - - O.loc = M.loc - - if(M.mind) - M.mind.transfer_to(O) //transfer our mind to the cute little monkey - + var/mob/living/carbon/monkey/O = M.monkeyize(TR_KEEPITEMS | TR_HASHNAME | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS) + O.take_overall_damage(40, 0) + O.adjustToxLoss(20) if(connected) //inside dna thing var/obj/machinery/dna_scannernew/C = connected O.loc = C C.occupant = O connected = null - O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6)) - O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss()) - O.adjustToxLoss(M.getToxLoss() + 20) - O.adjustOxyLoss(M.getOxyLoss()) - O.stat = M.stat - O.a_intent = "harm" - for (var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - // O.update_icon = 1 //queue a full icon update at next life() call - del(M) return 1 else if(istype(M, /mob/living/carbon/monkey)) // monkey > human, - var/mob/living/carbon/monkey/Mo = M - Mo.monkeyizing = 1 - var/list/implants = list() //Still preserving implants - for(var/obj/item/weapon/implant/W in Mo) - implants += W - W.loc = null - if(!connected) - for(var/obj/item/W in (Mo.contents-implants)) - Mo.drop_from_inventory(W) - M.monkeyizing = 1 - M.canmove = 0 - M.icon = null - M.invisibility = 101 - var/atom/movable/overlay/animation = new( M.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("monkey2h", animation) - sleep(48) - del(animation) - - var/mob/living/carbon/human/O = new( src ) - O.gender = (deconstruct_block(getblock(M.dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE - - if(M) - if(M.dna) - O.dna = M.dna - M.dna = null - - if(M.suiciding) - O.suiciding = M.suiciding - M.suiciding = null - - O.viruses = M.viruses.Copy() - M.viruses.Cut() - for(var/datum/disease/D in O.viruses) - D.affected_mob = O - - O.loc = M.loc - - if(M.mind) - M.mind.transfer_to(O) //transfer our mind to the human - + var/mob/living/carbon/human/O = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPVIRUS) + O.take_overall_damage(40, 0) + O.adjustToxLoss(20) if(connected) //inside dna thing var/obj/machinery/dna_scannernew/C = connected O.loc = C C.occupant = O connected = null - - O.real_name = random_name(O.gender) - - updateappearance(O) - O.take_overall_damage(M.getBruteLoss(), M.getFireLoss()) - O.adjustToxLoss(M.getToxLoss()) - O.adjustOxyLoss(M.getOxyLoss()) - O.stat = M.stat - for (var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - // O.update_icon = 1 //queue a full icon update at next life() call - del(M) return 1 //////////////////////////////////////////////////////////// Monkey Block if(M) diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index 99aaebc39fa..2e250e689bd 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -3,7 +3,7 @@ if(!mind) return if(!mind.changeling) mind.changeling = new /datum/changeling(gender) if(!iscarbon(src)) return - + verbs += /datum/changeling/proc/EvolutionMenu var/lesser_form = !ishuman(src) @@ -66,7 +66,7 @@ /mob/living/carbon/proc/changeling_absorb_dna() set category = "Changeling" set name = "Absorb DNA" - + var/datum/changeling/changeling = changeling_power(0,0,100) if(!changeling) return @@ -205,61 +205,24 @@ changeling.geneticdamage = 30 src << "Our genes cry out!" - //TODO replace with monkeyize proc - var/list/implants = list() //Try to preserve implants. - for(var/obj/item/weapon/implant/W in src) - implants += W - - monkeyizing = 1 - canmove = 0 - icon = null - overlays.Cut() - invisibility = 101 - - var/atom/movable/overlay/animation = new /atom/movable/overlay( loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("h2monkey", animation) - sleep(48) - del(animation) - - var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) - O.dna = dna - dna = null - - for(var/obj/item/W in src) - drop_from_inventory(W) - for(var/obj/T in src) - del(T) - - O.loc = loc - O.name = "monkey ([copytext(md5(real_name), 2, 6)])" - O.setToxLoss(getToxLoss()) - O.adjustBruteLoss(getBruteLoss()) - O.setOxyLoss(getOxyLoss()) - O.adjustFireLoss(getFireLoss()) - O.stat = stat - O.a_intent = "harm" - for(var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - - mind.transfer_to(O) + var/mob/living/carbon/monkey/O = monkeyize(TR_KEEPITEMS | TR_HASHNAME | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPSE | TR_KEEPSRC) O.make_changeling(1) O.verbs += /mob/living/carbon/proc/changeling_lesser_transform feedback_add_details("changeling_powers","LF") + . = 1 del(src) - return 1 + return //Transform into a human /mob/living/carbon/proc/changeling_lesser_transform() + set category = "Changeling" set name = "Transform (1)" var/datum/changeling/changeling = changeling_power(1,1,0) + if(!changeling) return var/list/names = list() @@ -278,67 +241,20 @@ visible_message("[src] transforms!") dna = chosen_dna - var/list/implants = list() - for (var/obj/item/weapon/implant/I in src) //Still preserving implants - implants += I + var/mob/living/carbon/human/O = humanize((TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPSRC),chosen_dna.real_name) - monkeyizing = 1 - canmove = 0 - icon = null - overlays.Cut() - invisibility = 101 - var/atom/movable/overlay/animation = new /atom/movable/overlay( loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("monkey2h", animation) - sleep(48) - del(animation) - - for(var/obj/item/W in src) - u_equip(W) - if (client) - client.screen -= W - if (W) - W.loc = loc - W.dropped(src) - W.layer = initial(W.layer) - - var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) - O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE - O.dna = dna - dna = null - O.real_name = chosen_dna.real_name - - for(var/obj/T in src) - del(T) - - O.loc = loc - - updateappearance(O) - domutcheck(O, null) - O.setToxLoss(getToxLoss()) - O.adjustBruteLoss(getBruteLoss()) - O.setOxyLoss(getOxyLoss()) - O.adjustFireLoss(getFireLoss()) - O.stat = stat - for (var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - - mind.transfer_to(O) O.make_changeling() - feedback_add_details("changeling_powers","LFT") + . = 1 del(src) - return 1 + return //Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. /mob/living/carbon/proc/changeling_fakedeath() set category = "Changeling" set name = "Regenerative Stasis (20)" - + var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) if(!changeling) return diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 0066bd65bce..2e759d575a5 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -24,6 +24,10 @@ /obj/item/weapon/implant/proc/get_data() return "No information available" +/obj/item/weapon/implant/dropped(mob/user as mob) + . = 1 + del src + return . /obj/item/weapon/implant/tracking name = "tracking" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 551caed07cf..a1469f5b7df 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -78,6 +78,12 @@ var/global/floorIsLava = 0 body += "Transformation:" body += "
" + //Human + if(ishuman(M)) + body += "Human | " + else + body += "Humanize | " + //Monkey if(ismonkey(M)) body += "Monkeyized | " diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 0484ba0bd04..34b0026ff8a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1012,6 +1012,18 @@ message_admins("\blue [key_name_admin(usr)] attempting to monkeyize [key_name_admin(H)]", 1) H.monkeyize() + else if(href_list["humanone"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/monkey/Mo = locate(href_list["humanone"]) + if(!istype(Mo)) + usr << "This can only be used on instances of type /mob/living/carbon/monkey" + return + + log_admin("[key_name(usr)] attempting to humanize [key_name(Mo)]") + message_admins("\blue [key_name_admin(usr)] attempting to humanize [key_name_admin(Mo)]", 1) + Mo.humanize() + else if(href_list["corgione"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index dc14043b5e9..a7004485f31 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,47 +1,180 @@ -/mob/living/carbon/human/proc/monkeyize() +/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null) if (monkeyizing) return - for(var/obj/item/W in src) - if (W==w_uniform) // will be torn - continue - drop_from_inventory(W) + //Handle items on mob + + //first implants + var/list/implants = list() + if (tr_flags & TR_KEEPIMPLANTS) + for(var/obj/item/weapon/implant/W in src) + implants += W + + //now the rest + if (tr_flags & TR_KEEPITEMS) + for(var/obj/item/W in (src.contents-implants)) + drop_from_inventory(W) + + //Make mob invisible and spawn animation regenerate_icons() monkeyizing = 1 canmove = 0 stunned = 1 icon = null invisibility = 101 - for(var/t in organs) - del(t) var/atom/movable/overlay/animation = new /atom/movable/overlay( loc ) animation.icon_state = "blank" animation.icon = 'icons/mob/mob.dmi' animation.master = src flick("h2monkey", animation) - sleep(48) + sleep(22) //animation = null var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc ) del(animation) - O.name = "monkey" + // hash the original name? + if (tr_flags & TR_HASHNAME) + O.name = "monkey ([copytext(md5(real_name), 2, 6)])" + O.real_name = "monkey ([copytext(md5(real_name), 2, 6)])" + if (newname) //if there's a name as an argument, always take that one over the current name + O.name = newname + O.real_name = newname + + //handle DNA and other attributes O.dna = dna dna = null - O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(BAD_MUTATION_DIFFICULTY,BAD_MUTATION_DIFFICULTY)) + if (!(tr_flags & TR_KEEPSE)) + O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(BAD_MUTATION_DIFFICULTY,BAD_MUTATION_DIFFICULTY)) + if(suiciding) + O.suiciding = suiciding O.loc = loc - O.viruses = viruses - viruses = list() - for(var/datum/disease/D in O.viruses) - D.affected_mob = O + O.a_intent = "harm" - if (client) - client.mob = O + //keep viruses? + if (tr_flags & TR_KEEPVIRUS) + O.viruses = viruses + viruses = list() + for(var/datum/disease/D in O.viruses) + D.affected_mob = O + + //keep damage? + if (tr_flags & TR_KEEPDAMAGE) + O.setToxLoss(getToxLoss()) + O.adjustBruteLoss(getBruteLoss()) + O.setOxyLoss(getOxyLoss()) + O.adjustFireLoss(getFireLoss()) + + //re-add implants to new mob + for(var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + + //transfer mind and delete old mob if(mind) mind.transfer_to(O) - O.a_intent = "harm" - O << "You are now a monkey." - spawn(0)//To prevent the proc from returning null. + if (tr_flags & TR_DEFAULTMSG) + O << "You are now a monkey." + updateappearance(O) + . = O + if ( !(tr_flags & TR_KEEPSRC) ) //flag should be used if monkeyize() is called inside another proc of src so that one does not crash del(src) - return O + return + + + +////////////////////////// Humanize ////////////////////////////// +//Could probably be merged with monkeyize but other transformations got their own procs, too + +/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null) + if (monkeyizing) + return + //Handle items on mob + + //first implants + var/list/implants = list() + if (tr_flags & TR_KEEPIMPLANTS) + for(var/obj/item/weapon/implant/W in src) + implants += W + + //now the rest + if (tr_flags & TR_KEEPITEMS) + for(var/obj/item/W in (src.contents-implants)) + u_equip(W) + if (client) + client.screen -= W + if (W) + W.loc = loc + W.dropped(src) + W.layer = initial(W.layer) + + // for(var/obj/item/W in src) + // drop_from_inventory(W) + + //Make mob invisible and spawn animation + regenerate_icons() + monkeyizing = 1 + canmove = 0 + stunned = 1 + icon = null + invisibility = 101 + var/atom/movable/overlay/animation = new( loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(22) + var/mob/living/carbon/human/O = new( loc ) + del(animation) + + + O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE + O.dna = dna + dna = null + if (newname) //if there's a name as an argument, always take that one over the current name + O.real_name = newname + else + if ( !(cmptext ("monkey",copytext(O.dna.real_name,1,7)) ) ) + O.real_name = O.dna.real_name + else + O.real_name = random_name(O.gender) + O.name = O.real_name + + if (!(tr_flags & TR_KEEPSE)) + O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(1,BAD_MUTATION_DIFFICULTY)) + + if(suiciding) + O.suiciding = suiciding + + O.loc = loc + + //keep viruses? + if (tr_flags & TR_KEEPVIRUS) + O.viruses = viruses + viruses = list() + for(var/datum/disease/D in O.viruses) + D.affected_mob = O + + //keep damage? + if (tr_flags & TR_KEEPDAMAGE) + O.setToxLoss(getToxLoss()) + O.adjustBruteLoss(getBruteLoss()) + O.setOxyLoss(getOxyLoss()) + O.adjustFireLoss(getFireLoss()) + + //re-add implants to new mob + for(var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + + if(mind) + mind.transfer_to(O) + O.a_intent = "help" + if (tr_flags & TR_DEFAULTMSG) + O << "You are now a human." + updateappearance(O) + . = O + if ( !(tr_flags & TR_KEEPSRC) ) //don't delete src yet if it's needed to finish calling proc + del(src) + return /mob/new_player/AIize() spawning = 1 @@ -124,6 +257,7 @@ O.rename_self("ai",1) . = O del(src) + return //human -> robot @@ -165,10 +299,8 @@ O.mmi = new /obj/item/device/mmi(O) O.mmi.transfer_identity(src)//Does not transfer key/client. - - spawn(0)//To prevent the proc from returning null. - del(src) - return O + . = O + del(src) //human -> alien /mob/living/carbon/human/proc/Alienize() @@ -198,9 +330,8 @@ new_xeno.key = key new_xeno << "You are now an alien." - spawn(0)//To prevent the proc from returning null. - del(src) - return + . = new_xeno + del(src) /mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) if (monkeyizing) @@ -234,9 +365,8 @@ new_slime.key = key new_slime << "You are now a slime. Skreee!" - spawn(0)//To prevent the proc from returning null. - del(src) - return + . = new_slime + del(src) /mob/living/carbon/human/proc/corgize() if (monkeyizing) @@ -256,9 +386,8 @@ new_corgi.key = key new_corgi << "You are now a Corgi. Yap Yap!" - spawn(0)//To prevent the proc from returning null. - del(src) - return + . = new_corgi + del(src) /mob/living/carbon/human/proc/blobize() // Oh boy, this is for you Int - Summoner if (monkeyizing) @@ -278,9 +407,8 @@ new_blob.key = key new_blob << "You are now a Blob Fragment. You can now sacrifice yourself to spawn blobs!" - spawn(0)//To prevent the proc from returning null. - del(src) - return + . = new_blob + del(src) /mob/living/carbon/human/Animalize() @@ -312,9 +440,8 @@ new_mob << "You suddenly feel more... animalistic." - spawn() - del(src) - return + . = new_mob + del(src) /mob/proc/Animalize() @@ -331,6 +458,7 @@ new_mob.a_intent = "harm" new_mob << "You feel more... animalistic" + . = new_mob del(src) /* Certain mob types have problems and should not be allowed to be controlled by players.