Merge pull request #16471 from Core0verload/events

Adds minimal players requirements for random events
This commit is contained in:
duncathan salt
2016-03-31 12:14:44 -06:00
27 changed files with 219 additions and 154 deletions
+8 -2
View File
@@ -332,13 +332,19 @@
for(var/client/C in show_to)
C.images -= I
/proc/get_active_player_count()
/proc/get_active_player_count(var/alive_check = 0, var/afk_check = 0, var/human_check = 0)
// Get active players who are playing in the round
var/active_players = 0
for(var/i = 1; i <= player_list.len; i++)
var/mob/M = player_list[i]
if(M && M.client)
if(istype(M, /mob/new_player)) // exclude people in the lobby
if(alive_check && M.stat)
continue
else if(afk_check && M.client.is_afk())
continue
else if(human_check && !istype(M, /mob/living/carbon/human))
continue
else if(istype(M, /mob/new_player)) // exclude people in the lobby
continue
else if(isobserver(M)) // Ghosts are fine if they were playing once (didn't start as observers)
var/mob/dead/observer/O = M
+13 -1
View File
@@ -90,7 +90,6 @@
var/list/probabilities = list() // relative probability of each mode
var/humans_need_surnames = 0
var/allow_random_events = 0 // enables random events mid-round when set to 1
var/allow_ai = 0 // allow ai job
var/forbid_secborg = 0 // disallow secborg module to be chosen.
var/panic_bunker = 0 // prevents new people it hasn't seen before from connecting
@@ -187,6 +186,13 @@
var/maprotation = 1
var/maprotatechancedelta = 0.75
// Enables random events mid-round when set to 1
var/allow_random_events = 0
// Multipliers for random events minimal starting time and minimal players amounts
var/events_min_time_mul = 1
var/events_min_players_mul = 1
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
@@ -510,6 +516,12 @@
config.allow_latejoin_antagonists = 1
if("allow_random_events")
config.allow_random_events = 1
if("events_min_time_mul")
config.events_min_time_mul = text2num(value)
if("events_min_players_mul")
config.events_min_players_mul = text2num(value)
if("minimal_access_threshold")
config.minimal_access_threshold = text2num(value)
if("jobs_have_minimal_access")
+6 -20
View File
@@ -70,19 +70,14 @@ var/datum/subsystem/events/SSevent
// if(E) E.runEvent()
return
var/gamemode = ticker.mode.config_tag
var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
// Only alive, non-AFK human players count towards this.
var/sum_of_weights = 0
for(var/datum/round_event_control/E in control)
if(E.occurrences >= E.max_occurrences)
if(!E.canSpawnEvent(players_amt, gamemode))
continue
if(E.earliest_start >= world.time)
continue
if(E.gamemode_blacklist.len && (ticker.mode.config_tag in E.gamemode_blacklist))
continue
if(E.gamemode_whitelist.len && !(ticker.mode.config_tag in E.gamemode_whitelist))
continue
if(E.holidayID)
if(!holidays || !holidays[E.holidayID])
continue
if(E.weight < 0) //for round-start events etc.
if(E.runEvent() == PROCESS_KILL)
E.max_occurrences = 0
@@ -96,17 +91,8 @@ var/datum/subsystem/events/SSevent
sum_of_weights = rand(0,sum_of_weights) //reusing this variable. It now represents the 'weight' we want to select
for(var/datum/round_event_control/E in control)
if(E.occurrences >= E.max_occurrences)
if(!E.canSpawnEvent(players_amt, gamemode))
continue
if(E.earliest_start >= world.time)
continue
if(E.gamemode_blacklist.len && (ticker.mode.config_tag in E.gamemode_blacklist))
continue
if(E.gamemode_whitelist.len && !(ticker.mode.config_tag in E.gamemode_whitelist))
continue
if(E.holidayID)
if(!holidays || !holidays[E.holidayID])
continue
sum_of_weights -= E.weight
if(sum_of_weights <= 0) //we've hit our goal
@@ -1,127 +1,153 @@
//this datum is used by the events controller to dictate how it selects events
/datum/round_event_control
var/name //The name human-readable name of the event
var/typepath //The typepath of the event datum /datum/round_event
var/weight = 10 //The weight this event has in the random-selection process.
//Higher weights are more likely to be picked.
//10 is the default weight. 20 is twice more likely; 5 is half as likely as this default.
var/earliest_start = 12000 //The earliest world.time that an event can start (round-duration in deciseconds) default: 20 mins
var/occurrences = 0 //How many times this event has occured
var/max_occurrences = 20 //The maximum number of times this event can occur (naturally), it can still be forced.
//By setting this to 0 you can effectively disable an event.
var/holidayID = "" //string which should be in the SSevents.holidays list if you wish this event to be holiday-specific
//anything with a (non-null) holidayID which does not match holiday, cannot run.
var/wizardevent = 0
var/alertadmins = 1 //should we let the admins know this event is firing
//should be disabled on events that fire a lot
var/list/gamemode_blacklist = list() // Event won't happen in these gamemodes
var/list/gamemode_whitelist = list() // Event will happen ONLY in these gamemodes if not empty
/datum/round_event_control/wizard
wizardevent = 1
/datum/round_event_control/proc/runEvent()
if(!ispath(typepath,/datum/round_event))
return PROCESS_KILL
var/datum/round_event/E = new typepath()
E.control = src
feedback_add_details("event_ran","[E]")
occurrences++
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
return E
/datum/round_event //NOTE: Times are measured in master controller ticks!
var/processing = 1
var/datum/round_event_control/control
var/startWhen = 0 //When in the lifetime to call start().
var/announceWhen = 0 //When in the lifetime to call announce(). Set an event's announceWhen to >0 if there is an announcement.
var/endWhen = 0 //When in the lifetime the event should end.
var/activeFor = 0 //How long the event has existed. You don't need to change this.
//Called first before processing.
//Allows you to setup your event, such as randomly
//setting the startWhen and or announceWhen variables.
//Only called once.
//EDIT: if there's anything you want to override within the new() call, it will not be overridden by the time this proc is called.
//It will only have been overridden by the time we get to announce() start() tick() or end() (anything but setup basically).
//This is really only for setting defaults which can be overridden later when New() finishes.
/datum/round_event/proc/setup()
return
//Called when the tick is equal to the startWhen variable.
//Allows you to start before announcing or vice versa.
//Only called once.
/datum/round_event/proc/start()
return
//Called when the tick is equal to the announceWhen variable.
//Allows you to announce before starting or vice versa.
//Only called once.
/datum/round_event/proc/announce()
return
//Called on or after the tick counter is equal to startWhen.
//You can include code related to your event or add your own
//time stamped events.
//Called more than once.
/datum/round_event/proc/tick()
return
//Called on or after the tick is equal or more than endWhen
//You can include code related to the event ending.
//Do not place spawn() in here, instead use tick() to check for
//the activeFor variable.
//For example: if(activeFor == myOwnVariable + 30) doStuff()
//Only called once.
/datum/round_event/proc/end()
return
//Do not override this proc, instead use the appropiate procs.
//This proc will handle the calls to the appropiate procs.
/datum/round_event/process()
if(!processing)
return
if(activeFor == startWhen)
start()
if(activeFor == announceWhen)
announce()
if(startWhen < activeFor && activeFor < endWhen)
tick()
if(activeFor == endWhen)
end()
// Everything is done, let's clean up.
if(activeFor >= endWhen && activeFor >= announceWhen && activeFor >= startWhen)
kill()
activeFor++
//Garbage collects the event by removing it from the global events list,
//which should be the only place it's referenced.
//Called when start(), announce() and end() has all been called.
/datum/round_event/proc/kill()
SSevent.running -= src
//Sets up the event then adds the event to the the list of running events
/datum/round_event/New()
setup()
SSevent.running += src
//this datum is used by the events controller to dictate how it selects events
/datum/round_event_control
var/name //The human-readable name of the event
var/typepath //The typepath of the event datum /datum/round_event
var/weight = 10 //The weight this event has in the random-selection process.
//Higher weights are more likely to be picked.
//10 is the default weight. 20 is twice more likely; 5 is half as likely as this default.
var/earliest_start = 12000 //The earliest world.time that an event can start (round-duration in deciseconds) default: 20 mins
var/min_players = 0 //The minimum amount of alive, non-AFK human players on server required to start the event.
var/occurrences = 0 //How many times this event has occured
var/max_occurrences = 20 //The maximum number of times this event can occur (naturally), it can still be forced.
//By setting this to 0 you can effectively disable an event.
var/holidayID = "" //string which should be in the SSevents.holidays list if you wish this event to be holiday-specific
//anything with a (non-null) holidayID which does not match holiday, cannot run.
var/wizardevent = 0
var/alertadmins = 1 //should we let the admins know this event is firing
//should be disabled on events that fire a lot
var/list/gamemode_blacklist = list() // Event won't happen in these gamemodes
var/list/gamemode_whitelist = list() // Event will happen ONLY in these gamemodes if not empty
/datum/round_event_control/New()
..()
if(config && !wizardevent) // Magic is unaffected by configs
earliest_start = Ceiling(earliest_start * config.events_min_time_mul)
min_players = Ceiling(min_players * config.events_min_players_mul)
/datum/round_event_control/wizard
wizardevent = 1
// Checks if the event can be spawned. Used by event controller and "false alarm" event.
// Admin-created events override this.
/datum/round_event_control/proc/canSpawnEvent(var/players_amt, var/gamemode)
if(occurrences >= max_occurrences)
return FALSE
if(earliest_start >= world.time)
return FALSE
if(players_amt < min_players)
return FALSE
if(gamemode_blacklist.len && (gamemode in gamemode_blacklist))
return FALSE
if(gamemode_whitelist.len && !(gamemode in gamemode_whitelist))
return FALSE
if(holidayID && (!SSevent.holidays || !SSevent.holidays[holidayID]))
return FALSE
return TRUE
/datum/round_event_control/proc/runEvent()
if(!ispath(typepath,/datum/round_event))
return PROCESS_KILL
var/datum/round_event/E = new typepath()
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
E.control = src
feedback_add_details("event_ran","[E]")
occurrences++
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
return E
/datum/round_event //NOTE: Times are measured in master controller ticks!
var/processing = 1
var/datum/round_event_control/control
var/startWhen = 0 //When in the lifetime to call start().
var/announceWhen = 0 //When in the lifetime to call announce(). Set an event's announceWhen to >0 if there is an announcement.
var/endWhen = 0 //When in the lifetime the event should end.
var/activeFor = 0 //How long the event has existed. You don't need to change this.
var/current_players = 0 //Amount of of alive, non-AFK human players on server at the time of event start
//Called first before processing.
//Allows you to setup your event, such as randomly
//setting the startWhen and or announceWhen variables.
//Only called once.
//EDIT: if there's anything you want to override within the new() call, it will not be overridden by the time this proc is called.
//It will only have been overridden by the time we get to announce() start() tick() or end() (anything but setup basically).
//This is really only for setting defaults which can be overridden later when New() finishes.
/datum/round_event/proc/setup()
return
//Called when the tick is equal to the startWhen variable.
//Allows you to start before announcing or vice versa.
//Only called once.
/datum/round_event/proc/start()
return
//Called when the tick is equal to the announceWhen variable.
//Allows you to announce before starting or vice versa.
//Only called once.
/datum/round_event/proc/announce()
return
//Called on or after the tick counter is equal to startWhen.
//You can include code related to your event or add your own
//time stamped events.
//Called more than once.
/datum/round_event/proc/tick()
return
//Called on or after the tick is equal or more than endWhen
//You can include code related to the event ending.
//Do not place spawn() in here, instead use tick() to check for
//the activeFor variable.
//For example: if(activeFor == myOwnVariable + 30) doStuff()
//Only called once.
/datum/round_event/proc/end()
return
//Do not override this proc, instead use the appropiate procs.
//This proc will handle the calls to the appropiate procs.
/datum/round_event/process()
if(!processing)
return
if(activeFor == startWhen)
start()
if(activeFor == announceWhen)
announce()
if(startWhen < activeFor && activeFor < endWhen)
tick()
if(activeFor == endWhen)
end()
// Everything is done, let's clean up.
if(activeFor >= endWhen && activeFor >= announceWhen && activeFor >= startWhen)
kill()
activeFor++
//Garbage collects the event by removing it from the global events list,
//which should be the only place it's referenced.
//Called when start(), announce() and end() has all been called.
/datum/round_event/proc/kill()
SSevent.running -= src
//Sets up the event then adds the event to the the list of running events
/datum/round_event/New()
setup()
SSevent.running += src
return ..()
+1
View File
@@ -4,6 +4,7 @@
weight = 5
max_occurrences = 1
min_players = 5
earliest_start = 18000 // 30 min
gamemode_blacklist = list("nuclear","wizard","revolution","abduction")
+2
View File
@@ -2,6 +2,8 @@
name = "Alien Infestation"
typepath = /datum/round_event/alien_infestation
weight = 5
min_players = 10
max_occurrences = 1
/datum/round_event/alien_infestation
+2
View File
@@ -1,6 +1,8 @@
/datum/round_event_control/anomaly
name = "Anomaly: Energetic Flux"
typepath = /datum/round_event/anomaly
min_players = 1
max_occurrences = 0 //This one probably shouldn't occur! It'd work, but it wouldn't be very fun.
weight = 15
+2
View File
@@ -1,6 +1,8 @@
/datum/round_event_control/anomaly/anomaly_flux
name = "Anomaly: Hyper-Energetic Flux"
typepath = /datum/round_event/anomaly/anomaly_flux
min_players = 10
max_occurrences = 5
weight = 20
+2
View File
@@ -1,6 +1,8 @@
/datum/round_event_control/anomaly/anomaly_vortex
name = "Anomaly: Vortex"
typepath = /datum/round_event/anomaly/anomaly_vortex
min_players = 20
max_occurrences = 2
weight = 5
+1
View File
@@ -4,6 +4,7 @@
weight = 5
max_occurrences = 1
min_players = 20
earliest_start = 18000 //30 minutes
gamemode_blacklist = list("blob") //Just in case a blob survives that long
@@ -2,6 +2,8 @@
name = "Brand Intelligence"
typepath = /datum/round_event/brand_intelligence
weight = 5
min_players = 15
max_occurrences = 1
/datum/round_event/brand_intelligence
+1
View File
@@ -2,6 +2,7 @@
name = "Carp Migration"
typepath = /datum/round_event/carp_migration
weight = 15
min_players = 2
earliest_start = 6000
max_occurrences = 6
+1
View File
@@ -2,6 +2,7 @@
name = "Disease Outbreak"
typepath = /datum/round_event/disease_outbreak
max_occurrences = 1
min_players = 10
weight = 5
/datum/round_event/disease_outbreak
+1
View File
@@ -2,6 +2,7 @@
name = "Electrical Storm"
typepath = /datum/round_event/electrical_storm
earliest_start = 6000
min_players = 5
weight = 40
alertadmins = 0
+6 -3
View File
@@ -10,11 +10,14 @@
/datum/round_event/falsealarm/announce()
var/list/events_list = list()
var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
var/gamemode = ticker.mode.config_tag
for(var/datum/round_event_control/E in SSevent.control)
if(E.holidayID || E.wizardevent)
continue
if(E.earliest_start >= world.time)
if(!E.canSpawnEvent(players_amt, gamemode))
continue
var/datum/round_event/event = E.typepath
if(initial(event.announceWhen) <= 0)
continue
+1
View File
@@ -10,6 +10,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
/datum/round_event_control/immovable_rod
name = "Immovable Rod"
typepath = /datum/round_event/immovable_rod
min_players = 15
max_occurrences = 5
/datum/round_event/immovable_rod
+1
View File
@@ -5,6 +5,7 @@
name = "Ion Storm"
typepath = /datum/round_event/ion_storm
weight = 15
min_players = 2
/datum/round_event/ion_storm
var/botEmagChance = 10
@@ -3,6 +3,7 @@
typepath = /datum/round_event/mass_hallucination
weight = 7
max_occurrences = 2
min_players = 1
/datum/round_event/mass_hallucination/start()
for(var/mob/living/carbon/C in living_mob_list)
+1
View File
@@ -2,6 +2,7 @@
name = "Meteor Wave"
typepath = /datum/round_event/meteor_wave
weight = 5
min_players = 5
max_occurrences = 3
/datum/round_event/meteor_wave
+1
View File
@@ -2,6 +2,7 @@
name = "Portal Storm: Syndicate Shocktroops"
typepath = /datum/round_event/portal_storm/syndicate_shocktroop
weight = 2
min_players = 15
earliest_start = 18000
/datum/round_event/portal_storm/syndicate_shocktroop
+1
View File
@@ -2,6 +2,7 @@
name = "Prison Break"
typepath = /datum/round_event/prison_break
max_occurrences = 2
min_players = 5
/datum/round_event/prison_break
announceWhen = 50
+1
View File
@@ -3,6 +3,7 @@
typepath = /datum/round_event/spacevine
weight = 15
max_occurrences = 3
min_players = 10
/datum/round_event/spacevine/start()
var/list/turfs = list() //list of all the empty floor turfs in the hallway areas
@@ -3,6 +3,7 @@
typepath = /datum/round_event/spider_infestation
weight = 5
max_occurrences = 1
min_players = 15
/datum/round_event/spider_infestation
announceWhen = 400
@@ -4,6 +4,7 @@
weight = 20
max_occurrences = 4
earliest_start = 6000
min_players = 5 // To make your chance of getting help a bit higher.
/datum/round_event/spontaneous_appendicitis/start()
for(var/mob/living/carbon/human/H in shuffle(living_mob_list))
+1
View File
@@ -3,6 +3,7 @@
typepath = /datum/round_event/wormholes
max_occurrences = 3
weight = 2
min_players = 2
/datum/round_event/wormholes
+8 -1
View File
@@ -179,10 +179,17 @@ ALLOW_LATEJOIN_ANTAGONISTS
#SHOW_GAME_TYPE_ODDS
### RANDOM EVENTS ###
## Comment this to disable random events during the round.
ALLOW_RANDOM_EVENTS
## Multiplier for earliest start time of dangerous events.
## Set to 0 to make dangerous events avaliable from round start.
EVENTS_MIN_TIME_MUL 1
## Multiplier for minimal player count (players = alive non-AFK humans) for dangerous events to start.
## Set to 0 to make dangerous events avaliable for all populations.
EVENTS_MIN_PLAYERS_MUL 1
### AI ###
+1 -1
View File
@@ -975,6 +975,7 @@
#include "code\modules\detectivework\footprints_and_rag.dm"
#include "code\modules\detectivework\scanner.dm"
#include "code\modules\emoji\emoji_parse.dm"
#include "code\modules\events\_event.dm"
#include "code\modules\events\abductor.dm"
#include "code\modules\events\alien_infestation.dm"
#include "code\modules\events\anomaly.dm"
@@ -991,7 +992,6 @@
#include "code\modules\events\disease_outbreak.dm"
#include "code\modules\events\dust.dm"
#include "code\modules\events\electrical_storm.dm"
#include "code\modules\events\event.dm"
#include "code\modules\events\false_alarm.dm"
#include "code\modules\events\immovable_rod.dm"
#include "code\modules\events\ion_storm.dm"