Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Festival Sect Expansion: New Tunes, New Rites, Cogitandi Fidis #944

Merged
merged 2 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/__DEFINES/dcs/signals/signals_music.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// /datum/song signals

///sent to the instrument when a song starts playing
///sent to the instrument when a song starts playing: (datum/starting_song, atom/player)
#define COMSIG_INSTRUMENT_START "instrument_start"
///sent to the instrument when a song stops playing
#define COMSIG_INSTRUMENT_END "instrument_end"
Expand Down
3 changes: 3 additions & 0 deletions code/__DEFINES/religion.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#define ALIGNMENT_NEUT "neutral"
#define ALIGNMENT_EVIL "evil"

///how many lines multiplied by tempo should at least be higher than this. Makes people have to choose a long enough song to get the final effect.
#define FESTIVAL_SONG_LONG_ENOUGH 170

/// the probability, when not overridden by sects, for a bible's bless effect to trigger on a smack
#define DEFAULT_SMACK_CHANCE 60

Expand Down
50 changes: 35 additions & 15 deletions code/datums/components/religious_tool.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
*/
/datum/component/religious_tool
dupe_mode = COMPONENT_DUPE_UNIQUE
dupe_mode = COMPONENT_DUPE_HIGHLANDER
/// Enables access to the global sect directly
var/datum/religion_sect/easy_access_sect
/// Prevents double selecting sects
Expand All @@ -14,19 +14,32 @@
/// The rite currently being invoked
var/datum/religion_rites/performing_rite
///Sets the type for catalyst
var/catalyst_type = /obj/item/book/bible
var/obj/item/catalyst_type = /obj/item/book/bible
///Enables overide of COMPONENT_NO_AFTERATTACK, not recommended as it means you can potentially cause damage to the item using the catalyst.
var/force_catalyst_afterattack = FALSE
///Callback provided to the tool for after a sect is chosen
var/datum/callback/after_sect_select_cb
///Optional argument. If a positive value, each invocation will lower charges, and the component will delete without any more charges
var/charges
///If a typecache is provided, only types of rites in the cache can be invoked.
var/list/rite_types_allowlist

/datum/component/religious_tool/Initialize(_flags = ALL, _force_catalyst_afterattack = FALSE, _after_sect_select_cb, override_catalyst_type)
/datum/component/religious_tool/Initialize(
operation_flags = ALL,
force_catalyst_afterattack = FALSE,
after_sect_select_cb = null,
catalyst_type = /obj/item/book/bible,
charges = -1,
rite_types_allowlist = null,
)
. = ..()
SetGlobalToLocal() //attempt to connect on start in case one already exists!
operation_flags = _flags
force_catalyst_afterattack = _force_catalyst_afterattack
after_sect_select_cb = _after_sect_select_cb
if(override_catalyst_type)
catalyst_type = override_catalyst_type
src.operation_flags = operation_flags
src.force_catalyst_afterattack = force_catalyst_afterattack
src.after_sect_select_cb = after_sect_select_cb
src.catalyst_type = catalyst_type
src.charges = charges
src.rite_types_allowlist = rite_types_allowlist
RegisterSignal(SSdcs, COMSIG_RELIGIOUS_SECT_CHANGED, PROC_REF(SetGlobalToLocal))
RegisterSignal(SSdcs, COMSIG_RELIGIOUS_SECT_RESET, PROC_REF(on_sect_reset))

Expand Down Expand Up @@ -150,6 +163,9 @@
else
to_chat(user, "<span class='warning'>You are not holy, and therefore cannot perform rites.")
return
if(rite_types_allowlist && !is_path_in_list(path, rite_types_allowlist))
to_chat(user, span_warning("This cannot perform that kind of rite."))
return
if(performing_rite)
to_chat(user, "<span class='notice'>There is a rite currently being performed here already.")
return
Expand All @@ -159,13 +175,17 @@
performing_rite = new path(parent)
if(!performing_rite.perform_rite(user, parent))
QDEL_NULL(performing_rite)
return
performing_rite.invoke_effect(user, parent)
easy_access_sect.adjust_favor(-performing_rite.favor_cost)
if(performing_rite.auto_delete)
QDEL_NULL(performing_rite)
else
performing_rite.invoke_effect(user, parent)
easy_access_sect.adjust_favor(-performing_rite.favor_cost)
if(performing_rite.auto_delete)
QDEL_NULL(performing_rite)
else
performing_rite = null
performing_rite = null
if(charges)
charges--
if(!charges)
qdel(src)

