diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 8a9f995d26f..eb2d7b924a7 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -20,6 +20,12 @@ datum/mind var/rev_cooldown = 0 proc/transfer_to(mob/new_character) + // multikey information is stored in the mob, not the mind, so + // we need to clean this stuff up to avoid multikey alerts + current.lastKnownIP = null + current.computer_id = null + + if(current) current.mind = null @@ -28,6 +34,9 @@ datum/mind new_character.key = key + // mob/Login() will handle setting the new mob's lastKnownIP and + // computer_id for us + proc/store_memory(new_text) memory += "[new_text]
" diff --git a/code/game/gamemodes/meme/meme.dm b/code/game/gamemodes/meme/meme.dm index c362caf4d43..a98bc524441 100644 --- a/code/game/gamemodes/meme/meme.dm +++ b/code/game/gamemodes/meme/meme.dm @@ -11,7 +11,9 @@ var - var/datum/mind/first_host = null + var/list/datum/mind/first_hosts = list() + var/list/assigned_hosts = list() + const prob_int_murder_target = 50 // intercept names the assassination target half the time prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target @@ -41,23 +43,34 @@ if(!..()) return 0 + // for every 10 players, get 1 meme, and for each meme, get a host + // also make sure that there's at least one meme and one host + recommended_enemies = max(src.num_players() / 10 * 2, 2) + var/list/datum/mind/possible_memes = get_players_for_role(BE_MEME) if(possible_memes.len < 2) log_admin("MODE FAILURE: MEME. NOT ENOUGH MEME CANDIDATES.") return 0 // not enough candidates for meme - var/datum/mind/meme = pick(possible_memes) - possible_memes.Remove(meme) + // for each 2 possible memes, add one meme and one host + while(possible_memes.len >= 2) + var/datum/mind/meme = pick(possible_memes) + possible_memes.Remove(meme) - first_host = pick(possible_memes) + var/datum/mind/first_host = pick(possible_memes) + possible_memes.Remove(first_host) - modePlayer += meme - modePlayer += first_host - memes += meme + modePlayer += meme + modePlayer += first_host + memes += meme + first_hosts += first_host - meme.assigned_role = "MODE" //So they aren't chosen for other jobs. - meme.special_role = "Meme" + // so that we can later know which host belongs to which meme + assigned_hosts[meme.key] = first_host + + meme.assigned_role = "MODE" //So they aren't chosen for other jobs. + meme.special_role = "Meme" return 1 @@ -72,6 +85,9 @@ var/mob/original = meme.current meme.transfer_to(M) M.clearHUD() + + // get the host for this meme + var/datum/mind/first_host = assigned_hosts[meme.key] M.enter_host(first_host.current) forge_meme_objectives(meme, first_host) @@ -79,7 +95,7 @@ break - // TODO: make it possible to have multiple memes with multiple hosts + log_admin("Created [memes.len] memes.") spawn (rand(waittime_l, waittime_h)) send_intercept() @@ -135,7 +151,6 @@ var/attuned = 0 if((meme.current) && istype(meme.current,/mob/living/parasite/meme)) world << "The meme was [meme.current.key]." - world << "The first host was [src:first_host.current.key]." world << "The last host was [meme.current:host.key]." world << "Hosts attuned: [attuned]" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 7d9b6d65f85..3d3ab39da8b 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -134,6 +134,26 @@ var/global/BSACooldown = 0 M.change_mob_type( /mob/living/simple_animal/constructwraith , null, null, delmob) if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob) + if("meme") + var/mob/living/parasite/meme/newmeme = new + M.mind.transfer_to(newmeme) + newmeme.clearHUD() + + var/found = 0 + for(var/mob/living/carbon/human/H in world) if(H.client && !H.parasites.len) + found = 1 + newmeme.enter_host(H) + + log_admin("[H] has become [newmeme.key]'s host") + + break + + // if there was no host, abort + if(!found) + newmeme.mind.transfer_to(M) + log_admin("Failed to find host for meme [M.key]. Aborting.") + + if(href_list["view_player_info"]) show_player_info(href_list["view_player_info"]) @@ -2435,6 +2455,7 @@ var/global/BSACooldown = 0 body += "Builder , " body += "Wraith \] " body += "Shade" + body += "Meme" body += "
" if (M.client) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 750174757f1..795f2cf8ab4 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -892,7 +892,7 @@ switch(alert("You sure you wish to edit this mob's appearance?",,"Yes","No")) if("No") return - if(istype(M,/mob/living/carbon/human/tajaran) || istype(M,/mob/living/carbon/human/birdman)) + if(istype(M,/mob/living/carbon/human/tajaran)) usr << "\red Humanoid aliens do not have an editable appearance... yet!" else var/new_facial = input("Please select facial hair color.", "Character Generation") as color diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 4fc203c2f4e..c497f3d023e 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -252,6 +252,28 @@ dat += "Changeling not found!" dat += "" + if(ticker.mode.memes.len > 0) + dat += "
" + for(var/datum/mind/meme in ticker.mode.memes) + var/mob/living/parasite/meme/M = meme.current + if(M) + dat += "" + dat += "" + dat += "" + + // need this check because the meme may be possessing someone right now + if(istype(M)) + dat += "\t" + dat += "
Memes
[M.key][M.client ? "" : " (logged out)"][M.stat == 2 ? " (DEAD)" : ""]PMShow Objective
Attuned: " + for(var/mob/attuned in M.indoctrinated) + if(attuned.key) + dat += "[attuned.real_name]([attuned.key]) " + else + dat += "[attuned.real_name] " + else + dat += "
Changeling not found!
" + + if(ticker.mode.wizards.len > 0) dat += "
" for(var/datum/mind/wizard in ticker.mode.wizards) diff --git a/code/modules/mob/living/parasite/meme.dm b/code/modules/mob/living/parasite/meme.dm index f0c219252fd..61989ce78b0 100644 --- a/code/modules/mob/living/parasite/meme.dm +++ b/code/modules/mob/living/parasite/meme.dm @@ -90,8 +90,8 @@ mob/living/parasite/meme/Life() src.death() return - if(host.blinded) src.blinded = 1 - else src.blinded = 0 + if(host.blinded && host.stat != 1) src.blinded = 1 + else src.blinded = 0 mob/living/parasite/meme/death() @@ -382,10 +382,15 @@ mob/living/parasite/meme/verb/SubtleJump(mob/living/carbon/human/target as mob i src << "Your target doesn't seem to hear you.." return + if(target.parasites.len > 0) + src << "Your target already is possessed by something.." + return + src.exit_host() src.enter_host(target) usr << "You successfully jumped to [target]." + log_admin("[src.key] has jumped to [target]") // Jump to a distant target through a shout mob/living/parasite/meme/verb/ObviousJump(mob/living/carbon/human/target as mob in world) @@ -415,10 +420,15 @@ mob/living/parasite/meme/verb/ObviousJump(mob/living/carbon/human/target as mob src << "Your target doesn't seem to hear you.." return + if(target.parasites.len > 0) + src << "Your target already is possessed by something.." + return + src.exit_host() src.enter_host(target) usr << "You successfully jumped to [target]." + log_admin("[src.key] has jumped to [target]") // Jump to an attuned mob for free mob/living/parasite/meme/verb/AttunedJump(mob/living/carbon/human/target as mob in world) @@ -441,6 +451,8 @@ mob/living/parasite/meme/verb/AttunedJump(mob/living/carbon/human/target as mob usr << "You successfully jumped to [target]." + log_admin("[src.key] has jumped to [target]") + // ATTUNE a mob, adding it to the indoctrinated list mob/living/parasite/meme/verb/Attune() set category = "Meme" @@ -459,6 +471,8 @@ mob/living/parasite/meme/verb/Attune() usr << "You successfully indoctrinated [host]." host << "\red Your head feels a bit roomier.." + log_admin("[src.key] has attuned [host]") + // Enables the mob to take a lot more damage mob/living/parasite/meme/verb/Analgesic() set category = "Meme" @@ -511,8 +525,12 @@ mob/living/parasite/meme/verb/Possession() host_mind.current.clearHUD() host.update_clothing() + log_admin("[meme_mind.key] has taken possession of [host]([host_mind.key])") + sleep(600) + log_admin("[meme_mind.key] has lost possession of [host]([host_mind.key])") + meme_mind.transfer_to(src) host_mind.transfer_to(host) meme_mind.current.clearHUD()
Wizards