diff --git a/modular_ss220/antagonists/_antagonists.dme b/modular_ss220/antagonists/_antagonists.dme
index 95aa531b404b..f5c866a3bd7a 100644
--- a/modular_ss220/antagonists/_antagonists.dme
+++ b/modular_ss220/antagonists/_antagonists.dme
@@ -8,3 +8,10 @@
#include "code/configuration/antag_mix_configuration.dm"
#include "code/mind/memory_edit.dm"
#include "code/antag_mix/antag_mix.dm"
+#include "code/rave_wizard/rave_wizard_event.dm"
+#include "code/rave_wizard/summon_disco_ball.dm"
+#include "code/rave_wizard/dancing_field.dm"
+#include "code/rave_wizard/beer_missiles.dm"
+#include "code/rave_wizard/great_revelry.dm"
+#include "code/rave_wizard/rocker_touch.dm"
+#include "code/rave_wizard/datum/rave_wizard.dm"
diff --git a/modular_ss220/antagonists/code/mind/memory_edit.dm b/modular_ss220/antagonists/code/mind/memory_edit.dm
index 3ae318daf3ed..8dc49814e25c 100644
--- a/modular_ss220/antagonists/code/mind/memory_edit.dm
+++ b/modular_ss220/antagonists/code/mind/memory_edit.dm
@@ -7,6 +7,15 @@
. += _memory_edit_role_enabled(ROLE_BLOOD_BROTHER)
+/datum/mind/memory_edit_wizard(mob/living/carbon/human/H)
+ . = _memory_edit_header("wizard")
+ if(has_antag_datum(/datum/antagonist/wizard))
+ . += "WIZARD|no"
+ . += "
To lair, undress, dress up, let choose name, enrave."
+ else
+ . += "wizard|NO"
+
+ . += _memory_edit_role_enabled(ROLE_WIZARD)
/datum/mind/proc/clear_antag_datum(datum/antagonist/antag_datum_to_clear)
if(!has_antag_datum(antag_datum_to_clear))
@@ -31,4 +40,13 @@
if(!brother_antag_datum.admin_add(usr, src))
qdel(brother_antag_datum)
+ if(href_list["wizard"])
+ switch(href_list["wizard"])
+ if("enrave")
+ var/datum/antagonist/wizard/wizard = has_antag_datum(/datum/antagonist/wizard)
+ if(!istype(wizard))
+ return
+ add_antag_datum(/datum/antagonist/wizard/rave)
+ log_admin("[key_name(usr)] has enraved wizard [key_name(current)]")
+ message_admins("[key_name_admin(usr)] has enraved wizard [key_name_admin(current)]")
. = ..()
diff --git a/modular_ss220/antagonists/code/rave_wizard/beer_missiles.dm b/modular_ss220/antagonists/code/rave_wizard/beer_missiles.dm
new file mode 100644
index 000000000000..3a0b9ee201dd
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/beer_missiles.dm
@@ -0,0 +1,34 @@
+/datum/spell/projectile/magic_missile/beer
+ name = "Beer Missile"
+ desc = "This spell fires several, slow moving, magic beer bottles at nearby targets"
+ school = "evocation"
+ base_cooldown = 60
+ clothes_req = FALSE
+ invocation = "CERVISIA TORMENTUM"
+ invocation_type = "shout"
+ cooldown_min = 60 //35 deciseconds reduction per rank
+ proj_icon = 'icons/obj/drinks.dmi'
+ proj_icon_state = "beer"
+ proj_name = "A bottle of beer"
+ proj_lingering = 1
+ proj_type = "/obj/item/projectile/magic/magic_missile/beer"
+ proj_lifespan = 20
+ proj_step_delay = 5
+ proj_trail_icon = 'icons/obj/drinks.dmi'
+ proj_trail = 1
+ proj_trail_lifespan = 5
+ proj_trail_icon_state = "beer"
+ action_icon_state = "no_state"
+ action_background_icon_state = "missile"
+ action_icon = 'modular_ss220/antagonists/icons/rave.dmi'
+ sound = 'sound/magic/magic_missile.ogg'
+
+/obj/item/projectile/magic/magic_missile/beer
+ hitsound = "shatter"
+ var/debuff_effect_duration = 10 SECONDS
+
+/datum/spellbook_entry/beer_missile
+ name = "Magic beer missiles"
+ spell_type = /datum/spell/projectile/magic_missile/beer
+ category = "Rave"
+
diff --git a/modular_ss220/antagonists/code/rave_wizard/dancing_field.dm b/modular_ss220/antagonists/code/rave_wizard/dancing_field.dm
new file mode 100644
index 000000000000..d1323a221535
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/dancing_field.dm
@@ -0,0 +1,66 @@
+/datum/spell/aoe/conjure/timestop/dance
+ name = "Dance Time"
+ desc = "This spell makes everyone dance in it's range. Enchanted targets cannot attack, but projectiles harm as usual"
+ invocation = "DAN SIN FIVA"
+ action_icon_state = "no_state"
+ action_background_icon_state = "dance_field"
+ action_icon = 'modular_ss220/antagonists/icons/rave.dmi'
+ summon_lifespan = 100
+ summon_type = list(/obj/effect/timestop/dancing/wizard)
+
+/obj/effect/timestop/dancing
+ name = "Dancing field"
+ desc = "Feel the heat"
+ icon = 'modular_ss220/antagonists/icons/160x160.dmi'
+ icon_state = "dancing_ball"
+ var/sound_type = list('modular_ss220/antagonists/sound/music1.mp3',
+ 'modular_ss220/antagonists/sound/music2.mp3',
+ 'modular_ss220/antagonists/sound/music3.mp3',
+ 'modular_ss220/antagonists/sound/music4.mp3',
+ 'modular_ss220/antagonists/sound/music5.mp3',
+ 'modular_ss220/antagonists/sound/music6.mp3')
+ var/emote_probability = 60
+
+/obj/effect/timestop/dancing/timestop()
+ playsound(get_turf(src), pick(sound_type), 100, 1, -1)
+ for(var/i in 0 to duration-2)
+ addtimer(CALLBACK(src, PROC_REF(stop_and_dance_mobs_in_area)), i)
+ addtimer(CALLBACK(src, PROC_REF(release_frozen_mobs)), duration-1)
+ QDEL_IN(src, duration)
+ return
+
+/obj/effect/timestop/dancing/proc/release_frozen_mobs()
+ for(var/mob/living/M in stopped_atoms)
+ unfreeze_mob(M)
+
+/obj/effect/timestop/dancing/proc/stop_and_dance_mobs_in_area()
+ for(var/A in orange (freezerange, loc))
+ if(isliving(A))
+ var/mob/living/dancestoped_mob = A
+ if(dancestoped_mob in immune)
+ continue
+ dancestoped_mob.notransform = TRUE
+ dancestoped_mob.anchored = TRUE
+ if(ishostile(dancestoped_mob))
+ var/mob/living/simple_animal/hostile/H = dancestoped_mob
+ H.AIStatus = AI_OFF
+ H.LoseTarget()
+ stopped_atoms |= dancestoped_mob
+ for(var/mob/living/M in stopped_atoms)
+ if(get_dist(get_turf(M),get_turf(src)) > freezerange) //If they lagged/ran past the timestop somehow, just ignore them
+ unfreeze_mob(M)
+ stopped_atoms -= M
+ if(prob(emote_probability))
+ M.emote(pick(list("spin","dance","flip")), intentional = TRUE)
+
+/datum/spellbook_entry/dancestop
+ name = "Dance Stop"
+ spell_type = /datum/spell/aoe/conjure/timestop/dance
+ category = "Rave"
+
+/obj/effect/timestop/dancing/wizard
+ duration = 100
+
+/obj/effect/timestop/dancing/wizard/New()
+ ..()
+ timestop()
diff --git a/modular_ss220/antagonists/code/rave_wizard/datum/rave_wizard.dm b/modular_ss220/antagonists/code/rave_wizard/datum/rave_wizard.dm
new file mode 100644
index 000000000000..db34bababd18
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/datum/rave_wizard.dm
@@ -0,0 +1,90 @@
+#define SPELLBOOK_AVAILABLE_POINTS 4
+/datum/antagonist/wizard/rave
+
+/datum/objective/wizrave
+ explanation_text = "Устройте вечеринку, о которой потомки будут слагать легенды."
+ needs_target = FALSE
+ completed = TRUE
+
+/datum/antagonist/wizard/rave/give_objectives()
+ add_antag_objective(/datum/objective/wizrave)
+
+/datum/antagonist/wizard/rave/on_gain()
+ . = ..()
+ var/spell_paths = list(/datum/spell/projectile/magic_missile/beer,
+ /datum/spell/aoe/conjure/timestop/dance,
+ /datum/spell/great_revelry,
+ /datum/spell/touch/touch/rocker,
+ /datum/spell/aoe/conjure/summon_disco)
+ for(var/spell_path in spell_paths)
+ var/S = new spell_path
+ owner.AddSpell(S)
+
+
+/datum/mind/proc/enrave() //for admin spawn
+ if(!has_antag_datum(/datum/antagonist/wizard/rave))
+ return
+ var/obj/item/spellbook/spellbook = new /obj/item/spellbook(src)
+ spellbook.owner = src
+ spellbook.remove_harmful_spells_and_items()
+ spellbook.uses = SPELLBOOK_AVAILABLE_POINTS
+ src.current.equip_to_slot_or_del(spellbook, SLOT_HUD_LEFT_HAND)
+
+
+/datum/antagonist/wizard/rave/equip_wizard() //copypasta to make spellbook adjustments
+ if(!ishuman(owner.current))
+ return
+ var/mob/living/carbon/human/new_wiz = owner.current
+
+ //So zards properly get their items when they are admin-made.
+ qdel(new_wiz.wear_suit)
+ qdel(new_wiz.head)
+ qdel(new_wiz.shoes)
+ qdel(new_wiz.r_hand)
+ qdel(new_wiz.r_store)
+ qdel(new_wiz.l_store)
+
+ if(isplasmaman(new_wiz))
+ new_wiz.equipOutfit(new /datum/outfit/plasmaman/wizard)
+ new_wiz.internal = new_wiz.r_hand
+ new_wiz.update_action_buttons_icon()
+ else
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(new_wiz), SLOT_HUD_JUMPSUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(new_wiz), SLOT_HUD_HEAD)
+ new_wiz.dna.species.after_equip_job(null, new_wiz)
+ new_wiz.rejuvenate() //fix any damage taken by naked vox/plasmamen/etc while round setups
+ new_wiz.equip_to_slot_or_del(new /obj/item/radio/headset(new_wiz), SLOT_HUD_LEFT_EAR)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_wiz), SLOT_HUD_BACK)
+ if(new_wiz.dna.species.speciesbox)
+ new_wiz.equip_to_slot_or_del(new new_wiz.dna.species.speciesbox(new_wiz), SLOT_HUD_IN_BACKPACK)
+ else
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/box/survival(new_wiz), SLOT_HUD_IN_BACKPACK)
+ new_wiz.equip_to_slot_or_del(new /obj/item/teleportation_scroll(new_wiz), SLOT_HUD_RIGHT_STORE)
+ var/obj/item/spellbook/spellbook = new /obj/item/spellbook(new_wiz)
+ spellbook.owner = new_wiz
+ spellbook.remove_harmful_spells_and_items()
+ spellbook.uses = SPELLBOOK_AVAILABLE_POINTS
+ new_wiz.equip_to_slot_or_del(spellbook, SLOT_HUD_LEFT_HAND)
+
+ var/list/reading = list()
+ reading += "You will find a list of available spells in your spell book. Choose your magic arsenal carefully."
+ reading += "The spellbook is bound to you, and others cannot use it."
+ reading += "In your pockets you will find a teleport scroll. Use it as needed."
+ new_wiz.mind.store_memory("Remember: do not forget to prepare your spells.")
+ new_wiz.update_icons()
+ new_wiz.gene_stability += DEFAULT_GENE_STABILITY //magic
+ return reading
+
+/obj/item/spellbook/proc/remove_harmful_spells_and_items()
+ main_categories -= "Magical Items"
+ main_categories -= "Loadouts"
+ spell_categories -= "Offensive"
+ spell_categories -= "Rituals"
+
+/datum/spellbook_entry/summon_supermatter
+ category = "Offensive"
+
+/datum/spellbook_entry/rathens
+ category = "Offensive"
diff --git a/modular_ss220/antagonists/code/rave_wizard/great_revelry.dm b/modular_ss220/antagonists/code/rave_wizard/great_revelry.dm
new file mode 100644
index 000000000000..817dbdfdac80
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/great_revelry.dm
@@ -0,0 +1,48 @@
+/datum/spell/great_revelry
+ name = "Ritual of Great Revelry"
+ desc = "Gives everyone a beckoning bottle of alcohol, forcing them to drop an item from their hand."
+
+ school = "transmutation"
+ base_cooldown = 300
+ clothes_req = TRUE
+ invocation = "none"
+ invocation_type = "none"
+ cooldown_min = 100 //50 deciseconds reduction per rank
+ nonabstract_req = TRUE
+ var/beverages = list(/obj/item/reagent_containers/drinks/bottle/vodka,
+ /obj/item/reagent_containers/drinks/bottle/whiskey,
+ /obj/item/reagent_containers/drinks/bottle/tequila,
+ /obj/item/reagent_containers/drinks/bottle/absinthe/premium,
+ /obj/item/reagent_containers/drinks/bottle/absinthe,
+ /obj/item/reagent_containers/drinks/bottle/hcider,
+ /obj/item/reagent_containers/drinks/bottle/fernet)
+ action_icon_state = "no_state"
+ action_background_icon_state = "revelry"
+ action_icon = 'modular_ss220/antagonists/icons/rave.dmi'
+
+/datum/spell/great_revelry/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/datum/spell/great_revelry/cast(list/targets, mob/user = usr)
+ for(var/mob/living/carbon/human/H in GLOB.player_list)
+ var/turf/T = get_turf(H)
+ if(T && is_away_level(T.z))
+ continue
+ if(H.stat == DEAD || !(H.client))
+ return
+ if(iswizard(H) || H?.mind.offstation_role)
+ return
+ H.drop_item()
+ give_alcohol(H)
+
+
+/datum/spell/great_revelry/proc/give_alcohol(mob/living/carbon/human/H)
+ var/bottle_type = pick(beverages)
+ var/obj/item/bottle = new bottle_type(get_turf(H))
+ playsound(get_turf(H),'modular_ss220/antagonists/sound/beer_can_open.ogg', 50, TRUE)
+ H.put_in_hands(bottle)
+
+/datum/spellbook_entry/great_revelry
+ name = "Ritual of Great Revelry"
+ spell_type = /datum/spell/great_revelry
+ category = "Rave"
diff --git a/modular_ss220/antagonists/code/rave_wizard/rave_wizard_event.dm b/modular_ss220/antagonists/code/rave_wizard/rave_wizard_event.dm
new file mode 100644
index 000000000000..69ec32d61262
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/rave_wizard_event.dm
@@ -0,0 +1,66 @@
+#define MAGIVENDS_PRODUCTS_REFILL_VALUE 20
+#define WIZARD_WIKI ("На вики-странице доступна более подробная информация: ([GLOB.configuration.url.wiki_url]/index.php/Wizard)")
+#define RAVE_WIZARD_EVENT_WEIGHT 5
+
+/datum/event/rave_wizard
+
+/datum/event/rave_wizard/start()
+ INVOKE_ASYNC(src, PROC_REF(wrappedstart))
+
+/datum/event/rave_wizard/proc/wrappedstart()
+
+ var/image/source = image('modular_ss220/antagonists/icons/rave.dmi', "rave_poll")
+ var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a rave Space Wizard?", ROLE_WIZARD, TRUE, poll_time = 40 SECONDS, source = source)
+ var/mob/dead/observer/new_wizard = null
+
+ if(!length(candidates))
+ kill()
+ return
+
+ new_wizard = pick(candidates)
+
+ if(new_wizard)
+
+ var/mob/living/carbon/human/new_character = makeBody(new_wizard)
+ var/datum/antagonist/wizard/rave_wizard = new /datum/antagonist/wizard/rave()
+ new_character.mind.add_antag_datum(rave_wizard)
+ new_character.forceMove(pick(GLOB.wizardstart))
+ // This puts them at the wizard spawn, worry not
+ new_character.equip_to_slot_or_del(new /obj/item/reagent_containers/drinks/mugwort(new_wizard), SLOT_HUD_IN_BACKPACK)
+ new_character.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses, SLOT_HUD_GLASSES)
+ populate_magivends()
+ // The first wiznerd can get their mugwort from the wizard's den, new ones will also need mugwort!
+ dust_if_respawnable(new_wizard)
+ return TRUE
+ else
+ . = FALSE
+ CRASH("The candidates list for rave wizard contained non-observer entries!")
+
+// ripped from -tg-'s wizcode, because whee lets make a very general proc for a very specific gamemode
+// This probably wouldn't do half bad as a proc in __HELPERS
+// Lemme know if this causes species to mess up spectacularly or anything
+/datum/event/rave_wizard/proc/makeBody(mob/dead/observer/ghost_candidate)
+ if(!ghost_candidate?.key)
+ return // Let's not steal someone's soul here
+ var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))
+ ghost_candidate.client.prefs.active_character.copy_to(new_character)
+ new_character.key = ghost_candidate.key
+ return new_character
+
+/datum/event/rave_wizard/proc/populate_magivends()
+ for(var/obj/machinery/economy/vending/magivend/magic in GLOB.machines)
+ for(var/key in magic.products)
+ magic.products[key] = MAGIVENDS_PRODUCTS_REFILL_VALUE // and so, there was prosperity for mages everywhere
+ magic.product_records.Cut()
+ magic.build_inventory(magic.products, magic.product_records)
+
+/datum/event_container/major/New()
+ . = ..()
+ ASSERT(length(available_events) > 0)
+ var/datum/event_meta/nothing_event = available_events[1]
+ nothing_event.weight -= RAVE_WIZARD_EVENT_WEIGHT
+ available_events += list(new /datum/event_meta(EVENT_LEVEL_MAJOR, "Rave Wizard", /datum/event/rave_wizard, RAVE_WIZARD_EVENT_WEIGHT, is_one_shot = TRUE))
+
+#undef MAGIVENDS_PRODUCTS_REFILL_VALUE
+#undef WIZARD_WIKI
+#undef RAVE_WIZARD_EVENT_WEIGHT
diff --git a/modular_ss220/antagonists/code/rave_wizard/rocker_touch.dm b/modular_ss220/antagonists/code/rave_wizard/rocker_touch.dm
new file mode 100644
index 000000000000..8d6d065311d0
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/rocker_touch.dm
@@ -0,0 +1,88 @@
+#define DRUGS_AMOUNT_INJECTED_BY_TUMOR 20
+#define ALCOHOL_AMOUNT_INJECTED_BY_TUMOR 20
+
+/datum/spell/touch/touch/rocker
+ name = "Rocker Touch"
+ desc = "Teach those foolish suits how to spend time in style"
+ hand_path = /obj/item/melee/touch_attack/rocker
+ school = "transmutation"
+ base_cooldown = 30 SECONDS
+ clothes_req = TRUE
+ action_icon_state = "no_state"
+ action_background_icon_state = "curse"
+ action_icon = 'modular_ss220/antagonists/icons/rave.dmi'
+
+/obj/item/melee/touch_attack/rocker
+ name = "rocker touch"
+ desc = "It's time for anti corpo party to start"
+ catchphrase = "YRTAP SIBENG"
+ on_use_sound = 'modular_ss220/antagonists/sound/metal_riff.mp3'
+ icon_state = "banana_touch"
+ item_state = "banana_touch"
+
+/datum/spellbook_entry/rocker_curse
+ name = "Alcoholism curse"
+ spell_type = /datum/spell/touch/touch/rocker
+ category = "Rave"
+ cost = 1
+
+/obj/item/melee/touch_attack/rocker/afterattack(atom/target, mob/living/carbon/user, proximity)
+ if(!proximity || target == user || !ishuman(target) || !iscarbon(user) || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
+ return
+
+ var/datum/effect_system/smoke_spread/s = new
+ s.set_up(5, FALSE, target)
+ s.start()
+
+ var/mob/living/carbon/human/H = target
+ H.rocker_touched()
+ ..()
+
+/mob/living/carbon/human/proc/rocker_touched()
+ var/obj/item/organ/internal/chrome_tumor/tumor = new
+ tumor.insert(src)
+ AdjustWeakened(6 SECONDS)
+ unEquip(w_uniform, TRUE)
+ unEquip(shoes, TRUE)
+ unEquip(wear_suit, TRUE)
+ equipOutfit(new /datum/outfit/rocker_cursed)
+
+/obj/item/organ/internal/chrome_tumor
+ name = "chrome tumor"
+ desc = "Shiny metallic tumor"
+ origin_tech = "biotech=1"
+ w_class = WEIGHT_CLASS_TINY
+ parent_organ = "groin"
+ slot = "liver_tumor"
+ destroy_on_removal = TRUE //no icon, so just let it die
+ unremovable = TRUE
+ var/poisoned_offset = 0
+ var/suffering_delay = 1200
+
+/obj/item/organ/internal/chrome_tumor/on_life()
+ if(poisoned_offset < world.time)
+ poisoned_offset = world.time + suffering_delay
+ if(prob(75))
+ owner?.reagents.add_reagent("beer", ALCOHOL_AMOUNT_INJECTED_BY_TUMOR) //TODO change to choose from set of reagents
+ if(prob(50))
+ owner?.reagents.add_reagent("space_drugs", DRUGS_AMOUNT_INJECTED_BY_TUMOR) //TODO change to choose from set of reagents
+
+
+/obj/item/organ/internal/chrome_tumor/insert(mob/living/carbon/M, special = 0)
+ . = ..()
+ poisoned_offset = world.time
+
+/datum/outfit/rocker_cursed
+ name = "Cursed Rocker"
+ uniform = /obj/item/clothing/under/color/black/nodrop
+ shoes = /obj/item/clothing/shoes/jackboots/nodrop
+ suit = /obj/item/clothing/suit/leathercoat/nodrop
+
+/obj/item/clothing/under/color/black/nodrop
+ flags = NODROP
+
+/obj/item/clothing/shoes/jackboots/nodrop
+ flags = NODROP
+
+/obj/item/clothing/suit/leathercoat/nodrop
+ flags = NODROP
diff --git a/modular_ss220/antagonists/code/rave_wizard/summon_disco_ball.dm b/modular_ss220/antagonists/code/rave_wizard/summon_disco_ball.dm
new file mode 100644
index 000000000000..44b360510383
--- /dev/null
+++ b/modular_ss220/antagonists/code/rave_wizard/summon_disco_ball.dm
@@ -0,0 +1,30 @@
+/datum/spell/aoe/conjure/summon_disco
+ name = "Summon Disco Ball"
+ desc = "Summons a disco ball"
+ base_cooldown = 400 SECONDS
+ summon_type = list(/obj/machinery/jukebox/disco/indestructible)
+ invocation = "YRTAP SELDEN"
+ invocation_type = "shout"
+ summon_amt = 1
+ aoe_range = 0
+ level_max = 0 //cannot be improved
+ action_icon_state = "no_state"
+ action_background_icon_state = "summon_disco"
+ action_icon = 'modular_ss220/antagonists/icons/rave.dmi'
+ var/obj/machinery/jukebox/disco/indestructible/our_disco
+
+/datum/spell/aoe/conjure/summon_disco/cast(list/targets, mob/living/user = usr)
+ if(!our_disco)
+ var/list/summoned_items = ..()
+ if(summoned_items || summoned_items.len > 0)
+ our_disco = summoned_items[1]
+ else
+ playsound(get_turf(src), cast_sound, 50, 1)
+ our_disco.forceMove(user.loc)
+ playsound(get_turf(user), cast_sound, 50,1)
+
+/datum/spellbook_entry/summon_disco
+ name = "Summon Disco Ball"
+ spell_type = /datum/spell/aoe/conjure/summon_disco
+ cost = 1
+ category = "Rave"
diff --git a/modular_ss220/antagonists/icons/160x160.dmi b/modular_ss220/antagonists/icons/160x160.dmi
new file mode 100644
index 000000000000..c7a3f57fcb6d
Binary files /dev/null and b/modular_ss220/antagonists/icons/160x160.dmi differ
diff --git a/modular_ss220/antagonists/icons/rave.dmi b/modular_ss220/antagonists/icons/rave.dmi
new file mode 100644
index 000000000000..e8377262b6be
Binary files /dev/null and b/modular_ss220/antagonists/icons/rave.dmi differ
diff --git a/modular_ss220/antagonists/sound/beer_can_open.ogg b/modular_ss220/antagonists/sound/beer_can_open.ogg
new file mode 100644
index 000000000000..e5a126af3acc
Binary files /dev/null and b/modular_ss220/antagonists/sound/beer_can_open.ogg differ
diff --git a/modular_ss220/antagonists/sound/dancing_field.mp3 b/modular_ss220/antagonists/sound/dancing_field.mp3
new file mode 100644
index 000000000000..91a8d894d42b
Binary files /dev/null and b/modular_ss220/antagonists/sound/dancing_field.mp3 differ
diff --git a/modular_ss220/antagonists/sound/metal_riff.mp3 b/modular_ss220/antagonists/sound/metal_riff.mp3
new file mode 100644
index 000000000000..99511c6e3314
Binary files /dev/null and b/modular_ss220/antagonists/sound/metal_riff.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music1.mp3 b/modular_ss220/antagonists/sound/music1.mp3
new file mode 100644
index 000000000000..71ead6a373d9
Binary files /dev/null and b/modular_ss220/antagonists/sound/music1.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music2.mp3 b/modular_ss220/antagonists/sound/music2.mp3
new file mode 100644
index 000000000000..d53e13133006
Binary files /dev/null and b/modular_ss220/antagonists/sound/music2.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music3.mp3 b/modular_ss220/antagonists/sound/music3.mp3
new file mode 100644
index 000000000000..84467c20c2fd
Binary files /dev/null and b/modular_ss220/antagonists/sound/music3.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music4.mp3 b/modular_ss220/antagonists/sound/music4.mp3
new file mode 100644
index 000000000000..92be50109883
Binary files /dev/null and b/modular_ss220/antagonists/sound/music4.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music5.mp3 b/modular_ss220/antagonists/sound/music5.mp3
new file mode 100644
index 000000000000..29992e9c4bc1
Binary files /dev/null and b/modular_ss220/antagonists/sound/music5.mp3 differ
diff --git a/modular_ss220/antagonists/sound/music6.mp3 b/modular_ss220/antagonists/sound/music6.mp3
new file mode 100644
index 000000000000..ebd8f34cda31
Binary files /dev/null and b/modular_ss220/antagonists/sound/music6.mp3 differ