mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-31 09:00:25 +01:00
TGUI Faction Select (#21737)
## Description Hello! First PR here so I figured I'd do a big one ~~and stress out the maintainers as quickly as possible~~. :) While going through the process of creating a character the 'faction select' UI stuck out to me as *functional*, but difficult to parse visually and pretty dated looking by modern SS13 standards. (Not too bad, but you know what I mean) The new version is realistically *bit* too flashy for what it is (a single-use interface hidden away in the character creation menu), but it was very good practise for me to get back into DM/TGUI programming so it works out either way. I'm very happy to implement any feedback or suggested changes that could help improve it. ## Actual Description This PR replaces the old HTML 'faction select' interface with a new TGUI one, and also cleans up and fixes some adjacent code I bumped into while working on it. A couple of notes about the current version: * The 'Citizenship Check' line is currently non-functional and will always show a checkmark. I know a lot of the corporations have specific backgrounds/origins they won't hire people from, but I wasn't sure where exactly that's enforced in code, if at all. (I noticed `/datum/faction` has a `blacklisted_citizenship_types` variable, but it's currently unused.) * De-adminning or changing species doesn't immediately update the UI to reflect the changes, you have to click on something new to trigger an update manually. This doesn't have any actual consequences since I made sure to sanitise everything, but it is a visual thing. ## Screenshots <details><summary><b>Collapsed so it doesn't take up so much room:</b></summary> ### Before <img width="752" height="482" alt="xziPCYXbkn" src="https://github.com/user-attachments/assets/334e0609-c2e3-4a33-92ad-15120b78ab35" /> ### After <img width="900" height="645" alt="NT" src="https://github.com/user-attachments/assets/476702c7-c83c-4fee-a2cd-34d912468903" /> ### Unathi attempting to join Zeng-Hu (Button disabled) <img width="900" height="645" alt="Unathi fail" src="https://github.com/user-attachments/assets/c5a256c1-5531-4cbe-8198-27411c1aab9a" /> ### Faction Pages <details><summary><b>Stellar Corporate Conglomerate</b></summary> <img width="900" height="645" alt="SCC" src="https://github.com/user-attachments/assets/6e8bdb64-a220-41d4-a503-1268f9f93a30" /> </details> <details><summary><b>Nanotrasen</b></summary> <img width="900" height="645" alt="NT" src="https://github.com/user-attachments/assets/1ff107b5-7b3e-40e2-8f86-390ce29e165b" /> </details> <details><summary><b>Hephaestus Industries</b></summary> <img width="900" height="645" alt="HI" src="https://github.com/user-attachments/assets/6fc23159-990d-4de2-9745-827e11ca0442" /> </details> <details><summary><b>Idris Incorporated</b></summary> <img width="900" height="645" alt="II" src="https://github.com/user-attachments/assets/366a9824-81f1-4dd1-b385-4fa3968e39e0" /> </details> <details><summary><b>Orion Express</b></summary> <img width="900" height="645" alt="OE" src="https://github.com/user-attachments/assets/5588f0fe-d6c3-44b4-8297-cca4ed991bd8" /> </details> <details><summary><b>Private Military Contracting Group</b></summary> <img width="900" height="645" alt="PMCG" src="https://github.com/user-attachments/assets/a3dc6540-bfde-4fb2-939d-11e066b1e316" /> </details> <details><summary><b>Zavodskoi Interstellar</b></summary> <img width="900" height="645" alt="ZI" src="https://github.com/user-attachments/assets/a8c2c33d-7138-4164-a9f1-6a2dc3eb3e61" /> </details> <details><summary><b>Zeng-Hu Pharmaceuticals</b></summary> <img width="900" height="645" alt="ZHP" src="https://github.com/user-attachments/assets/4535ba80-efcb-4e50-9396-299bc16db2b5" /> </details> <details><summary><b>Independent</b></summary> <img width="900" height="645" alt="Independent" src="https://github.com/user-attachments/assets/dcf7b46c-edce-4104-a4f5-000479a9f963" /> </details> <hr> </details> ## Changelog - rscadd: "Revamped the 'Faction Select' UI in the occupation menu of character setup." - bugfix: "Fixed changing species in character setup not resetting your faction if it became invalid." - Not player-facing: - Fixed the TGUI dev server not working by bumping up the 'source-map' version. You still have to manually refresh the interface with Ctrl+R or Ctrl+F5 but it actually links now. - Added a `wiki_page` variable to each faction to allow for it to be manually set rather than being exclusively based on the name. (Mostly just futureproofing) - Added some line breaks to the faction descriptions to make them more easily readable. --------- Signed-off-by: SabreML <57483089+SabreML@users.noreply.github.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
@@ -3848,6 +3848,7 @@
|
||||
#include "code\modules\tgui\tgui.dm"
|
||||
#include "code\modules\tgui\tgui_window.dm"
|
||||
#include "code\modules\tgui\modules\armor_values.dm"
|
||||
#include "code\modules\tgui\modules\faction_select.dm"
|
||||
#include "code\modules\tgui\modules\flavor_text.dm"
|
||||
#include "code\modules\tgui\modules\hivenet_manifest.dm"
|
||||
#include "code\modules\tgui\modules\ipc_diagnostic.dm"
|
||||
|
||||
@@ -119,3 +119,6 @@
|
||||
|
||||
/proc/cmp_fusion_reaction_des(singleton/fusion_reaction/A, singleton/fusion_reaction/B)
|
||||
return B.priority - A.priority
|
||||
|
||||
/proc/cmp_faction(datum/faction/A, datum/faction/B)
|
||||
return A.ui_priority - B.ui_priority
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/datum/faction/admin
|
||||
name = "Admin Jobs"
|
||||
description = {"<p>
|
||||
This faction is for IC administrative jobs used by staff.
|
||||
</p>"}
|
||||
|
||||
departments = {"Command"}
|
||||
description = "This faction is for IC administrative jobs used by staff."
|
||||
departments = list(DEPARTMENT_COMMAND)
|
||||
title_suffix = "SCC"
|
||||
|
||||
ui_priority = -INFINITY // top of the list
|
||||
|
||||
allowed_role_types = ADMIN_ROLES
|
||||
|
||||
allowed_species_types = list(
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
var/name
|
||||
var/description
|
||||
var/title_suffix
|
||||
var/departments
|
||||
var/list/departments
|
||||
var/wiki_page
|
||||
|
||||
/// Number indicating the list index of this faction in the 'faction select' interface.
|
||||
var/ui_priority
|
||||
|
||||
var/list/allowed_role_types
|
||||
var/list/allowed_species_types
|
||||
@@ -60,33 +64,31 @@
|
||||
role.blacklisted_species = J.blacklisted_species
|
||||
. += role
|
||||
|
||||
/datum/faction/proc/get_selection_error(datum/preferences/prefs, var/mob/user)
|
||||
/datum/faction/proc/get_selection_error(datum/preferences/prefs, mob/user)
|
||||
if(length(allowed_species_types))
|
||||
|
||||
var/datum/species/S = prefs.get_species_datum()
|
||||
|
||||
if(!S)
|
||||
return "No valid species selected."
|
||||
return "No valid species"
|
||||
|
||||
if(!is_type_in_typecache(S, allowed_species_types))
|
||||
return "Invalid species selected."
|
||||
return "Invalid species"
|
||||
|
||||
if(length(blacklisted_citizenship_types))
|
||||
|
||||
var/datum/citizenship/C = SSrecords.citizenships[prefs.citizenship]
|
||||
|
||||
if(!C)
|
||||
return "No valid nation selected."
|
||||
return "No valid nation"
|
||||
|
||||
if(is_type_in_typecache(C, blacklisted_citizenship_types))
|
||||
return "Invalid nation selected."
|
||||
return "Invalid nation"
|
||||
|
||||
if (!is_visible(user))
|
||||
return "This faction is not available to you."
|
||||
if(!is_visible(user))
|
||||
return "This faction is not available to you"
|
||||
|
||||
return null
|
||||
|
||||
/datum/faction/proc/can_select(datum/preferences/prefs, var/mob/user)
|
||||
/datum/faction/proc/can_select(datum/preferences/prefs, mob/user)
|
||||
return !get_selection_error(prefs, user)
|
||||
|
||||
/datum/faction/proc/get_logo_name()
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
/datum/faction/hephaestus_industries
|
||||
name = "Hephaestus Industries"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
Hephaestus Industries, a sprawling and diverse mega-corporation
|
||||
focused on engineering and manufacturing on a massive scale, found their start
|
||||
as a conglomerate of several aerospace companies in the 22nd century. Initially
|
||||
as a conglomerate of several aerospace companies in the 22nd century.<br><br> Initially
|
||||
funded by sales of new designs for warp technology, the company fell on hard times
|
||||
during the Second Great Depression in the late 23rd century. Receiving bailouts
|
||||
from the Sol Alliance and securing several crucial production contracts, they have slowly
|
||||
worked their way to become the dominant manufacturing mega-corporation in the
|
||||
Sol Alliance, pioneering interstellar logistics and construction on an awe-inspiring scale.
|
||||
</p>"}
|
||||
departments = {"Engineering<br>Operations"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_CARGO)
|
||||
title_suffix = "Hepht"
|
||||
wiki_page = "Hephaestus_Industries"
|
||||
|
||||
allowed_role_types = HEPH_ROLES
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/datum/faction/idris_incorporated
|
||||
name = "Idris Incorporated"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
The Orion Spur's largest interstellar banking conglomerate, Idris Incorporated
|
||||
is operated by the mysterious Idris family. Idris Incorporated's influence
|
||||
can be found in nearly every corner of human space with their financing of
|
||||
nearly every type of business and enterprise. Their higher risk ventures have
|
||||
nearly every type of business and enterprise.<br> Their higher risk ventures have
|
||||
payment enforced by the infamous Idris Reclamation Units, shell IPCs sent to
|
||||
claim payment from negligent loan takers. In recent years, they have begun
|
||||
diversifying into more service-based industries.
|
||||
</p>"}
|
||||
departments = {"Security<br>Service"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_SERVICE)
|
||||
title_suffix = "Idris"
|
||||
wiki_page = "Idris_Incorporated"
|
||||
|
||||
allowed_role_types = IDRIS_ROLES
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
/datum/faction/nano_trasen
|
||||
name = "NanoTrasen"
|
||||
description = {"<p>
|
||||
Considered the largest megacorporation within the Orion Spur, many will find themselves doing the biddings of NanoTrasen.
|
||||
description = {"
|
||||
Considered the largest megacorporation within the Orion Spur, many will find themselves doing the biddings of NanoTrasen.<br>
|
||||
Initially a biotechnical research company, it rapidly grew in size after the discovery of phoron.
|
||||
NanoTrasen's continued monopoly on the resource catapulted it into the limelight, where it has remained for the last forty-odd years.
|
||||
NanoTrasen's continued monopoly on the resource catapulted it into the limelight, where it has remained for the last forty-odd years.<br><br>
|
||||
During the Phoron Scarcity, NanoTrasen's power has since begun to waver, resulting in their profit margins diminishing considerably.
|
||||
Nonetheless, NanoTrasen has managed to secure itself as a crucial member of the newly-founded Stellar Corporate Conglomerate
|
||||
allowing themselves to remain as a dominant corporate presence within the Orion Spur.
|
||||
</p>"}
|
||||
departments = {"Medical<br>Research<br>Service"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_SCIENCE, DEPARTMENT_SERVICE)
|
||||
title_suffix = "NT"
|
||||
wiki_page = "NanoTrasen_Corporation"
|
||||
|
||||
ui_priority = -1
|
||||
|
||||
is_default = TRUE
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/datum/faction/orion_express
|
||||
name = "Orion Express"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
Founded in 2464, the Orion Express is a corporation designed to handle logistics for the
|
||||
Stellar Corporate Conglomerate in the wake of the Phoron Scarcity and the sudden issues
|
||||
the Conglomeration of the megacorporations presented. It consists of its main branch, dedicated
|
||||
the Conglomeration of the megacorporations presented.<br> It consists of its main branch, dedicated
|
||||
to cargo services and transport, but also features a fledgling robotics division, mainly focused
|
||||
on industrial synthetics to aid in its logistics missions. The Orion Express is expected to become an
|
||||
on industrial synthetics to aid in its logistics missions.<br> The Orion Express is expected to become an
|
||||
integral part of the Stellar Corporate Conglomerate's future through delivering supplies and merchandise throughout the Orion Spur.
|
||||
</p>"}
|
||||
departments = {"Operations<br>Service"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_CARGO, DEPARTMENT_SERVICE)
|
||||
title_suffix = "Orion"
|
||||
wiki_page = "Orion_Express"
|
||||
|
||||
allowed_role_types = ORION_ROLES
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/datum/faction/pmc
|
||||
name = "Private Military Contracting Group"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
The Private Military Contracting Group is a coalition of security and medical contractors;
|
||||
borne from the necessity of protecting the Stellar Corporate Conglomerate and its holdings.
|
||||
borne from the necessity of protecting the Stellar Corporate Conglomerate and its holdings.<br>
|
||||
Following the ever-growing corporate empire, mercenaries and contractors from all across the spur are deployed accordingly;
|
||||
from mere office buildings to outposts in the Corporate Reconstruction Zone.
|
||||
from mere office buildings to outposts in the Corporate Reconstruction Zone.<br><br>
|
||||
Unlike the other members of the Corporate Conglomerate, the Private Military Contracting Group has few employees of its own.
|
||||
Only some liaisons and bureaucrats work behind the scenes to hire and manage the contractors;
|
||||
the rest of its members are part of several organizations contracted to supply the PMCG.
|
||||
</p>"}
|
||||
departments = {"Medical<br>Security"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_SECURITY)
|
||||
title_suffix = "PMCG"
|
||||
wiki_page = "Private_Military_Contracting_Group"
|
||||
|
||||
allowed_role_types = PMC_ROLES
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
/datum/faction/scc
|
||||
name = "Stellar Corporate Conglomerate"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
The Stellar Corporate Conglomerate (SCC) was formed at the height of corporate power in the galaxy,
|
||||
originally to secure Tau Ceti assets during the Second Solarian Incursion.
|
||||
Chainlink now exercises undisputed economic dominance over the Orion Spur,
|
||||
and is now willing and eager to supersede any and all higher authority placed before it.
|
||||
and is now willing and eager to supersede any and all higher authority placed before it.<br>
|
||||
Cooperation has been deemed essential ever since Einstein Engines resurfaced due to the emerging prominence of warp travel.
|
||||
They've remained in a shaky peace, puppeteered to carry out the engimatic whims of the Trasen family.
|
||||
Of course, this doesn't stop their greed for power and glory - they're just corporations, after all.
|
||||
</p>"}
|
||||
departments = {"Command<br>Equipment"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_COMMAND, DEPARTMENT_EQUIPMENT)
|
||||
title_suffix = "SCC"
|
||||
wiki_page = "Stellar_Corporate_Conglomerate"
|
||||
|
||||
ui_priority = -2
|
||||
|
||||
allowed_role_types = SCC_ROLES
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/datum/faction/unaffiliated
|
||||
name = "Independent"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
For individuals not necessarily tied to any of the large mega corporations lording
|
||||
over human space, the mark of "independent" can open as many doors as it is likely to
|
||||
close. You would often see people lacking a concrete affiliation popping up as
|
||||
close.<br> You would often see people lacking a concrete affiliation popping up as
|
||||
reporters, journalists, individual traders. Their presence, though often an inconvenience
|
||||
for the mega corporations, is often necessary to forward the facade of economic freedom
|
||||
that Tau Ceti reports to have.
|
||||
</p>"}
|
||||
departments = {"Civilian"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_CIVILIAN)
|
||||
allowed_role_types = INDEP_ROLES
|
||||
|
||||
title_suffix = "INDEP"
|
||||
|
||||
ui_priority = INFINITY // bottom of the list
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/datum/faction/zavodskoi_interstellar
|
||||
name = "Zavodskoi Interstellar"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
The largest weapons producer in human space, Zavodskoi Interstellar initially
|
||||
found its place with the invention of a militarized voidsuit for use in the Interstellar War.
|
||||
found its place with the invention of a militarized voidsuit for use in the Interstellar War.<br>
|
||||
With many lucrative weapon contracts thanks to the Sol Alliance, as well as acquisitions of
|
||||
other major armaments companies, Zavodskoi weapons can be found in the hands of nearly every
|
||||
military force across the Orion Spur. They are the main corporation found in the Empire of
|
||||
military force across the Orion Spur.<br> They are the main corporation found in the Empire of
|
||||
Dominia, and are at the forefront of weapons development technology.
|
||||
</p>"}
|
||||
departments = {"Engineering<br>Research<br>Security"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SCIENCE, DEPARTMENT_SECURITY)
|
||||
title_suffix = "Zavod"
|
||||
wiki_page = "Zavodskoi_Interstellar"
|
||||
|
||||
allowed_role_types = ZAVOD_ROLES
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/datum/faction/zeng_hu
|
||||
name = "Zeng-Hu Pharmaceuticals"
|
||||
description = {"<p>
|
||||
description = {"
|
||||
Zeng-Hu Pharmaceuticals, born of a merger of two major biotech companies on
|
||||
Earth in 2032, was the first to successfully develop cryogenics in the 21st
|
||||
century for the purposes of space travel. This development, crucial to
|
||||
interstellar colonization, helped propel them to their current position as the
|
||||
largest pharmaceutical and medical corporation in the Orion Spur. In more recent
|
||||
largest pharmaceutical and medical corporation in the Orion Spur.<br> In more recent
|
||||
years, they were also the first mega-corporation to partner with the newly-discovered
|
||||
Skrell, working closely with this alien species to pioneer cloning, a once
|
||||
controversial field that is now more accepted today.
|
||||
</p>"}
|
||||
|
||||
departments = {"Medical<br>Research"}
|
||||
"}
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_SCIENCE)
|
||||
title_suffix = "Zeng"
|
||||
wiki_page = "Zeng-Hu_Pharmaceuticals"
|
||||
|
||||
allowed_role_types = ZENG_ROLES
|
||||
|
||||
|
||||
@@ -490,6 +490,11 @@ GLOBAL_LIST_INIT(valid_bloodtypes, list(
|
||||
pref.citizenship = OO.possible_citizenships[1]
|
||||
pref.religion = OO.possible_religions[1]
|
||||
|
||||
var/datum/faction/current_faction = SSjobs.name_factions[pref.faction]
|
||||
if(!current_faction?.can_select(pref, user))
|
||||
to_chat(user, SPAN_WARNING("[pref.faction] does not employ [mob_species.name_plural]. Resetting to [SSjobs.default_faction.name]!"))
|
||||
pref.faction = SSjobs.default_faction.name
|
||||
|
||||
// Follows roughly the same way hair does above, but for gradient styles
|
||||
var/global/list/valid_gradients = list()
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/category_item/player_setup_item/occupation
|
||||
name = "Occupation"
|
||||
sort_order = 1
|
||||
/// The module datum for the faction select interface, if it's currently open.
|
||||
var/datum/tgui_module/faction_select/faction_ui
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/load_character(var/savefile/S)
|
||||
S["alternate_option"] >> pref.alternate_option
|
||||
@@ -163,7 +165,7 @@
|
||||
"<style>span.none{color: black} span.low{color: #DDD} span.med{color: yellow} span.high{color: lime} a:hover span{color: #40628a !important}</style>",
|
||||
"<center><b>Character Faction</b><br>",
|
||||
"<small>This will influence the jobs you can select from, and the starting equipment.</small><br>",
|
||||
"<b><a href='byond://?src=[REF(src)];faction_preview=[html_encode(pref.faction)]'>[pref.faction]</a></b></center><br><hr>"
|
||||
"<b><a href='byond://?src=[REF(src)];faction_select=1;'>[pref.faction]</a></b></center><br><hr>"
|
||||
)
|
||||
|
||||
dat += list(
|
||||
@@ -292,17 +294,17 @@
|
||||
if(SetJob(user, href_list["set_job"]))
|
||||
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||
|
||||
else if(href_list["faction_preview"])
|
||||
show_faction_menu(user, html_decode(href_list["faction_preview"]))
|
||||
else if(href_list["faction_select"])
|
||||
if(!faction_ui)
|
||||
faction_ui = new(src)
|
||||
faction_ui.ui_interact(user)
|
||||
return TOPIC_NOACTION
|
||||
|
||||
else if(href_list["faction_select"])
|
||||
validate_and_set_faction(html_decode(href_list["faction_select"]))
|
||||
show_faction_menu(user, html_decode(href_list["faction_select"]))
|
||||
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/proc/on_ui_close()
|
||||
faction_ui = null
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/proc/sanitize_faction()
|
||||
if (!SSjobs.name_factions[pref.faction])
|
||||
pref.faction = SSjobs.default_faction.name
|
||||
@@ -448,67 +450,10 @@
|
||||
|
||||
pref.player_alt_titles.Cut()
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/proc/show_faction_menu(mob/user, selected_faction) //note : selected faction is what you choose to see, pref.faction is the actual chosen faction
|
||||
simple_asset_ensure_is_sent(user, /datum/asset/simple/faction_icons)
|
||||
|
||||
var/list/dat = list("<center><h2>")
|
||||
|
||||
var/list/factions = list()
|
||||
for (var/datum/faction/faction in SSjobs.factions)
|
||||
if(!faction.is_visible(user))
|
||||
continue
|
||||
|
||||
if (faction.name == selected_faction)
|
||||
factions += "[faction.name]"
|
||||
else
|
||||
factions += "<a href='byond://?src=[REF(src)];faction_preview=[html_encode(faction.name)]'>[faction.name]</a>"
|
||||
|
||||
dat += factions.Join(" ")
|
||||
|
||||
var/datum/faction/faction = SSjobs.name_factions[selected_faction]
|
||||
if(!istype(faction))
|
||||
to_client_chat(SPAN_DANGER("Invalid faction chosen. Resetting to [SSjobs.default_faction.name]."))
|
||||
selected_faction = SSjobs.default_faction.name
|
||||
faction = SSjobs.name_factions[selected_faction]
|
||||
return
|
||||
|
||||
dat += "</h2></center><hr/>"
|
||||
dat += "<table padding='8px'>"
|
||||
dat += "<tr>"
|
||||
dat += "<td width = 500>[faction.description]</td>"
|
||||
dat += "<td width = 200 align='center'>"
|
||||
dat += {"<img style="height:132px;" src="[faction.get_logo_name()]">"}
|
||||
|
||||
dat += "<br/><b>Departments:</br></b>"
|
||||
dat += "<small><b>[faction.departments]</b></small>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table><center><hr/>"
|
||||
|
||||
dat += "You can learn more about this faction on <a href='byond://?src=[REF(user.client)];JSlink=wiki;wiki_page=[replacetext(faction.name, " ", "_")]'>the wiki</a>."
|
||||
|
||||
if (selected_faction == pref.faction)
|
||||
dat += "<br>\[Faction selected\]"
|
||||
else if (faction.can_select(pref,user))
|
||||
dat += "<br>\[<a href='byond://?src=[REF(src)];faction_select=[html_encode(selected_faction)]'>Select faction</a>\]"
|
||||
else
|
||||
dat += "<br><span class='warning'>[faction.get_selection_error(pref, user)]</span>"
|
||||
dat += "</center>"
|
||||
|
||||
user << browse(HTML_SKELETON(dat.Join()), "window=factionpreview;size=750x450")
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/proc/validate_and_set_faction(selected_faction)
|
||||
var/datum/faction/faction = SSjobs.name_factions[selected_faction]
|
||||
|
||||
if (!faction)
|
||||
to_client_chat(SPAN_DANGER("Invalid faction chosen. Resetting to default."))
|
||||
selected_faction = SSjobs.default_faction.name
|
||||
|
||||
/datum/category_item/player_setup_item/occupation/proc/validate_and_set_faction(datum/faction/faction)
|
||||
ResetJobs() // How to be horribly lazy.
|
||||
|
||||
pref.faction = selected_faction
|
||||
|
||||
to_client_chat(SPAN_NOTICE("New faction chosen. Job preferences reset."))
|
||||
pref.faction = faction.name
|
||||
to_client_chat(SPAN_NOTICE("New faction chosen! Job preferences reset."))
|
||||
|
||||
/datum/preferences/proc/GetPlayerAltTitle(datum/job/job)
|
||||
return player_alt_titles[job.title] || job.title
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/datum/tgui_module/faction_select
|
||||
/// The 'occupation' datum of the user viewing the interface.
|
||||
var/datum/category_item/player_setup_item/occupation/occupation
|
||||
/// The name of the currently viewed faction.
|
||||
var/viewed_faction
|
||||
|
||||
/datum/tgui_module/faction_select/New(datum/category_item/player_setup_item/occupation/occupation)
|
||||
. = ..()
|
||||
src.occupation = occupation
|
||||
viewed_faction = occupation.pref.faction
|
||||
|
||||
/datum/tgui_module/faction_select/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "FactionSelect")
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/datum/tgui_module/faction_select/ui_close(mob/user)
|
||||
. = ..()
|
||||
occupation.on_ui_close()
|
||||
|
||||
/datum/tgui_module/faction_select/ui_data(mob/user)
|
||||
var/list/data = alist()
|
||||
data["chosen_faction"] = occupation.pref.faction
|
||||
|
||||
var/datum/faction/faction_datum = get_faction(viewed_faction, user)
|
||||
// Set `viewed_faction` to the `get_faction()` result from it, since that double checks that it's actually valid.
|
||||
data["viewed_faction"] = faction_datum.name
|
||||
data["viewed_selection_error"] = faction_datum.get_selection_error(occupation.pref, user)
|
||||
|
||||
return data
|
||||
|
||||
/datum/tgui_module/faction_select/ui_static_data(mob/user)
|
||||
var/list/data = alist()
|
||||
|
||||
var/list/factions = list()
|
||||
for(var/datum/faction/faction as anything in sort_list(SSjobs.factions, GLOBAL_PROC_REF(cmp_faction)))
|
||||
if(!faction.is_visible(user))
|
||||
continue
|
||||
|
||||
factions.Add(list(alist(
|
||||
"name" = faction.name,
|
||||
"suffix" = faction.title_suffix,
|
||||
"desc" = faction.description,
|
||||
"logo" = faction.get_logo_name(),
|
||||
"departments" = faction.departments,
|
||||
"wiki_page" = faction.wiki_page
|
||||
)))
|
||||
data["factions"] = factions
|
||||
data["wiki_url"] = GLOB.config.wikiurl
|
||||
return data
|
||||
|
||||
/datum/tgui_module/faction_select/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/datum/faction/faction = get_faction(params["faction"], usr, FALSE)
|
||||
|
||||
if(action == "view_faction")
|
||||
viewed_faction = faction.name
|
||||
return TRUE
|
||||
|
||||
if(action == "choose_faction")
|
||||
var/faction_error = faction.get_selection_error(occupation.pref, usr)
|
||||
if(faction_error)
|
||||
to_chat(usr, SPAN_DANGER("Error selecting faction!: [faction_error]"))
|
||||
return FALSE
|
||||
|
||||
occupation.validate_and_set_faction(faction)
|
||||
usr.client.prefs.ShowChoices(usr)
|
||||
usr.client.prefs.update_preview_icon()
|
||||
return TRUE
|
||||
|
||||
if(action == "open_wiki")
|
||||
var/client/client = usr.get_client()
|
||||
client?.wiki(faction.wiki_page)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_module/faction_select/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/faction_icons)
|
||||
)
|
||||
|
||||
/datum/tgui_module/faction_select/proc/get_faction(faction_name, mob/user, quiet = TRUE)
|
||||
var/datum/faction/faction = SSjobs.name_factions[faction_name]
|
||||
if(!istype(faction) || !faction.is_visible(user))
|
||||
if(!quiet)
|
||||
to_chat(usr, SPAN_WARNING("Invalid faction chosen. Resetting to [SSjobs.default_faction.name]."))
|
||||
update_static_data(user) // Update the faction list to hopefully remove anything invalid.
|
||||
return SSjobs.default_faction
|
||||
|
||||
return faction
|
||||
@@ -0,0 +1,14 @@
|
||||
# Your name.
|
||||
author: SabreML
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- rscadd: "Revamped the 'Faction Select' UI in the occupation menu of character setup."
|
||||
- bugfix: "Fixed changing species in character setup not resetting your faction if it became invalid."
|
||||
@@ -6,7 +6,7 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.12.0",
|
||||
"glob": "^7.1.7",
|
||||
"source-map": "^0.7.3",
|
||||
"source-map": "^0.7.4",
|
||||
"stacktrace-parser": "^0.1.10",
|
||||
"ws": "^7.5.10"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
// code/modules/tgui/modules/faction_select.dm
|
||||
import { classes } from 'common/react';
|
||||
import { resolveAsset } from '../assets';
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Divider, Flex, Icon, LabeledList, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export type FactionSelectData = {
|
||||
chosen_faction: string;
|
||||
viewed_faction: string;
|
||||
viewed_selection_error: string;
|
||||
factions: Faction[];
|
||||
wiki_url: string;
|
||||
};
|
||||
|
||||
export type Faction = {
|
||||
name: string;
|
||||
suffix: string;
|
||||
desc: string;
|
||||
logo: string;
|
||||
departments: string[];
|
||||
wiki_page: string;
|
||||
};
|
||||
|
||||
export const FactionSelect = () => {
|
||||
return (
|
||||
<Window theme="faction_select" width={900} height={645}>
|
||||
<Window.Content>
|
||||
<Stack fill>
|
||||
<Stack.Item width="22em">
|
||||
<FactionList />
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<FactionInfo />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const FactionList = (props, context) => {
|
||||
const { act, data } = useBackend<FactionSelectData>(context);
|
||||
return (
|
||||
<Section fill fitted pl={1} py={1} scrollable>
|
||||
<Stack vertical>
|
||||
{data.factions.map((faction) => (
|
||||
<Stack.Item key={faction.name}>
|
||||
<Button
|
||||
className={`faction_entry--${faction.suffix}`}
|
||||
fluid
|
||||
selected={faction.name === data.chosen_faction}
|
||||
color={faction.name === data.viewed_faction ? 'label' : 'grey'}
|
||||
style={{ 'white-space': 'normal' }}
|
||||
onClick={() => act('view_faction', { faction: faction.name })}>
|
||||
<Flex align="center" justify="space-between">
|
||||
<Flex.Item bold fontSize={1.08}>
|
||||
{faction.name}
|
||||
</Flex.Item>
|
||||
<Flex.Item pt={1} pr={0.5}>
|
||||
<Box
|
||||
as="img"
|
||||
src={resolveAsset(faction.logo)}
|
||||
width="48px"
|
||||
height="48px"
|
||||
/>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
))}
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const FactionInfo = (props, context) => {
|
||||
const { act, data } = useBackend<FactionSelectData>(context);
|
||||
|
||||
const currentFaction = data.factions.find(
|
||||
(faction) => faction.name === data.viewed_faction
|
||||
)!; // Non-null assertion for `currentFaction` since if it is null, that shouldn't be handled here.
|
||||
|
||||
const FormatDescription = (text: string) => {
|
||||
return text
|
||||
.replace(/\n\t/g, ' ')
|
||||
.replace(/<br>\s*/g, '\n')
|
||||
.trim();
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex height="100%" direction="column" justify="space-between">
|
||||
<Flex.Item>
|
||||
<Section>
|
||||
<Box
|
||||
my={1}
|
||||
textAlign="center"
|
||||
bold
|
||||
fontSize={2.1}
|
||||
fontFamily="Arial Black">
|
||||
{currentFaction.name}
|
||||
</Box>
|
||||
</Section>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Divider />
|
||||
</Flex.Item>
|
||||
<Flex.Item grow>
|
||||
<Flex height="100%">
|
||||
<Flex.Item grow>
|
||||
<Section fill scrollable fontSize={1.1} preserveWhitespace>
|
||||
{FormatDescription(currentFaction.desc)}
|
||||
</Section>
|
||||
</Flex.Item>
|
||||
<Flex.Item align="center" height="100%" mt={12.5}>
|
||||
<div
|
||||
class={classes([
|
||||
'Divider--vertical',
|
||||
'Divider--vertical--dashed',
|
||||
])}
|
||||
style={{ height: '85%' }}
|
||||
/>
|
||||
</Flex.Item>
|
||||
<Flex.Item width="15.5em">
|
||||
<FactionPanel currentFaction={currentFaction} />
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Divider />
|
||||
<Box textAlign="center">
|
||||
━━ You can learn more about this faction on the wiki:
|
||||
<Button
|
||||
icon="arrow-up-right-from-square"
|
||||
disabled={!currentFaction.wiki_page}
|
||||
title={
|
||||
currentFaction.wiki_page
|
||||
? data.wiki_url + currentFaction.wiki_page
|
||||
: 'This faction does not have a wiki page'
|
||||
}
|
||||
onClick={() => act('open_wiki', { 'faction': currentFaction.name })}
|
||||
/>
|
||||
━━
|
||||
</Box>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const FactionPanel = (props: { currentFaction: Faction }, context) => {
|
||||
const { currentFaction } = props;
|
||||
const { act, data } = useBackend<FactionSelectData>(context);
|
||||
|
||||
const currentIsChosen = currentFaction.name === data.chosen_faction;
|
||||
const CanSelect = () =>
|
||||
currentFaction.name === data.chosen_faction ||
|
||||
!!data.viewed_selection_error;
|
||||
|
||||
const Checkmark = (input: boolean) => {
|
||||
if (input) {
|
||||
return <Icon name="check" size={1.1} color="good" />;
|
||||
} else {
|
||||
return <Icon name="xmark" size={1.1} color="bad" />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex
|
||||
height="100%"
|
||||
direction="column"
|
||||
align="center"
|
||||
justify="space-between">
|
||||
<Flex.Item>
|
||||
<Stack vertical align="center" textColor="label">
|
||||
<Stack.Item>
|
||||
<Box
|
||||
as="img"
|
||||
src={resolveAsset(currentFaction.logo)}
|
||||
height="13em"
|
||||
width="13em"
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item bold fontSize={1.25}>
|
||||
<u>Departments:</u>
|
||||
</Stack.Item>
|
||||
{currentFaction.departments.map((department) => (
|
||||
<Stack.Item key={department} bold>
|
||||
{department}
|
||||
</Stack.Item>
|
||||
))}
|
||||
</Stack>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
<Divider />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
width="15em"
|
||||
height="3.75em"
|
||||
textAlign="center"
|
||||
bold
|
||||
verticalAlignContent="middle"
|
||||
style={{ 'white-space': 'normal' }}
|
||||
disabled={CanSelect()}
|
||||
onClick={() =>
|
||||
act('choose_faction', { 'faction': currentFaction.name })
|
||||
}>
|
||||
{`[${
|
||||
currentIsChosen
|
||||
? 'Faction Selected'
|
||||
: data.viewed_selection_error ?? 'Select Faction'
|
||||
}]`}
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item fontFamily="Tahoma" fontSize={1.05}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Citizenship Check">
|
||||
{Checkmark(true)}
|
||||
{/* NYI (/datum/faction/var/blacklisted_citizenship_types) */}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Cultural Check">
|
||||
{Checkmark(!data.viewed_selection_error)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
@use '../components/Divider.scss';
|
||||
|
||||
// Colours based on the companies' 'Official Colours' sections on the wiki.
|
||||
$company-colors: (
|
||||
'SCC': #1966b3,
|
||||
'NT': #14498f,
|
||||
'Hepht': #aa6d18,
|
||||
'Idris': #369fa1,
|
||||
'Orion': #aa6818,
|
||||
'PMCG': #1a1a1a,
|
||||
'Zavod': #8a1414,
|
||||
'Zeng': #b56cea,
|
||||
// 'Independent' doesn't get a colour :(
|
||||
);
|
||||
|
||||
.theme-faction_select {
|
||||
.Divider {
|
||||
&--vertical--dashed {
|
||||
border-left: Divider.$thickness dashed Divider.$color;
|
||||
}
|
||||
}
|
||||
|
||||
.LabeledList__content {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.Layout__content {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
@each $name, $color in $company-colors {
|
||||
.faction_entry--#{$name}:not(.Button--selected) {
|
||||
background-image: linear-gradient(to right, transparent 65%, $color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
@include meta.load-css('./components/BlockQuote.scss');
|
||||
@include meta.load-css('./components/Button.scss');
|
||||
@include meta.load-css('./components/ColorBox.scss');
|
||||
@include meta.load-css('./components/Dialog.scss');
|
||||
@include meta.load-css('./components/Dimmer.scss');
|
||||
@include meta.load-css('./components/Divider.scss');
|
||||
@include meta.load-css('./components/Dropdown.scss');
|
||||
@@ -44,12 +45,12 @@
|
||||
@include meta.load-css('./components/Tabs.scss');
|
||||
@include meta.load-css('./components/TextArea.scss');
|
||||
@include meta.load-css('./components/Tooltip.scss');
|
||||
@include meta.load-css('./components/Dialog.scss');
|
||||
|
||||
// Interfaces
|
||||
@include meta.load-css('./interfaces/ListInput.scss');
|
||||
@include meta.load-css('./interfaces/AlertModal.scss');
|
||||
@include meta.load-css('./interfaces/CrewManifest.scss');
|
||||
@include meta.load-css('./interfaces/FactionSelect.scss');
|
||||
@include meta.load-css('./interfaces/ListInput.scss');
|
||||
@include meta.load-css('./interfaces/PersonalCrafting.scss');
|
||||
@include meta.load-css('./interfaces/RequestManager.scss');
|
||||
|
||||
|
||||
+8
-1
@@ -9462,6 +9462,13 @@ resolve@^2.0.0-next.3:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"source-map@npm:^0.7.4":
|
||||
version: 0.7.6
|
||||
resolution: "source-map@npm:0.7.6"
|
||||
checksum: 932f4a2390aa7100e91357d88cc272de984ad29139ac09eedfde8cc78d46da35f389065d0c5343c5d71d054a6ebd4939a8c0f2c98d5df64fe97bb8a730596c2d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sprintf-js@npm:~1.0.2":
|
||||
version: 1.0.3
|
||||
resolution: "sprintf-js@npm:1.0.3"
|
||||
@@ -9967,7 +9974,7 @@ resolve@^2.0.0-next.3:
|
||||
dependencies:
|
||||
axios: ^1.12.0
|
||||
glob: ^7.1.7
|
||||
source-map: ^0.7.3
|
||||
source-map: ^0.7.4
|
||||
stacktrace-parser: ^0.1.10
|
||||
ws: ^7.5.10
|
||||
languageName: unknown
|
||||
|
||||
Reference in New Issue
Block a user