mafia update.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
var/phase = MAFIA_PHASE_SETUP
|
||||
///how long the game has gone on for, changes with every sunrise. day one, night one, day two, etc.
|
||||
var/turn = 0
|
||||
///if enabled, the game has fallen under half pop and is sped up
|
||||
var/speed_up = FALSE
|
||||
///for debugging and testing a full game, or adminbuse. If this is not empty, it will use this as a setup. clears when game is over
|
||||
var/list/custom_setup = list()
|
||||
///first day has no voting, and thus is shorter
|
||||
@@ -187,8 +189,22 @@
|
||||
turn += 1
|
||||
phase = MAFIA_PHASE_DAY
|
||||
if(!check_victory())
|
||||
if(!speed_up)//lets check if the game should be sped up, if not already.
|
||||
var/living_players = 0
|
||||
for(var/i in all_roles)
|
||||
var/datum/mafia_role/player = i
|
||||
if(player.game_status == MAFIA_ALIVE)
|
||||
living_players += 1
|
||||
if(living_players < all_roles.len / 2)
|
||||
speed_up = TRUE
|
||||
send_message("<span class='bold notice'>With only [living_players] living players left, the game timers have been sped up.</span>")
|
||||
day_phase_period /= 2
|
||||
voting_phase_period /= 2
|
||||
judgement_phase_period /= 2
|
||||
judgement_lynch_period /= 2
|
||||
night_phase_period /= 2
|
||||
if(turn == 1)
|
||||
send_message("<span class='notice'><b>The selected map is [current_map.name]!</b></br>[current_map.description]</span>")
|
||||
send_message(span_notice("<b>The selected map is [current_map.name]!</b></br>[current_map.description]"))
|
||||
send_message("<b>Day [turn] started! There is no voting on the first day. Say hello to everybody!</b>")
|
||||
next_phase_timer = addtimer(CALLBACK(src,.proc/check_trial, FALSE),first_day_phase_period,TIMER_STOPPABLE) //no voting period = no votes = instant night
|
||||
else
|
||||
@@ -257,19 +273,19 @@
|
||||
/datum/mafia_controller/proc/lynch()
|
||||
for(var/i in judgement_innocent_votes)
|
||||
var/datum/mafia_role/role = i
|
||||
send_message("<span class='green'>[role.body.real_name] voted innocent.</span>")
|
||||
send_message(span_green("[role.body.real_name] voted innocent."))
|
||||
for(var/ii in judgement_abstain_votes)
|
||||
var/datum/mafia_role/role = ii
|
||||
send_message("<span class='comradio'>[role.body.real_name] abstained.</span>")
|
||||
send_message(span_comradio("[role.body.real_name] abstained."))
|
||||
for(var/iii in judgement_guilty_votes)
|
||||
var/datum/mafia_role/role = iii
|
||||
send_message("<span class='red'>[role.body.real_name] voted guilty.</span>")
|
||||
send_message(span_red("[role.body.real_name] voted guilty."))
|
||||
if(judgement_guilty_votes.len > judgement_innocent_votes.len) //strictly need majority guilty to lynch
|
||||
send_message("<span class='red'><b>Guilty wins majority, [on_trial.body.real_name] has been lynched.</b></span>")
|
||||
on_trial.kill(src, lynch = TRUE)
|
||||
send_message(span_red("<b>Guilty wins majority, [on_trial.body.real_name] has been lynched.</b>"))
|
||||
on_trial.kill(src,lynch = TRUE)
|
||||
addtimer(CALLBACK(src, .proc/send_home, on_trial),judgement_lynch_period)
|
||||
else
|
||||
send_message("<span class='green'><b>Innocent wins majority, [on_trial.body.real_name] has been spared.</b></span>")
|
||||
send_message(span_green("<b>Innocent wins majority, [on_trial.body.real_name] has been spared.</b>"))
|
||||
on_trial.body.forceMove(get_turf(on_trial.assigned_landmark))
|
||||
on_trial = null
|
||||
//day votes are already cleared, so this will skip the trial and check victory/lockdown/whatever else
|
||||
@@ -300,11 +316,14 @@
|
||||
var/list/total_town = list()
|
||||
var/list/total_mafia = list()
|
||||
|
||||
var/alive_town = 0
|
||||
//voting power of town + solos (since they don't want mafia to overpower)
|
||||
var/anti_mafia_power = 0
|
||||
//voting power of mafia (greater than anti mafia power + team end not blocked = mafia victory)
|
||||
var/alive_mafia = 0
|
||||
var/list/solos_to_ask = list() //need to ask after because first round is counting team sizes
|
||||
var/list/total_victors = list() //if this list gets filled with anyone, they win. list because side antags can with with people
|
||||
var/blocked_victory = FALSE //if a solo antagonist is stopping the town or mafia from finishing the game.
|
||||
var/town_can_kill = FALSE //Town has a killing role and it cannot allow mafia to win
|
||||
|
||||
///PHASE ONE: TALLY UP ALL NUMBERS OF PEOPLE STILL ALIVE
|
||||
|
||||
@@ -313,23 +332,24 @@
|
||||
if(MAFIA_TEAM_MAFIA)
|
||||
total_mafia += R
|
||||
if(R.game_status == MAFIA_ALIVE)
|
||||
alive_mafia += R.vote_power
|
||||
alive_mafia += R.vote_potential
|
||||
if(MAFIA_TEAM_TOWN)
|
||||
total_town += R
|
||||
if(R.game_status == MAFIA_ALIVE)
|
||||
alive_town += R.vote_power
|
||||
anti_mafia_power += R.vote_potential
|
||||
if(R.role_flags & ROLE_CAN_KILL) //the game cannot autoresolve with killing roles (unless a solo wins anyways, like traitors who are immune)
|
||||
town_can_kill = TRUE
|
||||
if(MAFIA_TEAM_SOLO)
|
||||
if(R.game_status == MAFIA_ALIVE)
|
||||
if(R.solo_counts_as_town)
|
||||
alive_town += R.vote_power
|
||||
anti_mafia_power += R.vote_potential
|
||||
solos_to_ask += R
|
||||
|
||||
///PHASE TWO: SEND STATS TO SOLO ANTAGS, SEE IF THEY WON OR TEAMS CANNOT WIN
|
||||
|
||||
for(var/datum/mafia_role/solo in solos_to_ask)
|
||||
if(solo.check_total_victory(alive_town, alive_mafia))
|
||||
if(solo.check_total_victory(anti_mafia_power, alive_mafia))
|
||||
total_victors += solo
|
||||
if(solo.block_team_victory(alive_town, alive_mafia))
|
||||
if(solo.block_team_victory(anti_mafia_power, alive_mafia))
|
||||
blocked_victory = TRUE
|
||||
|
||||
//solo victories!
|
||||
@@ -348,7 +368,7 @@
|
||||
award_role(townie.winner_award, townie)
|
||||
start_the_end("<span class='big green'>!! TOWN VICTORY !!</span>")
|
||||
return TRUE
|
||||
else if(alive_mafia >= alive_town) //guess could change if town nightkill is added
|
||||
else if(alive_mafia >= anti_mafia_power && !town_can_kill)
|
||||
start_the_end("<span class='big red'>!! MAFIA VICTORY !!</span>")
|
||||
for(var/datum/mafia_role/changeling in total_mafia)
|
||||
award_role(changeling.winner_award, changeling)
|
||||
@@ -396,6 +416,13 @@
|
||||
custom_setup = list()
|
||||
turn = 0
|
||||
votes = list()
|
||||
|
||||
day_phase_period = initial(day_phase_period)
|
||||
voting_phase_period = initial(voting_phase_period)
|
||||
judgement_phase_period = initial(judgement_phase_period)
|
||||
judgement_lynch_period = initial(judgement_lynch_period)
|
||||
night_phase_period = initial(night_phase_period)
|
||||
|
||||
//map gen does not deal with landmarks
|
||||
QDEL_LIST(landmarks)
|
||||
QDEL_NULL(town_center_landmark)
|
||||
@@ -451,14 +478,15 @@
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_START)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_ACTION_PHASE)
|
||||
//resolve mafia kill, todo unsnowflake this
|
||||
var/datum/mafia_role/R = get_vote_winner("Mafia")
|
||||
if(R)
|
||||
var/datum/mafia_role/victim = get_vote_winner("Mafia")
|
||||
if(victim)
|
||||
var/datum/mafia_role/killer = get_random_voter("Mafia")
|
||||
if(SEND_SIGNAL(killer,COMSIG_MAFIA_CAN_PERFORM_ACTION,src,"mafia killing",R) & MAFIA_PREVENT_ACTION)
|
||||
send_message("<span class='danger'>[killer.body.real_name] was unable to attack [R.body.real_name] tonight!</span>",MAFIA_TEAM_MAFIA)
|
||||
if(!victim.can_action(src, killer, "changeling murder"))
|
||||
send_message(span_danger("[killer.body.real_name] was unable to attack [victim.body.real_name] tonight!"),MAFIA_TEAM_MAFIA)
|
||||
else
|
||||
send_message("<span class='danger'>[killer.body.real_name] has attacked [R.body.real_name]!</span>",MAFIA_TEAM_MAFIA)
|
||||
R.kill(src)
|
||||
send_message(span_danger("[killer.body.real_name] has attacked [victim.body.real_name]!"),MAFIA_TEAM_MAFIA)
|
||||
if(victim.kill(src,killer,lynch=FALSE))
|
||||
to_chat(victim.body, span_userdanger("You have been killed by a Changeling!"))
|
||||
reset_votes("Mafia")
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_KILL_PHASE)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_END)
|
||||
@@ -485,14 +513,14 @@
|
||||
else
|
||||
votes[vote_type][voter] = target
|
||||
if(old_vote && old_vote == target)
|
||||
send_message("<span class='notice'>[voter.body.real_name] retracts their vote for [target.body.real_name]!</span>", team = teams)
|
||||
send_message(span_notice("[voter.body.real_name] retracts their vote for [target.body.real_name]!"), team = teams)
|
||||
else
|
||||
send_message("<span class='notice'>[voter.body.real_name] voted for [target.body.real_name]!</span>",team = teams)
|
||||
send_message(span_notice("[voter.body.real_name] voted for [target.body.real_name]!"),team = teams)
|
||||
if(!teams)
|
||||
target.body.update_icon() //Update the vote display if it's a public vote
|
||||
target.body.update_appearance() //Update the vote display if it's a public vote
|
||||
var/datum/mafia_role/old = old_vote
|
||||
if(old)
|
||||
old.body.update_icon()
|
||||
old.body.update_appearance()
|
||||
|
||||
/**
|
||||
* Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched
|
||||
@@ -504,7 +532,7 @@
|
||||
bodies_to_update += R.body
|
||||
votes[vote_type] = list()
|
||||
for(var/mob/M in bodies_to_update)
|
||||
M.update_icon()
|
||||
M.update_appearance()
|
||||
|
||||
/**
|
||||
* Returns how many people voted for the role, in whatever vote (day vote, night kill vote)
|
||||
@@ -571,6 +599,9 @@
|
||||
/datum/mafia_controller/proc/create_bodies()
|
||||
for(var/datum/mafia_role/role in all_roles)
|
||||
var/mob/living/carbon/human/H = new(get_turf(role.assigned_landmark))
|
||||
ADD_TRAIT(H, TRAIT_NOFIRE, MAFIA_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_NOBREATH, MAFIA_TRAIT)
|
||||
// ADD_TRAIT(H, TRAIT_CANNOT_CRYSTALIZE, MAFIA_TRAIT) freon tomfoolery
|
||||
H.equipOutfit(player_outfit)
|
||||
H.status_flags |= GODMODE
|
||||
RegisterSignal(H,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/display_votes)
|
||||
@@ -707,6 +738,7 @@
|
||||
if(role_count > 0)
|
||||
debug_setup[found_path] = role_count
|
||||
custom_setup = debug_setup
|
||||
try_autostart()//don't worry, this fails if there's a game in progress
|
||||
if("cancel_setup")
|
||||
custom_setup = list()
|
||||
switch(action) //both living and dead
|
||||
@@ -723,28 +755,28 @@
|
||||
switch(action)
|
||||
if("mf_signup")
|
||||
if(!SSticker.HasRoundStarted())
|
||||
to_chat(usr, "<span class='warning'>Wait for the round to start.</span>")
|
||||
to_chat(usr, span_warning("Wait for the round to start."))
|
||||
return
|
||||
if(GLOB.mafia_signup[C.ckey])
|
||||
GLOB.mafia_signup -= C.ckey
|
||||
to_chat(usr, "<span class='notice'>You unregister from Mafia.</span>")
|
||||
to_chat(usr, span_notice("You unregister from Mafia."))
|
||||
return TRUE
|
||||
else
|
||||
GLOB.mafia_signup[C.ckey] = C
|
||||
to_chat(usr, "<span class='notice'>You sign up for Mafia.</span>")
|
||||
to_chat(usr, span_notice("You sign up for Mafia."))
|
||||
if(phase == MAFIA_PHASE_SETUP)
|
||||
check_signups()
|
||||
try_autostart()
|
||||
return TRUE
|
||||
if("mf_spectate")
|
||||
if(C.ckey in spectators)
|
||||
to_chat(usr, "<span class='notice'>You will no longer get messages from the game.</span>")
|
||||
to_chat(usr, span_notice("You will no longer get messages from the game."))
|
||||
spectators -= C.ckey
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You will now get messages from the game.</span>")
|
||||
to_chat(usr, span_notice("You will now get messages from the game."))
|
||||
spectators += C.ckey
|
||||
return TRUE
|
||||
if(user_role.game_status == MAFIA_DEAD)
|
||||
if(user_role && user_role.game_status == MAFIA_DEAD)
|
||||
return
|
||||
//User actions (just living)
|
||||
switch(action)
|
||||
@@ -814,58 +846,59 @@
|
||||
. += L[key]
|
||||
|
||||
/**
|
||||
* Returns a semirandom setup, with...
|
||||
* Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town.
|
||||
* Mafia, 2 normal mafia and one special.
|
||||
* Neutral, two disruption roles, sometimes one is a killing.
|
||||
* Returns a semirandom setup with 12 roles. balance not guaranteed!
|
||||
*
|
||||
* See _defines.dm in the mafia folder for a rundown on what these groups of roles include.
|
||||
* please check the variables at the top of the proc to see how much of each role types it picks
|
||||
*/
|
||||
/datum/mafia_controller/proc/generate_random_setup()
|
||||
var/invests_left = 2
|
||||
var/protects_left = 1
|
||||
var/miscs_left = prob(35)
|
||||
var/protects_left = 2
|
||||
var/killings_left = 1
|
||||
var/supports_left = 2
|
||||
|
||||
var/mafiareg_left = 2
|
||||
var/mafiaspe_left = 1
|
||||
var/killing_role = prob(50)
|
||||
var/disruptors = killing_role ? 1 : 2 //still required to calculate overflow
|
||||
var/overflow_left = max_player - (invests_left + protects_left + miscs_left + mafiareg_left + mafiaspe_left + killing_role + disruptors)
|
||||
|
||||
// if there is one killing role, there will be less disruptors
|
||||
var/neutral_killing_role = prob(50)
|
||||
|
||||
var/list/random_setup = list()
|
||||
var/list/unique_roles_added = list()
|
||||
for(var/i in 1 to max_player) //should match the number of roles to add
|
||||
if(overflow_left)
|
||||
add_setup_role(random_setup, TOWN_OVERFLOW)
|
||||
overflow_left--
|
||||
else if(invests_left)
|
||||
add_setup_role(random_setup, TOWN_INVEST)
|
||||
if(invests_left)
|
||||
add_setup_role(random_setup, unique_roles_added, TOWN_INVEST)
|
||||
invests_left--
|
||||
else if(protects_left)
|
||||
add_setup_role(random_setup, TOWN_PROTECT)
|
||||
add_setup_role(random_setup, unique_roles_added, TOWN_PROTECT)
|
||||
protects_left--
|
||||
else if(miscs_left)
|
||||
add_setup_role(random_setup, TOWN_MISC)
|
||||
miscs_left--
|
||||
else if(killings_left)
|
||||
add_setup_role(random_setup, unique_roles_added, TOWN_KILLING)
|
||||
killings_left--
|
||||
else if(supports_left)
|
||||
add_setup_role(random_setup, unique_roles_added, TOWN_SUPPORT)
|
||||
supports_left--
|
||||
else if(mafiareg_left)
|
||||
add_setup_role(random_setup, MAFIA_REGULAR)
|
||||
add_setup_role(random_setup, unique_roles_added, MAFIA_REGULAR)
|
||||
mafiareg_left--
|
||||
else if(mafiaspe_left)
|
||||
add_setup_role(random_setup, MAFIA_SPECIAL)
|
||||
add_setup_role(random_setup, unique_roles_added, MAFIA_SPECIAL)
|
||||
mafiaspe_left--
|
||||
else if(killing_role)
|
||||
add_setup_role(random_setup, NEUTRAL_KILL)
|
||||
killing_role--
|
||||
else if(neutral_killing_role)
|
||||
add_setup_role(random_setup, unique_roles_added, NEUTRAL_KILL)
|
||||
neutral_killing_role--
|
||||
else
|
||||
add_setup_role(random_setup, NEUTRAL_DISRUPT)
|
||||
add_setup_role(random_setup, unique_roles_added, NEUTRAL_DISRUPT)
|
||||
debug = random_setup
|
||||
return random_setup
|
||||
|
||||
/**
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one. unique roles can only get added once.
|
||||
*/
|
||||
/datum/mafia_controller/proc/add_setup_role(setup_list, wanted_role_type)
|
||||
/datum/mafia_controller/proc/add_setup_role(setup_list, banned_roles, wanted_role_type)
|
||||
var/list/role_type_paths = list()
|
||||
for(var/path in typesof(/datum/mafia_role))
|
||||
var/datum/mafia_role/instance = path
|
||||
if(initial(instance.role_type) == wanted_role_type)
|
||||
if(initial(instance.role_type) == wanted_role_type && !(path in banned_roles))
|
||||
role_type_paths += instance
|
||||
|
||||
var/mafia_path = pick(role_type_paths)
|
||||
@@ -880,6 +913,8 @@
|
||||
setup_list[found_role] += 1
|
||||
return
|
||||
setup_list[mafia_path] = 1
|
||||
if(initial(mafia_path_type.role_flags) & ROLE_UNIQUE) //check to see if we should no longer consider this okay to add to the game
|
||||
banned_roles += mafia_path
|
||||
|
||||
/**
|
||||
* Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.
|
||||
@@ -893,6 +928,8 @@
|
||||
var/list/setup = custom_setup
|
||||
if(!setup.len)
|
||||
req_players = max_player //MAFIA_MAX_PLAYER_COUNT
|
||||
else if(low_pop_mode)
|
||||
req_players = required_player
|
||||
else
|
||||
req_players = assoc_value_sum(setup)
|
||||
|
||||
@@ -909,10 +946,10 @@
|
||||
GLOB.mafia_signup -= key //not valid to play when we checked so remove them from signups
|
||||
|
||||
//if there were not enough players, don't start. we already trimmed the list to now hold only valid signups
|
||||
|
||||
if(length(possible_keys) < req_players)
|
||||
return
|
||||
else //hacky implementation of max players
|
||||
req_players = clamp(length(possible_keys), 1, max_player)
|
||||
req_players = clamp(length(possible_keys), required_player, max_player)
|
||||
|
||||
//if there were too many players, still start but only make filtered keys as big as it needs to be (cut excess)
|
||||
//also removes people who do get into final player list from the signup so they have to sign up again when game ends
|
||||
@@ -923,8 +960,8 @@
|
||||
//small message about not getting into this game for clarity on why they didn't get in
|
||||
for(var/unpicked in possible_keys)
|
||||
var/client/unpicked_client = GLOB.directory[unpicked]
|
||||
to_chat(unpicked_client, "<span class='danger'>Sorry, the starting mafia game has too many players and you were not picked.</span>")
|
||||
to_chat(unpicked_client, "<span class='warning'>You're still signed up, getting messages from the current round, and have another chance to join when the one starting now finishes.</span>")
|
||||
to_chat(unpicked_client, span_danger("Sorry, the starting mafia game has too many players and you were not picked."))
|
||||
to_chat(unpicked_client, span_warning("You're still signed up, getting messages from the current round, and have another chance to join when the one starting now finishes."))
|
||||
|
||||
if(!setup.len) //don't actually have one yet, so generate a max player random setup. it's good to do this here instead of above so it doesn't generate one every time a game could possibly start.
|
||||
setup = generate_random_setup()
|
||||
|
||||
Reference in New Issue
Block a user