FACTIONS: fix unstable display order (#920)

This commit is contained in:
Jesse Clark 2023-12-03 01:06:30 -08:00 committed by GitHub
parent 34cc0441c2
commit 7fc46649f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 70 deletions

@ -143,12 +143,12 @@ export function FactionsDev(): React.ReactElement {
value={selectedFaction.name} value={selectedFaction.name}
startAdornment={ startAdornment={
<> <>
<Tooltip title={`Hear rumor about ${selectedFaction}`}> <Tooltip title={`Hear rumor about ${selectedFaction.name}`}>
<IconButton onClick={receiveRumor} size="large"> <IconButton onClick={receiveRumor} size="large">
<ChatIcon /> <ChatIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title={`Receive invitation to ${selectedFaction}`}> <Tooltip title={`Receive invitation to ${selectedFaction.name}`}>
<IconButton onClick={receiveInvite} size="large"> <IconButton onClick={receiveInvite} size="large">
<ReplyIcon /> <ReplyIcon />
</IconButton> </IconButton>

@ -3,7 +3,7 @@ import type { Faction } from "./Faction";
import { Augmentations } from "../Augmentation/Augmentations"; import { Augmentations } from "../Augmentation/Augmentations";
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { AugmentationName, FactionName } from "@enums"; import { AugmentationName } from "@enums";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Player } from "@player"; import { Player } from "@player";
@ -20,7 +20,7 @@ import { InvitationEvent } from "./ui/InvitationModal";
import { SFC32RNG } from "../Casino/RNG"; import { SFC32RNG } from "../Casino/RNG";
import { isFactionWork } from "../Work/FactionWork"; import { isFactionWork } from "../Work/FactionWork";
import { getAugCost } from "../Augmentation/AugmentationHelpers"; import { getAugCost } from "../Augmentation/AugmentationHelpers";
import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record"; import { getRecordKeys } from "../Types/Record";
export function inviteToFaction(faction: Faction): void { export function inviteToFaction(faction: Faction): void {
if (faction.alreadyInvited || faction.isMember) return; if (faction.alreadyInvited || faction.isMember) return;
@ -34,23 +34,18 @@ export function inviteToFaction(faction: Faction): void {
export function joinFaction(faction: Faction): void { export function joinFaction(faction: Faction): void {
if (faction.isMember) return; if (faction.isMember) return;
faction.isMember = true; faction.isMember = true;
Player.factions.push(faction.name); // Add this faction to player's faction list, keeping it in standard order
let i = 0; Player.factions = getRecordKeys(Factions).filter((facName) => Factions[facName].isMember);
const factionIndexes = createEnumKeyedRecord(FactionName, (__) => i++);
Player.factions.sort((a, b) => factionIndexes[a] - factionIndexes[b]);
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction // Ban player from this faction's enemies
for (const enemy of factionInfo.enemies) { for (const enemy of faction.getInfo().enemies) {
if (Factions[enemy]) Factions[enemy].isBanned = true; if (Factions[enemy]) Factions[enemy].isBanned = true;
Player.factionRumors.delete(enemy); Player.factionRumors.delete(enemy);
} }
for (let i = 0; i < Player.factionInvitations.length; ++i) { // Remove invalid invites and rumors
if (Player.factionInvitations[i] == faction.name || Factions[Player.factionInvitations[i]].isBanned) { Player.factionInvitations = Player.factionInvitations.filter((factionName) => {
Player.factionInvitations.splice(i, 1); return !Factions[factionName].isMember && !Factions[factionName].isBanned;
i--; });
}
}
Player.factionRumors.delete(faction.name); Player.factionRumors.delete(faction.name);
} }

@ -430,6 +430,25 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
keepOnInstall: false, keepOnInstall: false,
}), }),
[FactionName.CyberSec]: new FactionInfo({
infoText: (
<>
The Internet is the first thing that was built that we don't fully understand, the largest experiment in anarchy
that we have ever had. And as the world becomes increasingly dominated by it, society approaches the brink of
total chaos. We serve only to protect society, to protect humanity, to protect the world from imminent collapse.
</>
),
rumorText: (
<>
A hacking group known as {FactionName.CyberSec} will invite you to join them if you demonstrate your hacking
skills on their server.
</>
),
inviteReqs: [haveBackdooredServer(SpecialServers.CyberSecServer)],
rumorReqs: [haveFile(MessageFilename.CyberSecTest)],
offerHackingWork: true,
}),
// City factions, essentially governments // City factions, essentially governments
[FactionName.Aevum]: new FactionInfo({ [FactionName.Aevum]: new FactionInfo({
infoText: <>The Silicon City.</>, infoText: <>The Silicon City.</>,
@ -631,25 +650,6 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
offerSecurityWork: true, offerSecurityWork: true,
}), }),
[FactionName.CyberSec]: new FactionInfo({
infoText: (
<>
The Internet is the first thing that was built that we don't fully understand, the largest experiment in anarchy
that we have ever had. And as the world becomes increasingly dominated by it, society approaches the brink of
total chaos. We serve only to protect society, to protect humanity, to protect the world from imminent collapse.
</>
),
rumorText: (
<>
A hacking group known as {FactionName.CyberSec} will invite you to join them if you demonstrate your hacking
skills on their server.
</>
),
inviteReqs: [haveBackdooredServer(SpecialServers.CyberSecServer)],
rumorReqs: [haveFile(MessageFilename.CyberSecTest)],
offerHackingWork: true,
}),
// Special Factions // Special Factions
[FactionName.Bladeburners]: new FactionInfo({ [FactionName.Bladeburners]: new FactionInfo({
infoText: ( infoText: (

@ -209,16 +209,16 @@ export function FactionsRoot(): React.ReactElement {
const theme = useTheme(); const theme = useTheme();
const rerender = useRerender(200); const rerender = useRerender(200);
useEffect(() => { useEffect(() => {
Player.factionInvitations.forEach((faction) => { Player.factionInvitations.forEach((factionName) => {
InvitationsSeen.add(faction); InvitationsSeen.add(factionName);
}); });
}, []); }, []);
const allFactions = Object.values(FactionName).map((faction) => faction as string); // Display joined factions in the standard order
const allJoinedFactions = [...Player.factions].map((facName) => Factions[facName]).filter((faction) => !!faction); const joinedFactions = Object.values(Factions).filter((faction) => faction.isMember);
allJoinedFactions.sort((a, b) => allFactions.indexOf(a.name) - allFactions.indexOf(b.name)); // Display invitations and rumors in the order they were received
const invitedFactions = Player.factionInvitations.map((facName) => Factions[facName]).filter((faction) => !!faction);
const invitations = Player.factionInvitations.map((facName) => Factions[facName]).filter((faction) => !!faction); const rumoredFactions = [...Player.factionRumors].map((facName) => Factions[facName]).filter((faction) => !!faction);
return ( return (
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}> <Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
@ -241,7 +241,7 @@ export function FactionsRoot(): React.ReactElement {
display="grid" display="grid"
sx={{ sx={{
gap: 1, gap: 1,
gridTemplateColumns: (invitations.length > 0 ? "1fr " : "") + "2fr", gridTemplateColumns: (invitedFactions.length > 0 ? "1fr " : "") + "2fr",
[theme.breakpoints.down("lg")]: { gridTemplateColumns: "1fr", "& > span:nth-of-type(1)": { order: 1 } }, [theme.breakpoints.down("lg")]: { gridTemplateColumns: "1fr", "& > span:nth-of-type(1)": { order: 1 } },
gridTemplateRows: "minmax(0, 1fr)", gridTemplateRows: "minmax(0, 1fr)",
"& > span > .MuiBox-root": { "& > span > .MuiBox-root": {
@ -251,35 +251,22 @@ export function FactionsRoot(): React.ReactElement {
}, },
}} }}
> >
<span> <span className="factions-invites">
{invitations.length > 0 && ( {invitedFactions.length > 0 && (
<> <>
<Typography variant="h5" color="primary"> <Typography variant="h5" color="primary">
Faction Invitations Faction Invitations
</Typography> </Typography>
<Box> <Box>
{invitations.map((faction) => ( {invitedFactions.map((faction) => (
<FactionElement key={faction.name} faction={faction} rerender={rerender} /> <FactionElement key={faction.name} faction={faction} rerender={rerender} />
))} ))}
</Box> </Box>
</> </>
)} )}
{Player.factionRumors.size > 0 && (
<>
<Typography variant="h5" color="primary">
Rumors
</Typography>
<div style={{ display: "grid", gap: 1, gridAutoRows: "minmax(70px, auto)" }}>
{[...Player.factionRumors].map((factionName) => (
<FactionElement key={factionName} faction={Factions[factionName]} rerender={rerender} />
))}
</div>
</>
)}
</span> </span>
<span> <span className="factions-joined">
{Player.inGang() && ( {Player.inGang() && (
<> <>
<Typography variant="h5" color="primary"> <Typography variant="h5" color="primary">
@ -294,8 +281,8 @@ export function FactionsRoot(): React.ReactElement {
Your Factions Your Factions
</Typography> </Typography>
<Box> <Box>
{allJoinedFactions.length > 0 ? ( {joinedFactions.length > 0 ? (
allJoinedFactions.map((faction) => { joinedFactions.map((faction) => {
if (Player.getGangName() === faction.name) return null; if (Player.getGangName() === faction.name) return null;
return <FactionElement key={faction.name} faction={faction} rerender={rerender} />; return <FactionElement key={faction.name} faction={faction} rerender={rerender} />;
}) })
@ -305,6 +292,20 @@ export function FactionsRoot(): React.ReactElement {
</Box> </Box>
</span> </span>
</Box> </Box>
<span className="factions-rumors">
{rumoredFactions.length > 0 && (
<>
<Typography variant="h5" color="primary">
Rumors
</Typography>
<Box style={{ display: "grid", gap: 1, gridAutoRows: "minmax(70px, auto)" }}>
{rumoredFactions.map((faction) => (
<FactionElement key={faction.name} faction={faction} rerender={rerender} />
))}
</Box>
</>
)}
</span>
</Container> </Container>
); );
} }

@ -171,7 +171,8 @@ export function prestigeSourceFile(this: PlayerObject): void {
export function receiveInvite(this: PlayerObject, factionName: FactionName): void { export function receiveInvite(this: PlayerObject, factionName: FactionName): void {
const faction = Factions[factionName]; const faction = Factions[factionName];
if (faction.alreadyInvited || faction.isMember || faction.isBanned) return; if (this.factionInvitations.includes(factionName) || faction.alreadyInvited || faction.isMember || faction.isBanned)
return;
this.factionInvitations.push(factionName); this.factionInvitations.push(factionName);
this.factionRumors.delete(factionName); this.factionRumors.delete(factionName);
faction.discovery = FactionDiscovery.known; faction.discovery = FactionDiscovery.known;

@ -35,13 +35,13 @@ export function prestigeAugmentation(): void {
initBitNodeMultipliers(); initBitNodeMultipliers();
// Maintain invites to factions with the 'keepOnInstall' flag, and rumors about others // Maintain invites to factions with the 'keepOnInstall' flag, and rumors about others
const maintainInvites = []; const maintainInvites = new Set<FactionName>();
const maintainRumors = []; const maintainRumors = new Set<FactionName>();
for (const facName of [...Player.factions, ...Player.factionInvitations]) { for (const facName of [...Player.factions, ...Player.factionInvitations]) {
if (Factions[facName].getInfo().keep) { if (Factions[facName].getInfo().keep) {
maintainInvites.push(facName); maintainInvites.add(facName);
} else { } else {
maintainRumors.push(facName); maintainRumors.add(facName);
} }
} }
@ -92,8 +92,10 @@ export function prestigeAugmentation(): void {
// Recalculate the bonus for circadian modulator aug // Recalculate the bonus for circadian modulator aug
initCircadianModulator(); initCircadianModulator();
Player.factionInvitations = Player.factionInvitations.concat(maintainInvites); Player.factionInvitations = Player.factionInvitations.concat([...maintainInvites]);
for (const factionName of maintainInvites) Factions[factionName].alreadyInvited = true; for (const factionName of maintainInvites) {
Factions[factionName].alreadyInvited = true;
}
Player.reapplyAllAugmentations(); Player.reapplyAllAugmentations();
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
Player.hp.current = Player.hp.max; Player.hp.current = Player.hp.max;