Remove all uses of any in Gang, Train Combat and Train Hacking are now the best exp gains, gang equipment and augs now give exp boosts

This commit is contained in:
Olivier Gagnon 2021-06-17 11:24:52 -04:00
parent 07cca48a17
commit 2c7fbc03cf
17 changed files with 137 additions and 132 deletions

@ -24,6 +24,7 @@ import { GangMemberUpgrade } from "./GangMemberUpgrade";
import { GangConstants } from "./data/Constants"; import { GangConstants } from "./data/Constants";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { GangMemberTasks } from "./GangMemberTasks"; import { GangMemberTasks } from "./GangMemberTasks";
import { IAscensionResult } from "./IAscensionResult";
import { AllGangs } from "./AllGangs"; import { AllGangs } from "./AllGangs";
import { GangMember } from "./GangMember"; import { GangMember } from "./GangMember";
@ -53,7 +54,7 @@ export class Gang {
notifyMemberDeath: boolean; notifyMemberDeath: boolean;
constructor(facName: string = "", hacking: boolean = false) { constructor(facName = "", hacking = false) {
this.facName = facName; this.facName = facName;
this.members = []; this.members = [];
this.wanted = 1; this.wanted = 1;
@ -87,7 +88,7 @@ export class Gang {
return AllGangs[this.facName].territory; return AllGangs[this.facName].territory;
} }
process(numCycles: number = 1, player: IPlayer): void { process(numCycles = 1, player: IPlayer): void {
const CyclesPerSecond = 1000 / CONSTANTS._idleSpeed; const CyclesPerSecond = 1000 / CONSTANTS._idleSpeed;
if (isNaN(numCycles)) { if (isNaN(numCycles)) {
@ -110,7 +111,7 @@ export class Gang {
} }
processGains(numCycles: number = 1, player: IPlayer): void { processGains(numCycles = 1, player: IPlayer): void {
// Get gains per cycle // Get gains per cycle
let moneyGains = 0, respectGains = 0, wantedLevelGains = 0; let moneyGains = 0, respectGains = 0, wantedLevelGains = 0;
let justice = 0; let justice = 0;
@ -170,7 +171,7 @@ export class Gang {
} }
} }
processTerritoryAndPowerGains(numCycles: number = 1): void { processTerritoryAndPowerGains(numCycles = 1): void {
this.storedTerritoryAndPowerCycles += numCycles; this.storedTerritoryAndPowerCycles += numCycles;
if (this.storedTerritoryAndPowerCycles < GangConstants.CyclesPerTerritoryAndPowerUpdate) { return; } if (this.storedTerritoryAndPowerCycles < GangConstants.CyclesPerTerritoryAndPowerUpdate) { return; }
this.storedTerritoryAndPowerCycles -= GangConstants.CyclesPerTerritoryAndPowerUpdate; this.storedTerritoryAndPowerCycles -= GangConstants.CyclesPerTerritoryAndPowerUpdate;
@ -268,14 +269,14 @@ export class Gang {
} }
} }
processExperienceGains(numCycles: number = 1): void { processExperienceGains(numCycles = 1): void {
for (let i = 0; i < this.members.length; ++i) { for (let i = 0; i < this.members.length; ++i) {
this.members[i].gainExperience(numCycles); this.members[i].gainExperience(numCycles);
this.members[i].updateSkillLevels(); this.members[i].updateSkillLevels();
} }
} }
clash(won: boolean = false): void { clash(won = false): void {
// Determine if a gang member should die // Determine if a gang member should die
let baseDeathChance = 0.01; let baseDeathChance = 0.01;
if (won) { baseDeathChance /= 2; } if (won) { baseDeathChance /= 2; }
@ -370,14 +371,8 @@ export class Gang {
} }
ascendMember(member: GangMember, workerScript: WorkerScript): void { ascendMember(member: GangMember, workerScript?: WorkerScript): IAscensionResult {
try { try {
// res is an object with the following format:
// {
// respect: Amount of respect to deduct
// hack/str/def/dex/agi/cha: Ascension multipliers gained for each stat
// }
const res = member.ascend(); const res = member.ascend();
this.respect = Math.max(1, this.respect - res.respect); this.respect = Math.max(1, this.respect - res.respect);
if (workerScript == null) { if (workerScript == null) {
@ -399,9 +394,8 @@ export class Gang {
} catch(e) { } catch(e) {
if (workerScript == null) { if (workerScript == null) {
exceptionAlert(e); exceptionAlert(e);
} else {
throw e; // Re-throw, will be caught in the Netscript Function
} }
throw e; // Re-throw, will be caught in the Netscript Function
} }
} }

@ -2,12 +2,22 @@ import { GangMemberTask } from "./GangMemberTask";
import { GangMemberTasks } from "./GangMemberTasks"; import { GangMemberTasks } from "./GangMemberTasks";
import { GangMemberUpgrade } from "./GangMemberUpgrade"; import { GangMemberUpgrade } from "./GangMemberUpgrade";
import { GangMemberUpgrades } from "./GangMemberUpgrades"; import { GangMemberUpgrades } from "./GangMemberUpgrades";
import { IAscensionResult } from "./IAscensionResult";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { GangConstants } from "./data/Constants"; import { GangConstants } from "./data/Constants";
import { AllGangs } from "./AllGangs"; import { AllGangs } from "./AllGangs";
import { IGang } from "./IGang"; import { IGang } from "./IGang";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
interface IMults {
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
}
export class GangMember { export class GangMember {
name: string; name: string;
task = "Unassigned"; task = "Unassigned";
@ -67,13 +77,12 @@ export class GangMember {
} }
assignToTask(taskName: string): boolean { assignToTask(taskName: string): boolean {
if (GangMemberTasks.hasOwnProperty(taskName)) { if (!GangMemberTasks.hasOwnProperty(taskName)) {
this.task = taskName;
return true;
} else {
this.task = "Unassigned"; this.task = "Unassigned";
return false; return false;
} }
this.task = taskName;
return true;
} }
unassignFromTask(): void { unassignFromTask(): void {
@ -151,25 +160,37 @@ export class GangMember {
return 5 * task.baseMoney * statWeight * territoryMult * respectMult; return 5 * task.baseMoney * statWeight * territoryMult * respectMult;
} }
expMult(): IMults {
return {
hack: (this.hack_mult-1)/10+1,
str: (this.str_mult-1)/10+1,
def: (this.def_mult-1)/10+1,
dex: (this.dex_mult-1)/10+1,
agi: (this.agi_mult-1)/10+1,
cha: (this.cha_mult-1)/10+1,
};
}
gainExperience(numCycles = 1): void { gainExperience(numCycles = 1): void {
const task = this.getTask(); const task = this.getTask();
if (task === GangMemberTasks["Unassigned"]) return; if (task === GangMemberTasks["Unassigned"]) return;
const difficultyMult = Math.pow(task.difficulty, 0.9); const difficultyMult = Math.pow(task.difficulty, 0.9);
const difficultyPerCycles = difficultyMult * numCycles; const difficultyPerCycles = difficultyMult * numCycles;
const weightDivisor = 1500; const weightDivisor = 1500;
this.hack_exp += (task.hackWeight / weightDivisor) * difficultyPerCycles; const expMult = this.expMult();
this.str_exp += (task.strWeight / weightDivisor) * difficultyPerCycles; this.hack_exp += (task.hackWeight / weightDivisor) * difficultyPerCycles * expMult.hack;
this.def_exp += (task.defWeight / weightDivisor) * difficultyPerCycles; this.str_exp += (task.strWeight / weightDivisor) * difficultyPerCycles * expMult.str;
this.dex_exp += (task.dexWeight / weightDivisor) * difficultyPerCycles; this.def_exp += (task.defWeight / weightDivisor) * difficultyPerCycles * expMult.def;
this.agi_exp += (task.agiWeight / weightDivisor) * difficultyPerCycles; this.dex_exp += (task.dexWeight / weightDivisor) * difficultyPerCycles * expMult.dex;
this.cha_exp += (task.chaWeight / weightDivisor) * difficultyPerCycles; this.agi_exp += (task.agiWeight / weightDivisor) * difficultyPerCycles * expMult.agi;
this.cha_exp += (task.chaWeight / weightDivisor) * difficultyPerCycles * expMult.cha;
} }
recordEarnedRespect(numCycles = 1, gang: IGang): void { recordEarnedRespect(numCycles = 1, gang: IGang): void {
this.earnedRespect += (this.calculateRespectGain(gang) * numCycles); this.earnedRespect += (this.calculateRespectGain(gang) * numCycles);
} }
getAscensionResults(): any { getAscensionResults(): IMults {
//Calculate ascension bonus to stat multipliers. //Calculate ascension bonus to stat multipliers.
//This is based on the current number of multipliers from Non-Augmentation upgrades //This is based on the current number of multipliers from Non-Augmentation upgrades
//+ Ascension Bonus = N% of current bonus from Augmentations //+ Ascension Bonus = N% of current bonus from Augmentations
@ -201,7 +222,7 @@ export class GangMember {
} }
} }
getAscensionEfficiency(): any { getAscensionEfficiency(): IMults {
function formula(mult: number): number { function formula(mult: number): number {
return 1/(1+Math.log(mult)/Math.log(20)); return 1/(1+Math.log(mult)/Math.log(20));
} }
@ -215,7 +236,7 @@ export class GangMember {
}; };
} }
ascend(): any { ascend(): IAscensionResult {
const res = this.getAscensionResults(); const res = this.getAscensionResults();
const hackAscMult = res.hack; const hackAscMult = res.hack;
const strAscMult = res.str; const strAscMult = res.str;
@ -275,12 +296,6 @@ export class GangMember {
} }
buyUpgrade(upg: GangMemberUpgrade, player: IPlayer, gang: IGang): boolean { buyUpgrade(upg: GangMemberUpgrade, player: IPlayer, gang: IGang): boolean {
if (typeof upg === 'string') {
upg = GangMemberUpgrades[upg];
}
if (!(upg instanceof GangMemberUpgrade)) {
return false;
}
// Prevent purchasing of already-owned upgrades // Prevent purchasing of already-owned upgrades
if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) { if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) {
return false; return false;

@ -1,23 +1,4 @@
import { ITaskParams, ITerritory } from "./ITaskParams";
interface ITerritory {
money: number;
respect: number;
wanted: number;
}
export interface ITaskParams {
baseRespect?: number;
baseWanted?: number;
baseMoney?: number;
hackWeight?: number;
strWeight?: number;
defWeight?: number;
dexWeight?: number;
agiWeight?: number;
chaWeight?: number;
difficulty?: number;
territory?: ITerritory;
}
export class GangMemberTask { export class GangMemberTask {
name: string; name: string;

@ -34,6 +34,7 @@ export function displayGangContent(engine: IEngine, gang: Gang, player: IPlayer)
} }
export function clearGangUI(): void { export function clearGangUI(): void {
if(UIElems.gangContainer) UIElems.gangContainer.style.display = 'none';
if (UIElems.gangContainer instanceof Element) ReactDOM.unmountComponentAtNode(UIElems.gangContainer); if (UIElems.gangContainer instanceof Element) ReactDOM.unmountComponentAtNode(UIElems.gangContainer);
UIElems.gangContainer = null; UIElems.gangContainer = null;
UIElems.gangContentCreated = false; UIElems.gangContentCreated = false;

@ -0,0 +1,9 @@
export interface IAscensionResult {
respect: number;
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
};

20
src/Gang/ITaskParams.ts Normal file

@ -0,0 +1,20 @@
export interface ITerritory {
money: number;
respect: number;
wanted: number;
}
export interface ITaskParams {
baseRespect?: number;
baseWanted?: number;
baseMoney?: number;
hackWeight?: number;
strWeight?: number;
defWeight?: number;
dexWeight?: number;
agiWeight?: number;
chaWeight?: number;
difficulty?: number;
territory?: ITerritory;
}

@ -1,3 +1,4 @@
import { ITaskParams } from "../ITaskParams";
/* tslint:disable:max-line-length */ /* tslint:disable:max-line-length */
/** /**
@ -29,7 +30,7 @@ export interface IGangMemberTaskMetadata {
* An object containing weighting parameters for the task. These parameters are used for * An object containing weighting parameters for the task. These parameters are used for
* various calculations (respect gain, wanted gain, etc.) * various calculations (respect gain, wanted gain, etc.)
*/ */
params?: any; params: ITaskParams;
} }
/** /**
@ -254,7 +255,7 @@ export const gangMemberTasksMetadata: IGangMemberTaskMetadata[] = [
name: "Train Combat", name: "Train Combat",
params: { params: {
strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 25, strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 25,
difficulty: 5, difficulty: 200,
}, },
}, },
{ {
@ -262,7 +263,7 @@ export const gangMemberTasksMetadata: IGangMemberTaskMetadata[] = [
isCombat: true, isCombat: true,
isHacking: true, isHacking: true,
name: "Train Hacking", name: "Train Hacking",
params: {hackWeight: 100, difficulty: 8}, params: {hackWeight: 100, difficulty: 45},
}, },
{ {
desc: "Assign this gang member to train their charisma", desc: "Assign this gang member to train their charisma",

@ -1,20 +1,23 @@
import * as React from "react"; import React, { useState } from "react";
import { Panel1 } from "./Panel1"; import { Panel1 } from "./Panel1";
import { Panel2 } from "./Panel2"; import { Panel2 } from "./Panel2";
import { Panel3 } from "./Panel3"; import { Panel3 } from "./Panel3";
import { Gang } from "../Gang";
import { GangMember } from "../GangMember";
interface IProps { interface IProps {
gang: any; gang: Gang;
member: any; member: GangMember;
} }
export function GangMemberAccordionContent(props: IProps): React.ReactElement { export function GangMemberAccordionContent(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
return (<> return (<>
<div className={"gang-member-info-div tooltip"}> <div className={"gang-member-info-div tooltip"}>
<Panel1 gang={props.gang} member={props.member} /> <Panel1 gang={props.gang} member={props.member} />
</div> </div>
<div className={"gang-member-info-div"}> <div className={"gang-member-info-div"}>
<Panel2 gang={props.gang} member={props.member} /> <Panel2 onTaskChange={()=>setRerender(old => !old)} gang={props.gang} member={props.member} />
</div> </div>
<div className={"gang-member-info-div"}> <div className={"gang-member-info-div"}>
<Panel3 member={props.member} /> <Panel3 member={props.member} />

@ -4,21 +4,17 @@ import { GangMemberAccordionContent } from "./GangMemberAccordionContent"
import { GangMemberUpgradePopup } from "./GangMemberUpgradePopup" import { GangMemberUpgradePopup } from "./GangMemberUpgradePopup"
import { createPopup } from "../../ui/React/createPopup"; import { createPopup } from "../../ui/React/createPopup";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { Gang } from "../Gang";
import { GangMember } from "../GangMember";
interface IProps { interface IProps {
gang: any; gang: Gang;
player: IPlayer; player: IPlayer;
} }
export function GangMemberList(props: IProps): React.ReactElement { export function GangMemberList(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const [filter, setFilter] = useState(""); const [filter, setFilter] = useState("");
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
function openUpgradePopup(): void { function openUpgradePopup(): void {
const popupId = `gang-upgrade-popup`; const popupId = `gang-upgrade-popup`;
createPopup(popupId, GangMemberUpgradePopup, { createPopup(popupId, GangMemberUpgradePopup, {
@ -32,15 +28,15 @@ export function GangMemberList(props: IProps): React.ReactElement {
setFilter(event.target.value); setFilter(event.target.value);
} }
function members(): any { function members(): GangMember[] {
return props.gang.members.filter((member: any) => member.name.indexOf(filter) > -1 || member.task.indexOf(filter) > -1) return props.gang.members.filter((member: GangMember) => member.name.indexOf(filter) > -1 || member.task.indexOf(filter) > -1)
} }
return (<> return (<>
<input className="text-input" placeholder="Filter gang member" style={{margin: "5px", padding: "5px"}} value={filter} onChange={onChange} /> <input className="text-input" placeholder="Filter gang member" style={{margin: "5px", padding: "5px"}} value={filter} onChange={onChange} />
<a className="a-link-button" style={{display: 'inline-block'}} onClick={openUpgradePopup}>Manage Equipment</a> <a className="a-link-button" style={{display: 'inline-block'}} onClick={openUpgradePopup}>Manage Equipment</a>
<ul> <ul>
{members().map((member: any) => <li key={member.name}> {members().map((member: GangMember) => <li key={member.name}>
<Accordion <Accordion
panelInitiallyOpened={true} panelInitiallyOpened={true}
headerContent={<>{member.name}</>} headerContent={<>{member.name}</>}

@ -6,10 +6,12 @@ import { GangMemberUpgrade } from "../GangMemberUpgrade";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { removePopup } from "../../ui/React/createPopup"; import { removePopup } from "../../ui/React/createPopup";
import { GangMember } from "../GangMember";
import { Gang } from "../Gang";
interface IPanelProps { interface IPanelProps {
member: any; member: GangMember;
gang: any; gang: Gang;
player: IPlayer; player: IPlayer;
} }
@ -79,8 +81,8 @@ Agi: {props.member.agi} (x{formatNumber(props.member.agi_mult * props.member.ag
Cha: {props.member.cha} (x{formatNumber(props.member.cha_mult * props.member.cha_asc_mult, 2)}) Cha: {props.member.cha} (x{formatNumber(props.member.cha_mult * props.member.cha_asc_mult, 2)})
</pre> </pre>
<div className="gang-owned-upgrades-div"> <div className="gang-owned-upgrades-div">
Purchased Upgrades: {props.member.upgrades.map((upg: any) => purchased(upg))} Purchased Upgrades: {props.member.upgrades.map((upg: string) => purchased(upg))}
{props.member.augmentations.map((upg: any) => purchased(upg))} {props.member.augmentations.map((upg: string) => purchased(upg))}
</div> </div>
<div style={{width: "20%", display: "inline-block"}}> <div style={{width: "20%", display: "inline-block"}}>
<h2>Weapons</h2> <h2>Weapons</h2>
@ -106,7 +108,7 @@ Cha: {props.member.cha} (x{formatNumber(props.member.cha_mult * props.member.ch
} }
interface IProps { interface IProps {
gang: any; gang: Gang;
player: IPlayer; player: IPlayer;
popupId: string; popupId: string;
} }
@ -115,16 +117,17 @@ export function GangMemberUpgradePopup(props: IProps): React.ReactElement {
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
const [filter, setFilter] = useState(""); const [filter, setFilter] = useState("");
function closePopup(): void { function closePopup(this: Window, ev: KeyboardEvent): void {
if(ev.keyCode !== 27) return;
removePopup(props.popupId); removePopup(props.popupId);
} }
useEffect(() => { useEffect(() => {
window.addEventListener('keydown', closePopup); window.addEventListener<'keydown'>('keydown', closePopup);
const id = setInterval(() => setRerender(old => !old), 1000); const id = setInterval(() => setRerender(old => !old), 1000);
return () => { return () => {
clearInterval(id); clearInterval(id);
window.removeEventListener('keydown', closePopup); window.removeEventListener<'keydown'>('keydown', closePopup);
} }
}, []); }, []);
@ -134,6 +137,6 @@ export function GangMemberUpgradePopup(props: IProps): React.ReactElement {
Discount: -{numeralWrapper.formatPercentage(1 - 1 / props.gang.getDiscount())} Discount: -{numeralWrapper.formatPercentage(1 - 1 / props.gang.getDiscount())}
<span className="tooltiptext">You get a discount on equipment and upgrades based on your gang's respect and power. More respect and power leads to more discounts.</span> <span className="tooltiptext">You get a discount on equipment and upgrades based on your gang's respect and power. More respect and power leads to more discounts.</span>
</p> </p>
{props.gang.members.map((member: any) => <GangMemberUpgradePanel key={member.name} player={props.player} gang={props.gang} member={member} />)} {props.gang.members.map((member: GangMember) => <GangMemberUpgradePanel key={member.name} player={props.player} gang={props.gang} member={member} />)}
</>); </>);
} }

@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { Gang } from "../Gang";
import { import {
formatNumber, formatNumber,
@ -14,7 +15,7 @@ import { createPopup, removePopup } from "../../ui/React/createPopup";
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
interface IRecruitPopupProps { interface IRecruitPopupProps {
gang: any; gang: Gang;
popupId: string; popupId: string;
} }
@ -45,12 +46,12 @@ function recruitPopup(props: IRecruitPopupProps): React.ReactElement {
removePopup(props.popupId); removePopup(props.popupId);
} }
function onKeyUp(event: any): void { function onKeyUp(event: React.KeyboardEvent<HTMLInputElement>): void {
if(event.keyCode === 13) recruit(); if(event.keyCode === 13) recruit();
if(event.keyCode === 27) cancel(); if(event.keyCode === 27) cancel();
} }
function onChange(event: any): void { function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
setName(event.target.value); setName(event.target.value);
} }
@ -68,7 +69,7 @@ function recruitPopup(props: IRecruitPopupProps): React.ReactElement {
} }
interface IProps { interface IProps {
gang: any; gang: Gang;
} }
function Recruitment(props: IProps): React.ReactElement { function Recruitment(props: IProps): React.ReactElement {
@ -120,13 +121,6 @@ function BonusTime(props: IProps): React.ReactElement {
} }
export function GangStats(props: IProps): React.ReactElement { export function GangStats(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
const territoryMult = AllGangs[props.gang.facName].territory * 100; const territoryMult = AllGangs[props.gang.facName].territory * 100;
let territoryStr; let territoryStr;
if (territoryMult <= 0) { if (territoryMult <= 0) {

@ -1,10 +1,11 @@
import * as React from "react"; import React, { useState, useEffect } from "react";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { GangStats } from "./GangStats"; import { GangStats } from "./GangStats";
import { Gang } from "../Gang";
import { GangMemberList } from "./GangMemberList"; import { GangMemberList } from "./GangMemberList";
interface IProps { interface IProps {
gang: any; gang: Gang;
player: IPlayer; player: IPlayer;
} }

@ -3,10 +3,12 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
import { formatNumber } from "../../../utils/StringHelperFunctions"; import { formatNumber } from "../../../utils/StringHelperFunctions";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { createPopup, removePopup } from "../../ui/React/createPopup"; import { createPopup, removePopup } from "../../ui/React/createPopup";
import { Gang } from "../Gang";
import { GangMember } from "../GangMember";
interface IAscendProps { interface IAscendProps {
member: any; member: GangMember;
gang: any; gang: Gang;
popupId: string; popupId: string;
} }
@ -43,17 +45,11 @@ Charisma: +{numeralWrapper.formatPercentage(ascendBenefits.cha/100)}<br />
} }
interface IProps { interface IProps {
member: any; member: GangMember;
gang: any; gang: Gang;
} }
export function Panel1(props: IProps): React.ReactElement { export function Panel1(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
function ascend(): void { function ascend(): void {
const popupId = `gang-management-ascend-member ${props.member.name}`; const popupId = `gang-management-ascend-member ${props.member.name}`;

@ -2,25 +2,23 @@ import React, { useState, useEffect } from "react";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { StatsTable } from "../../ui/React/StatsTable"; import { StatsTable } from "../../ui/React/StatsTable";
import { MoneyRate } from "../../ui/React/MoneyRate"; import { MoneyRate } from "../../ui/React/MoneyRate";
import { Gang } from "../Gang";
import { GangMember } from "../GangMember";
interface IProps { interface IProps {
member: any; member: GangMember;
gang: any; gang: Gang;
onTaskChange: () => void;
} }
export function Panel2(props: IProps): React.ReactElement { export function Panel2(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const [currentTask, setCurrentTask] = useState(props.member.task); const [currentTask, setCurrentTask] = useState(props.member.task);
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
function onChange(event: React.ChangeEvent<HTMLSelectElement>): void { function onChange(event: React.ChangeEvent<HTMLSelectElement>): void {
const task = event.target.value; const task = event.target.value;
props.member.assignToTask(task); props.member.assignToTask(task);
setCurrentTask(task); setCurrentTask(task);
props.onTaskChange();
} }
const tasks = props.gang.getAllTaskNames(); const tasks = props.gang.getAllTaskNames();
@ -39,7 +37,7 @@ export function Panel2(props: IProps): React.ReactElement {
id={`${props.member.name}-gang-member-task-selector`} id={`${props.member.name}-gang-member-task-selector`}
value={currentTask}> value={currentTask}>
<option key={0} value={"---"}>---</option> <option key={0} value={"---"}>---</option>
{tasks.map((task: any, i: number) => <option key={i+1} value={task}>{task}</option>)} {tasks.map((task: string, i: number) => <option key={i+1} value={task}>{task}</option>)}
</select> </select>
<div id={`${name}-gang-member-gain-info`}>{StatsTable(data, null)}</div> <div id={`${name}-gang-member-gain-info`}>{StatsTable(data, null)}</div>
</>); </>);

@ -1,20 +1,12 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { GangMemberTasks } from "../GangMemberTasks"; import { GangMemberTasks } from "../GangMemberTasks";
import { GangMember } from "../GangMember";
interface IProps { interface IProps {
member: any; member: GangMember;
} }
export function Panel3(props: IProps): React.ReactElement { export function Panel3(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => {
setRerender(old => !old);
}, 1000);
return () => clearInterval(id);
}, []);
const task = GangMemberTasks[props.member.task]; const task = GangMemberTasks[props.member.task];
const desc = task ? task.desc: GangMemberTasks["Unassigned"].desc; const desc = task ? task.desc: GangMemberTasks["Unassigned"].desc;

@ -1,18 +1,25 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { ManagementSubpage } from "./ManagementSubpage"; import { ManagementSubpage } from "./ManagementSubpage";
import { TerritorySubpage } from "./TerritorySubpage"; import { TerritorySubpage } from "./TerritorySubpage";
import { IEngine } from "../../IEngine"; import { IEngine } from "../../IEngine";
import { Gang } from "../Gang";
import { displayFactionContent } from "../../Faction/FactionHelpers"; import { displayFactionContent } from "../../Faction/FactionHelpers";
interface IProps { interface IProps {
gang: any; gang: Gang;
player: IPlayer; player: IPlayer;
engine: IEngine; engine: IEngine;
} }
export function Root(props: IProps): React.ReactElement { export function Root(props: IProps): React.ReactElement {
const [management, setManagement] = useState(true); const [management, setManagement] = useState(true);
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
function back(): void { function back(): void {
props.engine.loadFactionContent(); props.engine.loadFactionContent();

@ -3,19 +3,13 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
import { formatNumber } from "../../../utils/StringHelperFunctions"; import { formatNumber } from "../../../utils/StringHelperFunctions";
import { AllGangs } from "../AllGangs"; import { AllGangs } from "../AllGangs";
import { Gang } from "../Gang";
interface IProps { interface IProps {
gang: any; gang: Gang;
} }
export function TerritorySubpage(props: IProps): React.ReactElement { export function TerritorySubpage(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
function openWarfareHelp(): void { function openWarfareHelp(): void {
dialogBoxCreate("This percentage represents the chance you have of 'clashing' with " + dialogBoxCreate("This percentage represents the chance you have of 'clashing' with " +
"with another gang. If you do not wish to gain/lose territory, " + "with another gang. If you do not wish to gain/lose territory, " +