diff --git a/code/controllers/subsystem/achievements.dm b/code/controllers/subsystem/achievements.dm index fcbae35b3515..2119f9c2e20c 100644 --- a/code/controllers/subsystem/achievements.dm +++ b/code/controllers/subsystem/achievements.dm @@ -52,6 +52,8 @@ SUBSYSTEM_DEF(achievements) if(!achievement) log_sql("Achievement [achievementPath] not found in list of achievements when trying to unlock for [C.ckey]") return FALSE + if(istype(achievement,/datum/achievement/greentext) && achievementPath != /datum/achievement/greentext) + unlock_achievement(/datum/achievement/greentext,C) // Oooh, a little bit recursive! if(!has_achievement(achievementPath, C)) var/datum/DBQuery/medalQuery = SSdbcore.NewQuery("INSERT INTO [format_table_name("earned_achievements")] (ckey, id) VALUES ('[C.ckey]', '[achievement.id]')") medalQuery.Execute() @@ -90,6 +92,6 @@ SUBSYSTEM_DEF(achievements) /datum/controller/subsystem/achievements/proc/get_achievement(achievementPath) for(var/datum/achievement/i in achievements) - if(istype(i, achievementPath)) + if(i.type == achievementPath) // Can't use istype() here since it needs to be the EXACT correct type. return i return FALSE diff --git a/code/datums/achievements/achievements.dm b/code/datums/achievements/achievements.dm index b3d2d2c3e213..26b13ea155ef 100644 --- a/code/datums/achievements/achievements.dm +++ b/code/datums/achievements/achievements.dm @@ -1,3 +1,9 @@ +//OFFSETS - Used so that each general like "group" of achievements can be added to w/o fucking up the whole incremental pattern we got going on. +//DO NOT MAKE OFFSET VALUES THAT ARE GREATER THAN 2^15 OR LESS THAN 128. +//TO BE HONEST THIS OFFSET DOESN'T EVEN NEED TO BE POWER OF TWO, THOUGH. +#define GREENTEXT 256 // An offset for new greentext-related achievements, to keep the incremental pattern. +#define REDTEXT 512 // Offset for redtexts. + /datum/achievement var/name = "achievement" var/desc = "Please make an issue on github, including this achievement's name and how you got it." @@ -30,7 +36,7 @@ desc = "As a member of the Crew, deal a Humiliating defeat to Nuclear Team" id = 5 -/datum/achievement/nukewin +/datum/achievement/greentext/nukewin name = "Delta Alert" desc = "As a Nuclear Operative, score a Major or Minor Victory" id = 6 @@ -52,7 +58,7 @@ id = 9 hidden = TRUE -/datum/achievement/wizwin +/datum/achievement/greentext/wizwin name = "Scholars of the Arcane" desc = "As a wizard, complete your objectives" id = 10 @@ -68,12 +74,12 @@ id = 12 hidden = TRUE -/datum/achievement/changelingwin +/datum/achievement/greentext/changelingwin name = "The Thing" desc = "As a changeling, complete your objectives" id = 13 -/datum/achievement/slingascend +/datum/achievement/greentext/slingascend name = "The Dark Shadow" desc = "As a shadowling, ascend successfully" id = 14 @@ -131,3 +137,108 @@ name = "Duke of Ducats" desc = "As the QM, have a million cargo credits by the end of the round" //Cargoking-junior id = 22 + +// The achievements that are basically just "greentext as this sort of antag" + +/datum/achievement/greentext + name = "Green Text" + desc = "As an Antagonist achieve your first green text" + id = GREENTEXT + 1 + +/datum/achievement/greentext/ratvar + name = "Clock Work" + desc = "As a Servant of Ratvar summon Ratvar" + id = GREENTEXT + 2 + +/datum/achievement/greentext/ratvar/eminence + name = "Clock Work" + desc = "As the Eminence, summon Ratvar" + id = GREENTEXT + 3 + +/datum/achievement/greentext/narsie + name = "Blood Rites" + desc = "As a member of Blood Cult summon Nar-Sie" + id = GREENTEXT + 4 + +/datum/achievement/greentext/narsie/master + name = "Master of Blood" + desc = "As a Cult Master, summon Nar-Sie" + id = GREENTEXT + 5 + +/datum/achievement/greentext/revolution + name = "Down with Nanotrasen" + desc = "As a Revolutionary, complete your objectives" + id = GREENTEXT + 6 + +/datum/achievement/greentext/revolution/head + name = "Viva la Revolution!" + desc = "As a Head Revolutionary, complete your objectives" + id = GREENTEXT + 7 + +/datum/achievement/greentext/gang + name = "Turf War" + desc = "As a Gang Member, take over the station" + id = GREENTEXT + 8 + +/datum/achievement/greentext/gangleader + name = "\"I have built my organization upon fear.\"" + desc = "As a Gang Leader, take over the station" + id = GREENTEXT + 9 + +/datum/achievement/greentext/blob + name = "Grey Goo" + desc = "As a Blob complete your objectives" + id = GREENTEXT + 10 + +/datum/achievement/greentext/clownop + name = "\"You wouldn't get it\"" + desc = "As a Clown Operative score a Major or Minor Victory" + id = GREENTEXT + 11 + +/datum/achievement/greentext/internal + name = "Triple Cross" + desc = "As an Internal Affairs Agent, complete your objectives" + id = GREENTEXT + 12 + +/datum/achievement/greentext/external + name = "Quadruple Cross" + desc = "As an External Affairs Agent, complete your objectives" + id = GREENTEXT + 13 + +/datum/achievement/greentext/disease + name = "Space Aids" + desc = "As Sentient Disease, survive and complete your objectives" + id = GREENTEXT + 14 + +/datum/achievement/greentext/pirate + name = "Yaaaahr!" + desc = "As member of the Pirate crew, collect sufficient bounty from the crew" + id = GREENTEXT + 15 + +/datum/achievement/greentext/vampire + name = "Count de Ville" + desc = "As a Vampire, complete your objectives" + id = GREENTEXT + 16 + +/datum/achievement/greentext/revenant + name = "From The Shadows" + desc = "As a Revenant, complete your objectives" + id = GREENTEXT + 17 + +//end-greentext + +//start-redtext +/datum/achievement/redtext + name = "Mission Failed, We'll Get'em Next Time" + desc = "As an antagonist, fail your objectives." + id = REDTEXT + 1 + +/datum/achievement/redtext/winlost + name = "Arcane Failure" + desc = "As a Wizard, fail your objectives." + id = REDTEXT + 2 + hidden = TRUE +//end-redtext + +#undef GREENTEXT +#undef REDTEXT diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 4b862b512487..1733ba5ea9c5 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(antagonists) var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type + var/datum/achievement/greentext/greentext_achieve // The achievement received for greentexting as this antag type. Not all antag types use this to distribute their achievements. /datum/antagonist/New() GLOB.antagonists += src @@ -142,6 +143,10 @@ GLOBAL_LIST_EMPTY(antagonists) if(objectives.len == 0 || objectives_complete) report += "The [name] was successful!" + if(istype(greentext_achieve)) + SSachievements.unlock_achievement(greentext_achieve,owner.current) + else // The above still does award the generic greentext achievement, just implicitly. + SSachievements.unlock_achievement(/datum/achievement/greentext,owner.current.client) else report += "The [name] has failed!" diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index f11ca41b9388..edb187e860c3 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -146,6 +146,7 @@ for(var/datum/objective/O in objectives) if(!O.check_completion()) won = FALSE + break if(won) result += "[name] team fulfilled its mission!" else diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm index 3d6db983dc42..f878e1bf7715 100644 --- a/code/modules/antagonists/blob/blob.dm +++ b/code/modules/antagonists/blob/blob.dm @@ -16,6 +16,8 @@ if(!overmind.victory_in_progress) //if it won this doesn't really matter var/point_report = "
[owner.name] took over [overmind.max_count] tiles at the height of its growth." return basic_report+point_report + else + SSachievements.unlock_achievement(/datum/achievement/greentext/blob,overmind.client) return basic_report /datum/antagonist/blob/greet() diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 6bfe77a78901..f4b51889c221 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -575,7 +575,7 @@ if(changelingwin) parts += "The changeling was successful!" - SSachievements.unlock_achievement(/datum/achievement/changelingwin, owner.current.client) //changeling wins, give achivement + SSachievements.unlock_achievement(/datum/achievement/greentext/changelingwin, owner.current.client) //changeling wins, give achivement else parts += "The changeling has failed." diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index 57297bdc7337..ac6b374fbf5d 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -213,6 +213,10 @@ if(check_clockwork_victory()) parts += "Ratvar's servants defended the Ark until its activation!" + for(var/mind in SSticker.mode.servants_of_ratvar) + var/datum/mind/M = mind + SSachievements.unlock_achievement(/datum/achievement/greentext/ratvar,M.current.client) + SSachievements.unlock_achievement(/datum/achievement/greentext/ratvar/eminence,eminence.current.client) else parts += "The Ark was destroyed! Ratvar will rust away for all eternity!" parts += " " diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index f21389261f62..2f142663e41b 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -380,6 +380,11 @@ if(check_cult_victory()) parts += "The cult has succeeded! Nar-sie has snuffed out another torch in the void!" + for(var/mind in members) + var/datum/mind/M = mind + SSachievements.unlock_achievement(/datum/achievement/greentext/narsie,M.current.client) + if(M.has_antag_datum(/datum/antagonist/cult/master)) + SSachievements.unlock_achievement(/datum/achievement/greentext/narsie/master,M.current.client) else parts += "The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!" diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm index 1aef9ceba6db..f55b5c8d9b79 100644 --- a/code/modules/antagonists/disease/disease_datum.dm +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -57,6 +57,8 @@ if(win) result += "The [special_role_text] was successful!" + if(istype(owner.current, /mob/camera/disease)) + SSachievements.unlock_achievement(/datum/achievement/greentext/disease,owner.current.client) else result += "The [special_role_text] has failed!" diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 13c1702a3d35..6dcd2122ec38 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -380,8 +380,12 @@ SSachievements.unlock_achievement(/datum/achievement/flukeops, H.client) if(NUKE_RESULT_NUKE_WIN, NUKE_RESULT_DISK_LOST) for(var/mob/living/carbon/human/H in GLOB.player_list) - if(is_nuclear_operative(H)) - SSachievements.unlock_achievement(/datum/achievement/nukewin, H.client) + var/datum/mind/M = H.mind + if(M && M.has_antag_datum(/datum/antagonist/nukeop)) + if(M.has_antag_datum(/datum/antagonist/nukeop/clownop) || M.has_antag_datum(/datum/antagonist/nukeop/leader/clownop)) + SSachievements.unlock_achievement(/datum/achievement/greentext/clownop, H.client) + else + SSachievements.unlock_achievement(/datum/achievement/greentext/nukewin, H.client) /datum/team/nuclear/antag_listing_name() diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 754da76e10ac..c3d3acc1bcaa 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -101,6 +101,8 @@ if(L.check_completion() && !all_dead) parts += "The pirate crew was successful!" + for(var/datum/mind/M in members) + SSachievements.unlock_achievement(/datum/achievement/greentext/pirate,M.current.client) else parts += "The pirate crew has failed." diff --git a/code/modules/antagonists/revenant/revenant_antag.dm b/code/modules/antagonists/revenant/revenant_antag.dm index 8d99edf26ec6..f5b5aeb8ac1b 100644 --- a/code/modules/antagonists/revenant/revenant_antag.dm +++ b/code/modules/antagonists/revenant/revenant_antag.dm @@ -2,6 +2,7 @@ name = "Revenant" show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE + greentext_achieve = /datum/achievement/greentext/revenant /datum/antagonist/revenant/greet() owner.announce_objectives() diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index dc2b6cfd1731..ccd4895b3478 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -303,6 +303,12 @@ addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE) +/datum/team/revolution/proc/check_victory() + for(var/datum/objective/O in objectives) + if(!O.check_completion()) + return FALSE + return TRUE + /datum/team/revolution/roundend_report() if(!members.len) return @@ -326,6 +332,13 @@ var/list/targets = list() var/list/datum/mind/headrevs = get_antag_minds(/datum/antagonist/rev/head) var/list/datum/mind/revs = get_antag_minds(/datum/antagonist/rev,TRUE) + if(check_victory()) + for(var/H in revs) + var/datum/mind/M = H + SSachievements.unlock_achievement(/datum/achievement/greentext/revolution,M.current.client) + if(M.has_antag_datum(/datum/antagonist/rev/head)) + SSachievements.unlock_achievement(/datum/achievement/greentext/revolution/head,M.current.client) + if(headrevs.len) var/list/headrev_part = list() headrev_part += "The head revolutionaries were:" diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm index 32f4370d0fab..c35e97abcda4 100644 --- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm +++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm @@ -12,7 +12,7 @@ var/syndicate = FALSE var/last_man_standing = FALSE var/list/datum/mind/targets_stolen - + greentext_achieve = /datum/achievement/greentext/internal /datum/antagonist/traitor/internal_affairs/proc/give_pinpointer() if(owner && owner.current) @@ -234,6 +234,7 @@ special_role = TRAITOR_AGENT_ROLE syndicate = TRUE forge_single_objective() + greentext_achieve = /datum/achievement/greentext/external /datum/antagonist/traitor/internal_affairs/forge_traitor_objectives() forge_iaa_objectives() diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 252f5e62bafc..d1079c96fe71 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -421,6 +421,9 @@ if(traitorwin) result += "The [special_role_text] was successful!" + SSachievements.unlock_achievement(/datum/achievement/greentext,owner.current.client) + if(istype(greentext_achieve)) + SSachievements.unlock_achievement(greentext_achieve,owner.current) else result += "The [special_role_text] has failed!" SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg') diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 6effc95ebc15..7ae2d0a14f78 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -304,10 +304,10 @@ if(wizardwin) parts += "The wizard was successful!" - SSachievements.unlock_achievement(/datum/achievement/wizwin, owner.current.client) //wizard wins, give achievement + SSachievements.unlock_achievement(/datum/achievement/greentext/wizwin, owner.current.client) //wizard wins, give achievement else parts += "The wizard has failed!" - + SSachievements.unlock_achievement(/datum/achievement/redtext/winlost, owner.current.client) //wizard loses, still give achievement lol if(owner.spell_list.len>0) parts += "[owner.name] used the following spells: " var/list/spell_names = list() diff --git a/yogstation/code/datums/antagonists/vampire.dm b/yogstation/code/datums/antagonists/vampire.dm index 89f637d9dc3b..997e53a15a8e 100644 --- a/yogstation/code/datums/antagonists/vampire.dm +++ b/yogstation/code/datums/antagonists/vampire.dm @@ -341,6 +341,7 @@ if(vampwin) result += "The vampire was successful!" + SSachievements.unlock_achievement(/datum/achievement/greentext/vampire, owner.current.client) else result += "The vampire has failed!" SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg') diff --git a/yogstation/code/modules/antagonists/gang/gang.dm b/yogstation/code/modules/antagonists/gang/gang.dm index 777af61dd83d..b10e74b47034 100644 --- a/yogstation/code/modules/antagonists/gang/gang.dm +++ b/yogstation/code/modules/antagonists/gang/gang.dm @@ -331,6 +331,10 @@ report += "[name]:" if(winner) report += "The [name] gang was successful!" + for(var/datum/mind/M in leaders) + SSachievements.unlock_achievement(/datum/achievement/greentext/gangleader,M.current) + for(var/datum/mind/M in members) // Leaders are included in this too + SSachievements.unlock_achievement(/datum/achievement/greentext/gang,M.current) // and so get the lower achievement, too else report += "The [name] gang has failed!" diff --git a/yogstation/code/modules/antagonists/shadowling/special_shadowling_abilities.dm b/yogstation/code/modules/antagonists/shadowling/special_shadowling_abilities.dm index 0fcbb44f378f..0de60f91815f 100644 --- a/yogstation/code/modules/antagonists/shadowling/special_shadowling_abilities.dm +++ b/yogstation/code/modules/antagonists/shadowling/special_shadowling_abilities.dm @@ -164,7 +164,7 @@ SEND_SOUND(M, sound('sound/hallucinations/veryfar_noise.ogg')) for(var/obj/machinery/power/apc/A in GLOB.apcs_list) A.overload_lighting() - SSachievements.unlock_achievement(/datum/achievement/slingascend, H.client) + SSachievements.unlock_achievement(/datum/achievement/greentext/slingascend, H.client) var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc) for(var/X in H.mind.spell_list) var/obj/effect/proc_holder/spell/S = X