/**
* Generates a list of available sects to the user. Intended to support custom-availability sects.
Expand Down Expand Up @@ -231,7 +251,7 @@

if(!can_i_see)
return
examine_list += span_notice("Use a bible to interact with this.")
examine_list += span_notice("Use a [catalyst_type::name] to interact with this.")
if(isnull(easy_access_sect))
if(operation_flags & RELIGION_TOOL_SECTSELECT)
examine_list += span_notice("This looks like it can be used to select a sect.")
Expand Down
9 changes: 3 additions & 6 deletions code/datums/components/smooth_tunes.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
///how many lines multiplied by tempo should at least be higher than this.
#define LONG_ENOUGH_SONG 220

///Smooth tunes component! Applied to musicians to give the songs they play special effects, according to a rite!
///Comes with BARTICLES!!!
/datum/component/smooth_tunes
Expand Down Expand Up @@ -47,7 +44,7 @@
if(istype(starting_song.parent, /obj/structure/musician))
return //TODO: make stationary instruments work with no hiccups

if(starting_song.lines.len * starting_song.tempo > LONG_ENOUGH_SONG)
if(starting_song.lines.len * starting_song.tempo > FESTIVAL_SONG_LONG_ENOUGH)
viable_for_final_effect = TRUE
else
to_chat(parent, span_warning("This song is too short, so it won't include the song finishing effect."))
Expand All @@ -56,6 +53,8 @@
if(linked_songtuner_rite.song_start_message)
starting_song.parent.visible_message(linked_songtuner_rite.song_start_message)

linked_songtuner_rite.performer_start_effect(parent, starting_song)

///prevent more songs from being blessed concurrently, mob signal
UnregisterSignal(parent, COMSIG_ATOM_STARTING_INSTRUMENT)
///and hook into the instrument this time, preventing other weird exploity stuff.
Expand Down Expand Up @@ -112,5 +111,3 @@
linked_songtuner_rite.song_effect(listener, parent)
else
stop_singing()

#undef LONG_ENOUGH_SONG
19 changes: 19 additions & 0 deletions code/datums/status_effects/song_effects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,22 @@

/datum/status_effect/song/antimagic/get_examine_text()
return span_notice("[owner.p_They()] seem[owner.p_s()] to be covered in a dull, grey aura.")

/datum/status_effect/song/light
id = "light_song"
status_type = STATUS_EFFECT_REFRESH
duration = 1 MINUTES
aura_desc = "bright"
/// lighting object that makes owner glow
var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj

/datum/status_effect/song/light/on_apply()
mob_light_obj = owner.mob_light(3, color = LIGHT_COLOR_DIM_YELLOW)
playsound(owner, 'sound/weapons/fwoosh.ogg', 75, FALSE)
return TRUE

/datum/status_effect/song/light/on_remove()
QDEL_NULL(mob_light_obj)

/datum/status_effect/song/light_song/get_examine_text()
return span_notice("[owner.p_They()] seem[owner.p_s()] to be covered in a glowing aura.")
15 changes: 15 additions & 0 deletions code/game/objects/effects/particles/note_particles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@
"sleepy_9" = 2, //sleepy theme specific
"sleepy_10" = 2, //sleepy theme specific
)

/particles/musical_notes/light
icon = 'icons/effects/particles/notes/note_light.dmi'
icon_state = list(
"power_1" = 1,
"power_2" = 1,
"power_3" = 1,
"power_4" = 1,
"power_5" = 1,
"power_6" = 1,
"power_7" = 1,
"power_8" = 1,
"power_9" = 2, //light theme specific
"power_10" = 2, //light theme specific
)
4 changes: 2 additions & 2 deletions code/modules/instruments/piano_synth.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
RegisterSignal(src, COMSIG_INSTRUMENT_END, PROC_REF(update_icon_for_playing_music))

// Called by a component signal to update musical note VFX for songs playing while worn.
/obj/item/instrument/piano_synth/headphones/proc/update_icon_for_playing_music()
/obj/item/instrument/piano_synth/headphones/proc/update_icon_for_playing_music(datum/source, datum/starting_song, atom/player)
SIGNAL_HANDLER
update_appearance()

Expand Down Expand Up @@ -129,7 +129,7 @@
/obj/item/circuit_component/synth/proc/start_playing(datum/port/input/port)
synth.song.start_playing(src)

/obj/item/circuit_component/synth/proc/on_song_start()
/obj/item/circuit_component/synth/proc/on_song_start(datum/source, datum/starting_song, atom/player)
SIGNAL_HANDLER
is_playing.set_output(TRUE)
started_playing.set_output(COMPONENT_SIGNAL)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/instruments/songs/_song.dm
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@
//we can not afford to runtime, since we are going to be doing sound channel reservations and if we runtime it means we have a channel allocation leak.
//wrap the rest of the stuff to ensure stop_playing() is called.
do_hearcheck()
SEND_SIGNAL(parent, COMSIG_INSTRUMENT_START, src)
SEND_SIGNAL(parent, COMSIG_INSTRUMENT_START, src, user)
SEND_SIGNAL(user, COMSIG_ATOM_STARTING_INSTRUMENT, src)
elapsed_delay = 0
delay_by = 0
Expand Down
29 changes: 29 additions & 0 deletions code/modules/religion/festival/festival_violin.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/obj/item/instrument/violin/festival
name = "Cogitandi Fidis"
desc = "A violin that holds a special interest in the songs played from its strings."
icon_state = "holy_violin"
inhand_icon_state = "holy_violin"

/obj/item/instrument/violin/festival/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_INSTRUMENT_START, PROC_REF(on_instrument_start))

/// signal fired when the festival instrument starts to play.
/obj/item/instrument/violin/festival/proc/on_instrument_start(datum/source, datum/song/starting_song, atom/player)
SIGNAL_HANDLER

if(!starting_song || !isliving(player))
return
analyze_song(starting_song, player)

///Reports some relevant information when the song begins playing.
/obj/item/instrument/violin/festival/proc/analyze_song(datum/song/song, mob/living/playing_song)
var/list/analysis = list()
//check tempo and lines
var/song_length = song.lines.len * song.tempo
analysis += span_revenbignotice("[src] speaks to you...")
analysis += span_revennotice("\"This song has <b>[song.lines.len]</b> lines and a tempo of <b>[song.tempo]</b>.\"")
analysis += span_revennotice("\"Multiplying these together gives a song length of <b>[song_length]</b>.\"")
analysis += span_revennotice("\"To get a bonus effect from [GLOB.deity] upon finishing a performance, you need a song length of <b>[FESTIVAL_SONG_LONG_ENOUGH]</b>.\"")

to_chat(playing_song, analysis.Join("\n"))
87 changes: 87 additions & 0 deletions code/modules/religion/festival/instrument_rites.dm
Original file line number Diff line number Diff line change
@@ -1,9 +1,64 @@
/datum/religion_rites/holy_violin
name = "Cogitandi Fidis"
desc = "Creates a holy violin that can analyze songs played from it."
ritual_length = 6 SECONDS
ritual_invocations = list("A servant of jubilee is needed ...")
invoke_msg = "... A great mind for musical matters!"
favor_cost = 20 //you only need one

/datum/religion_rites/holy_violin/invoke_effect(mob/living/user, atom/religious_tool)
. = ..()
var/turf/tool_turf = get_turf(religious_tool)
var/obj/item/instrument/violin/fidis = new /obj/item/instrument/violin/festival(get_turf(religious_tool))
fidis.visible_message(span_notice("[fidis] appears!"))
playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE)

/datum/religion_rites/portable_song_tuning
name = "Portable Song Tuning"
desc = "Empowers an instrument on the table to work as a portable altar for tuning songs. Will need to be recharged after 5 rites."
ritual_length = 6 SECONDS
ritual_invocations = list("Allow me to bring your holy inspirations ...")
invoke_msg = "... And send them with the winds my tunes ride with!"
favor_cost = 10
///instrument to empower
var/obj/item/instrument/instrument_target

/datum/religion_rites/portable_song_tuning/perform_rite(mob/living/user, atom/religious_tool)
for(var/obj/item/instrument/could_empower in get_turf(religious_tool))
instrument_target = could_empower
return ..()
to_chat(user, span_warning("You need to place an instrument on [religious_tool] to do this!"))
return FALSE

/datum/religion_rites/portable_song_tuning/invoke_effect(mob/living/user, atom/movable/religious_tool)
..()
var/obj/item/instrument/empower_target = instrument_target
var/turf/tool_turf = get_turf(religious_tool)
instrument_target = null
if(QDELETED(empower_target) || !(tool_turf == empower_target.loc)) //check if the instrument is still there
to_chat(user, span_warning("Your target left the altar!"))
return FALSE
empower_target.visible_message(span_notice("[empower_target] glows for a moment."))
playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE)
var/list/allowed_rites_from_bible = subtypesof(/datum/religion_rites/song_tuner)
empower_target.AddComponent( \
/datum/component/religious_tool, \
operation_flags = RELIGION_TOOL_INVOKE, \
force_catalyst_afterattack = FALSE, \
after_sect_select_cb = null, \
catalyst_type = /obj/item/book/bible, \
charges = 5, \
rite_types_allowlist = allowed_rites_from_bible, \
)
return TRUE

///prototype for rites that tune a song.
/datum/religion_rites/song_tuner
name = "Tune Song"
desc = "this is a prototype."
ritual_length = 10 SECONDS
favor_cost = 10
auto_delete = FALSE
///if repeats count as continuations instead of a song's end, TRUE
var/repeats_okay = TRUE
///personal message sent to the chaplain as feedback for their chosen song
Expand All @@ -20,6 +75,16 @@
to_chat(user, span_notice(song_invocation_message))
user.AddComponent(/datum/component/smooth_tunes, src, repeats_okay, particles_path, glow_color)

/**
* Song effect applied when the performer starts playing.
*
* Arguments:
* * performer - A human starting the song
* * song_source - parent of the smooth_tunes component. This is limited to the compatible items of said component, which currently includes mobs and objects so we'll have to type appropriately.
*/
/datum/religion_rites/song_tuner/proc/performer_start_effect(mob/living/carbon/human/performer, atom/song_source)
return

/**
* Perform the song effect.
*
Expand Down Expand Up @@ -60,6 +125,28 @@
/datum/religion_rites/song_tuner/evangelism/finish_effect(mob/living/carbon/human/listener, atom/song_source)
listener.add_mood_event("blessing", /datum/mood_event/blessing)

/datum/religion_rites/song_tuner/light
name = "Illuminating Solo"
desc = "Sing a bright song, lighting up the area around you. At the end of the song, you'll give some illumination to listeners."
particles_path = /particles/musical_notes/light
song_invocation_message = "You've prepared a bright song!"
song_start_message = span_notice("This music simply glows!")
glow_color = "#fcff44"
repeats_okay = FALSE
favor_cost = 0
/// lighting object that makes chaplain glow
var/obj/effect/dummy/lighting_obj/moblight/performer_light_obj

/datum/religion_rites/song_tuner/light/performer_start_effect(mob/living/carbon/human/performer, atom/song_source)
performer_light_obj = performer.mob_light(8, color = LIGHT_COLOR_DIM_YELLOW)

/datum/religion_rites/song_tuner/light/Destroy()
QDEL_NULL(performer_light_obj)
. = ..()

/datum/religion_rites/song_tuner/light/finish_effect(mob/living/carbon/human/listener, atom/song_source)
listener.apply_status_effect(/datum/status_effect/song/light)

/datum/religion_rites/song_tuner/nullwave
name = "Nullwave Vibrato"
desc = "Sing a dull song, protecting those who listen from magic."
Expand Down
3 changes: 3 additions & 0 deletions code/modules/religion/religion_sects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,10 @@
alignment = ALIGNMENT_GOOD
candle_overlay = FALSE
rites_list = list(
/datum/religion_rites/holy_violin,
/datum/religion_rites/portable_song_tuning,
/datum/religion_rites/song_tuner/evangelism,
/datum/religion_rites/song_tuner/light,
/datum/religion_rites/song_tuner/nullwave,
/datum/religion_rites/song_tuner/pain,
/datum/religion_rites/song_tuner/lullaby,
Expand Down
Binary file added icons/effects/particles/notes/note_light.dmi
Binary file not shown.
Binary file modified icons/mob/inhands/equipment/instruments_lefthand.dmi
Binary file not shown.
Binary file modified icons/mob/inhands/equipment/instruments_righthand.dmi
Binary file not shown.
Binary file modified icons/obj/art/musician.dmi
Binary file not shown.
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -5467,6 +5467,7 @@
#include "code\modules\religion\rites.dm"
#include "code\modules\religion\burdened\burdened_trauma.dm"
#include "code\modules\religion\burdened\psyker.dm"
#include "code\modules\religion\festival\festival_violin.dm"
#include "code\modules\religion\festival\instrument_rites.dm"
#include "code\modules\religion\honorbound\honorbound_rites.dm"
#include "code\modules\religion\honorbound\honorbound_trauma.dm"
Expand Down
Loading