2018-10-02 23:54:56 +02:00
/ *
gang member upgrades - they should be cheaper as the gang gets more respect / power
kopelli09 / 12 / 2018
Another gang - related idea ( and perhaps I 'm not seeing it in the code) - gangs can lose power. Seems odd that the player' s power can drop by removing members , but the other gangs are forever gaining power ...
Grub09 / 12 / 2018
Maybe add a % chance of other gangs clashing ?
assign gangs a number of gang members and each clash kills a number of gang members based on each one ' s power
and they lose a proportionate number of members
Also add police clashes
balance point to keep them from running out of control
* /
import { gangMemberTasksMetadata } from "./data/gangmembertasks" ;
import { gangMemberUpgradesMetadata } from "./data/gangmemberupgrades" ;
2018-06-26 18:34:11 +02:00
import { Engine } from "./engine" ;
2018-03-27 02:46:21 +02:00
import { Faction , Factions ,
2018-06-26 18:34:11 +02:00
displayFactionContent } from "./Faction" ;
import { Player } from "./Player" ;
2018-09-12 17:53:08 +02:00
import { numeralWrapper } from "./ui/numeralFormat" ;
2018-06-26 18:34:11 +02:00
import { dialogBoxCreate } from "../utils/DialogBox" ;
2017-08-30 19:44:29 +02:00
import { Reviver , Generic _toJSON ,
2018-06-26 18:34:11 +02:00
Generic _fromJSON } from "../utils/JSONReviver" ;
2018-07-08 06:38:13 +02:00
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement" ;
2018-07-05 06:38:00 +02:00
import { createElement } from "../utils/uiHelpers/createElement" ;
2018-07-05 19:09:00 +02:00
import { createPopup } from "../utils/uiHelpers/createPopup" ;
2018-07-20 03:51:18 +02:00
import { Page , routing } from "./ui/navigationTracking" ;
2018-06-22 23:30:24 +02:00
import { formatNumber } from "../utils/StringHelperFunctions" ;
2018-10-02 23:54:56 +02:00
import { exceptionAlert } from "../utils/helpers/exceptionAlert" ;
2018-07-05 02:35:33 +02:00
import { getRandomInt } from "../utils/helpers/getRandomInt" ;
2018-07-08 06:00:57 +02:00
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement" ;
2018-07-08 05:42:58 +02:00
import { removeElement } from "../utils/uiHelpers/removeElement" ;
2018-07-05 19:36:02 +02:00
import { removeElementById } from "../utils/uiHelpers/removeElementById" ;
2017-08-30 19:44:29 +02:00
import { yesNoBoxCreate , yesNoTxtInpBoxCreate ,
yesNoBoxGetYesButton , yesNoBoxGetNoButton ,
yesNoTxtInpBoxGetYesButton , yesNoTxtInpBoxGetNoButton ,
yesNoTxtInpBoxGetInput , yesNoBoxClose ,
2018-06-26 18:34:11 +02:00
yesNoTxtInpBoxClose , yesNoBoxOpen } from "../utils/YesNoBox" ;
2017-08-30 19:44:29 +02:00
2018-10-02 18:45:00 +02:00
// Constants
const GangRespectToReputationRatio = 2 ; //Respect is divided by this to get rep gain
const MaximumGangMembers = 47 ;
const GangRecruitCostMultiplier = 2 ;
const GangTerritoryUpdateTimer = 150 ;
2018-10-02 23:54:56 +02:00
const AscensionMultiplierRatio = 10 / 100 ; //Portion upgrade multiplier is kept after ascending
2018-10-02 18:45:00 +02:00
// Switch between territory and management screen with 1 and 2
2017-08-13 07:01:33 +02:00
$ ( document ) . keydown ( function ( event ) {
2018-07-20 03:51:18 +02:00
if ( routing . isOn ( Page . Gang ) && ! yesNoBoxOpen ) {
2018-02-15 05:26:43 +01:00
if ( gangMemberFilter != null && gangMemberFilter === document . activeElement ) { return ; }
2017-08-13 07:01:33 +02:00
if ( event . keyCode === 49 ) {
2018-02-15 05:26:43 +01:00
if ( gangTerritorySubpage . style . display === "block" ) {
managementButton . click ( ) ;
2017-08-13 07:01:33 +02:00
}
} else if ( event . keyCode === 50 ) {
2018-02-15 05:26:43 +01:00
if ( gangManagementSubpage . style . display === "block" ) {
territoryButton . click ( ) ;
2017-08-13 07:01:33 +02:00
}
}
}
} ) ;
2017-08-20 03:36:19 +02:00
//Delete upgrade box when clicking outside
$ ( document ) . mousedown ( function ( event ) {
2018-02-15 05:26:43 +01:00
var boxId = "gang-member-upgrade-popup-box" ;
var contentId = "gang-member-upgrade-popup-box-content" ;
2017-08-20 03:36:19 +02:00
if ( gangMemberUpgradeBoxOpened ) {
2018-02-15 05:26:43 +01:00
if ( $ ( event . target ) . closest ( "#" + contentId ) . get ( 0 ) == null ) {
2017-08-20 03:36:19 +02:00
//Delete the box
2018-02-15 05:26:43 +01:00
removeElement ( gangMemberUpgradeBox ) ;
gangMemberUpgradeBox = null ;
gangMemberUpgradeBoxContent = null ;
2017-08-20 03:36:19 +02:00
gangMemberUpgradeBoxOpened = false ;
2018-02-15 05:26:43 +01:00
gangMemberUpgradeBoxElements = null ;
2017-08-20 03:36:19 +02:00
}
}
} ) ;
2017-08-30 19:44:29 +02:00
let GangNames = [ "Slum Snakes" , "Tetrads" , "The Syndicate" , "The Dark Army" , "Speakers for the Dead" ,
2017-08-13 07:01:33 +02:00
"NiteSec" , "The Black Hand" ] ;
2017-08-30 19:44:29 +02:00
let AllGangs = {
2017-08-13 07:01:33 +02:00
"Slum Snakes" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"Tetrads" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Syndicate" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Dark Army" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"Speakers for the Dead" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"NiteSec" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Black Hand" : {
power : 1 ,
territory : 1 / 7 ,
} ,
}
2017-09-02 22:05:42 +02:00
function resetGangs ( ) {
AllGangs = {
"Slum Snakes" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"Tetrads" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Syndicate" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Dark Army" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"Speakers for the Dead" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"NiteSec" : {
power : 1 ,
territory : 1 / 7 ,
} ,
"The Black Hand" : {
power : 1 ,
territory : 1 / 7 ,
} ,
}
}
2017-08-30 19:44:29 +02:00
function loadAllGangs ( saveString ) {
AllGangs = JSON . parse ( saveString , Reviver ) ;
}
2017-08-13 07:01:33 +02:00
//Power is an estimate of a gang's ability to gain/defend territory
2017-08-30 19:44:29 +02:00
let gangStoredPowerCycles = 0 ;
2017-08-13 07:01:33 +02:00
function processAllGangPowerGains ( numCycles = 1 ) {
if ( ! Player . inGang ( ) ) { return ; }
gangStoredPowerCycles += numCycles ;
if ( gangStoredPowerCycles < 150 ) { return ; }
var playerGangName = Player . gang . facName ;
for ( var name in AllGangs ) {
if ( AllGangs . hasOwnProperty ( name ) ) {
if ( name == playerGangName ) {
2017-08-15 22:22:46 +02:00
AllGangs [ name ] . power += Player . gang . calculatePower ( ) ;
2017-08-13 07:01:33 +02:00
} else {
2017-09-15 16:06:59 +02:00
var gain = Math . random ( ) * 0.02 ; //TODO Adjust as necessary
2017-08-15 22:22:46 +02:00
AllGangs [ name ] . power += ( gain ) ;
2017-08-13 07:01:33 +02:00
}
}
}
gangStoredPowerCycles -= 150 ;
}
2017-08-30 19:44:29 +02:00
let gangStoredTerritoryCycles = 0 ;
2017-08-13 07:01:33 +02:00
function processAllGangTerritory ( numCycles = 1 ) {
if ( ! Player . inGang ( ) ) { return ; }
gangStoredTerritoryCycles += numCycles ;
2018-10-02 18:45:00 +02:00
if ( gangStoredTerritoryCycles < GangTerritoryUpdateTimer ) { return ; }
2017-08-13 07:01:33 +02:00
for ( var i = 0 ; i < GangNames . length ; ++ i ) {
var other = getRandomInt ( 0 , GangNames . length - 1 ) ;
while ( other == i ) {
other = getRandomInt ( 0 , GangNames . length - 1 ) ;
}
var thisPwr = AllGangs [ GangNames [ i ] ] . power ;
var otherPwr = AllGangs [ GangNames [ other ] ] . power ;
var thisChance = thisPwr / ( thisPwr + otherPwr ) ;
2017-08-15 22:22:46 +02:00
2017-08-13 07:01:33 +02:00
if ( Math . random ( ) < thisChance ) {
2017-08-18 19:20:51 +02:00
if ( AllGangs [ GangNames [ other ] ] . territory <= 0 ) {
return ;
}
2017-08-13 07:01:33 +02:00
AllGangs [ GangNames [ i ] ] . territory += 0.0001 ;
2017-08-15 22:22:46 +02:00
AllGangs [ GangNames [ other ] ] . territory -= 0.0001 ;
2017-08-13 07:01:33 +02:00
} else {
2017-08-18 19:20:51 +02:00
if ( AllGangs [ GangNames [ i ] ] . territory <= 0 ) {
return ;
}
2017-08-13 07:01:33 +02:00
AllGangs [ GangNames [ i ] ] . territory -= 0.0001 ;
AllGangs [ GangNames [ other ] ] . territory += 0.0001 ;
}
}
2018-10-02 18:45:00 +02:00
gangStoredTerritoryCycles -= GangTerritoryUpdateTimer ;
2017-08-13 07:01:33 +02:00
}
/ * f a c t i o n - N a m e o f c o r r e s p o n d i n g f a c t i o n
hacking - Boolean indicating whether its a hacking gang or not
* /
function Gang ( facName , hacking = false ) {
this . facName = facName ;
this . members = [ ] ; //Array of GangMembers
this . wanted = 1 ;
this . respect = 1 ;
2017-08-15 22:22:46 +02:00
this . power = 0 ;
2017-08-13 07:01:33 +02:00
this . isHackingGang = hacking ;
this . respectGainRate = 0 ;
this . wantedGainRate = 0 ;
this . moneyGainRate = 0 ;
//When processing gains, this stores the number of cycles until some
//limit is reached, and then calculates and applies the gains only at that limit
this . storedCycles = 0 ;
}
Gang . prototype . process = function ( numCycles = 1 ) {
this . processGains ( numCycles ) ;
this . processExperienceGains ( numCycles ) ;
processAllGangPowerGains ( numCycles ) ;
processAllGangTerritory ( numCycles ) ;
}
Gang . prototype . processGains = function ( numCycles = 1 ) {
this . storedCycles += numCycles ;
if ( isNaN ( this . storedCycles ) ) {
console . log ( "ERROR: Gang's storedCylces is NaN" ) ;
this . storedCycles = 0 ;
}
2018-10-02 23:54:56 +02:00
if ( this . storedCycles < 25 ) { return ; } //Only process every 5 seconds at least
2017-08-13 07:01:33 +02:00
//Get gains per cycle
var moneyGains = 0 , respectGains = 0 , wantedLevelGains = 0 ;
for ( var i = 0 ; i < this . members . length ; ++ i ) {
respectGains += ( this . members [ i ] . calculateRespectGain ( ) ) ;
wantedLevelGains += ( this . members [ i ] . calculateWantedLevelGain ( ) ) ;
moneyGains += ( this . members [ i ] . calculateMoneyGain ( ) ) ;
}
this . respectGainRate = respectGains ;
this . wantedGainRate = wantedLevelGains ;
this . moneyGainRate = moneyGains ;
2018-10-02 23:54:56 +02:00
if ( typeof respectGains === "number" ) {
2017-08-13 07:01:33 +02:00
var gain = respectGains * this . storedCycles ;
this . respect += ( gain ) ;
2018-10-02 23:54:56 +02:00
// Faction reputation gains is respect gain divided by some constant
2017-08-13 07:01:33 +02:00
var fac = Factions [ this . facName ] ;
if ( ! ( fac instanceof Faction ) ) {
dialogBoxCreate ( "ERROR: Could not get Faction associates with your gang. This is a bug, please report to game dev" ) ;
} else {
var favorMult = 1 + ( fac . favor / 100 ) ;
2018-10-02 18:45:00 +02:00
fac . playerReputation += ( ( Player . faction _rep _mult * gain * favorMult ) / GangRespectToReputationRatio ) ;
2017-08-13 07:01:33 +02:00
}
2018-10-02 23:54:56 +02:00
// Keep track of respect gained per member
for ( let i = 0 ; i < this . members . length ; ++ i ) {
this . members [ i ] . recordEarnedRespect ( this . storedCycles ) ;
}
2017-08-13 07:01:33 +02:00
} else {
2018-10-02 23:54:56 +02:00
console . warn ( "respectGains calculated to be NaN" ) ;
2017-08-13 07:01:33 +02:00
}
2018-10-02 23:54:56 +02:00
if ( typeof wantedLevelGains === "number" ) {
2017-09-05 03:03:29 +02:00
if ( this . wanted === 1 && wantedLevelGains < 0 ) {
//Do nothing
} else {
2018-10-02 23:54:56 +02:00
const oldWanted = this . wanted ;
let newWanted = + ( wantedLevelGains * this . storedCycles ) ;
// Prevent overflow
if ( wantedLevelGains <= 0 && newWanted > oldWanted ) {
newWanted = 1 ;
}
this . wanted = newWanted ;
2017-09-05 03:03:29 +02:00
if ( this . wanted < 1 ) { this . wanted = 1 ; }
}
2017-08-13 07:01:33 +02:00
} else {
2018-10-02 23:54:56 +02:00
console . warn ( "ERROR: wantedLevelGains is NaN" ) ;
2017-08-13 07:01:33 +02:00
}
2018-10-02 23:54:56 +02:00
if ( typeof moneyGains === "number" ) {
2017-08-13 07:01:33 +02:00
Player . gainMoney ( moneyGains * this . storedCycles ) ;
} else {
2018-10-02 23:54:56 +02:00
console . warn ( "ERROR: respectGains is NaN" ) ;
2017-08-13 07:01:33 +02:00
}
this . storedCycles = 0 ;
}
2018-10-02 23:54:56 +02:00
Gang . prototype . canRecruitMember = function ( ) {
if ( this . members . length >= MaximumGangMembers ) { return false ; }
return ( this . respect >= this . getRespectNeededToRecruitMember ( ) ) ;
}
Gang . prototype . getRespectNeededToRecruitMember = function ( ) {
// First 3 members are free
if ( this . members . length < 3 ) { return 0 ; }
const i = this . members . length ;
return Math . round ( 0.7 * Math . pow ( i , 3 ) + 0.8 * Math . pow ( i , 2 ) ) ;
}
// Money and Respect gains multiplied by this number (< 1)
Gang . prototype . getWantedPenalty = function ( ) {
return ( this . respect ) / ( this . respect + this . wanted ) ;
}
2017-08-13 07:01:33 +02:00
Gang . prototype . processExperienceGains = function ( numCycles = 1 ) {
for ( var i = 0 ; i < this . members . length ; ++ i ) {
this . members [ i ] . gainExperience ( numCycles ) ;
this . members [ i ] . updateSkillLevels ( ) ;
}
}
2017-08-15 22:22:46 +02:00
//Calculates power GAIN, which is added onto the Gang's existing power
2017-08-13 07:01:33 +02:00
Gang . prototype . calculatePower = function ( ) {
var memberTotal = 0 ;
for ( var i = 0 ; i < this . members . length ; ++ i ) {
if ( this . members [ i ] . task instanceof GangMemberTask &&
this . members [ i ] . task . name == "Territory Warfare" ) {
memberTotal += this . members [ i ] . calculatePower ( ) ;
}
}
2017-08-15 22:22:46 +02:00
return ( 0.0005 * memberTotal ) ;
2017-08-13 07:01:33 +02:00
}
2018-10-02 23:54:56 +02:00
Gang . prototype . killMember = function ( memberObj ) {
// TODO
2018-02-09 22:11:43 +01:00
}
2018-10-02 23:54:56 +02:00
Gang . prototype . ascendMember = function ( memberObj ) {
try {
//Member.ascend() returns the amount of respect to deduct
this . respect = Math . min ( 1 , this . respect - memberObj . ascend ( ) ) ;
} catch ( e ) {
exceptionAlert ( e ) ;
2018-02-09 22:11:43 +01:00
}
}
2017-08-13 07:01:33 +02:00
Gang . prototype . toJSON = function ( ) {
return Generic _toJSON ( "Gang" , this ) ;
}
Gang . fromJSON = function ( value ) {
return Generic _fromJSON ( Gang , value . data ) ;
}
Reviver . constructors . Gang = Gang ;
/*** Gang Member object ***/
function GangMember ( name ) {
this . name = name ;
2018-02-09 22:11:43 +01:00
this . task = GangMemberTasks [ "Unassigned" ] ; //GangMemberTask object
2018-10-02 23:54:56 +02:00
this . earnedRespect = 0 ;
2017-08-13 07:01:33 +02:00
this . hack = 1 ;
this . str = 1 ;
this . def = 1 ;
this . dex = 1 ;
this . agi = 1 ;
this . cha = 1 ;
this . hack _exp = 0 ;
this . str _exp = 0 ;
this . def _exp = 0 ;
this . dex _exp = 0 ;
this . agi _exp = 0 ;
this . cha _exp = 0 ;
this . hack _mult = 1 ;
this . str _mult = 1 ;
this . def _mult = 1 ;
this . dex _mult = 1 ;
this . agi _mult = 1 ;
this . cha _mult = 1 ;
2018-02-09 22:11:43 +01:00
2018-10-02 23:54:56 +02:00
this . hack _asc _mult = 1 ;
this . str _asc _mult = 1 ;
this . def _asc _mult = 1 ;
this . dex _asc _mult = 1 ;
this . agi _asc _mult = 1 ;
this . cha _asc _mult = 1 ;
this . upgrades = [ ] ; //Names of upgrades
this . augmentations = [ ] ; //Names only
2017-08-13 07:01:33 +02:00
}
//Same formula for Player
2018-06-19 06:37:56 +02:00
GangMember . prototype . calculateSkill = function ( exp , mult = 1 ) {
2018-10-02 23:54:56 +02:00
return Math . max ( Math . floor ( mult * ( 32 * Math . log ( exp + 534.5 ) - 200 ) ) , 1 ) ;
2017-08-13 07:01:33 +02:00
}
GangMember . prototype . updateSkillLevels = function ( ) {
2018-10-02 23:54:56 +02:00
this . hack = this . calculateSkill ( this . hack _exp , this . hack _mult * this . hack _asc _mult ) ;
this . str = this . calculateSkill ( this . str _exp , this . str _mult * this . str _asc _mult ) ;
this . def = this . calculateSkill ( this . def _exp , this . def _mult * this . def _asc _mult ) ;
this . dex = this . calculateSkill ( this . dex _exp , this . dex _mult * this . dex _asc _mult ) ;
this . agi = this . calculateSkill ( this . agi _exp , this . agi _mult * this . agi _asc _mult ) ;
this . cha = this . calculateSkill ( this . cha _exp , this . cha _mult * this . cha _asc _mult ) ;
2017-08-13 07:01:33 +02:00
}
GangMember . prototype . calculatePower = function ( ) {
return ( this . hack + this . str + this . def +
this . dex + this . agi + this . cha ) / 100 ;
}
GangMember . prototype . assignToTask = function ( taskName ) {
if ( GangMemberTasks . hasOwnProperty ( taskName ) ) {
this . task = GangMemberTasks [ taskName ] ;
} else {
2018-02-15 05:26:43 +01:00
this . task = GangMemberTasks [ "Unassigned" ] ;
2017-08-13 07:01:33 +02:00
}
}
2018-02-09 22:11:43 +01:00
GangMember . prototype . unassignFromTask = function ( ) {
if ( GangMemberTasks . hasOwnProperty ( "Unassigned" ) ) {
this . task = GangMemberTasks [ "Unassigned" ] ;
} else {
console . log ( "ERROR: Can't find Unassigned Gang member task" ) ;
this . task = null ;
}
}
2017-08-13 07:01:33 +02:00
//Gains are per cycle
GangMember . prototype . calculateRespectGain = function ( ) {
var task = this . task ;
2017-10-26 00:05:12 +02:00
if ( task == null || ! ( task instanceof GangMemberTask ) || task . baseRespect === 0 ) { return 0 ; }
2017-08-13 07:01:33 +02:00
var statWeight = ( task . hackWeight / 100 ) * this . hack +
( task . strWeight / 100 ) * this . str +
( task . defWeight / 100 ) * this . def +
( task . dexWeight / 100 ) * this . dex +
( task . agiWeight / 100 ) * this . agi +
( task . chaWeight / 100 ) * this . cha ;
statWeight -= ( 3.5 * task . difficulty ) ;
2018-10-02 23:54:56 +02:00
if ( statWeight <= 0 ) { return 0 ; }
2017-08-13 07:01:33 +02:00
var territoryMult = AllGangs [ Player . gang . facName ] . territory ;
2018-10-02 23:54:56 +02:00
if ( territoryMult <= 0 ) { return 0 ; }
var respectMult = Player . gang . getWantedPenalty ( ) ;
2017-08-13 07:01:33 +02:00
return 12 * task . baseRespect * statWeight * territoryMult * respectMult ;
}
GangMember . prototype . calculateWantedLevelGain = function ( ) {
var task = this . task ;
2017-10-26 00:05:12 +02:00
if ( task == null || ! ( task instanceof GangMemberTask ) || task . baseWanted === 0 ) { return 0 ; }
2017-08-13 07:01:33 +02:00
var statWeight = ( task . hackWeight / 100 ) * this . hack +
( task . strWeight / 100 ) * this . str +
( task . defWeight / 100 ) * this . def +
( task . dexWeight / 100 ) * this . dex +
( task . agiWeight / 100 ) * this . agi +
( task . chaWeight / 100 ) * this . cha ;
statWeight -= ( 3.5 * task . difficulty ) ;
if ( statWeight <= 0 ) { return 0 ; }
var territoryMult = AllGangs [ Player . gang . facName ] . territory ;
2017-08-18 19:20:51 +02:00
if ( territoryMult <= 0 ) { return 0 ; }
2017-08-13 07:01:33 +02:00
if ( task . baseWanted < 0 ) {
return task . baseWanted * statWeight * territoryMult ;
} else {
2017-08-20 03:36:19 +02:00
return 6 * task . baseWanted / ( 3 * statWeight * territoryMult ) ;
2017-08-13 07:01:33 +02:00
}
}
GangMember . prototype . calculateMoneyGain = function ( ) {
var task = this . task ;
2017-10-26 00:05:12 +02:00
if ( task == null || ! ( task instanceof GangMemberTask ) || task . baseMoney === 0 ) { return 0 ; }
2017-08-13 07:01:33 +02:00
var statWeight = ( task . hackWeight / 100 ) * this . hack +
( task . strWeight / 100 ) * this . str +
( task . defWeight / 100 ) * this . def +
( task . dexWeight / 100 ) * this . dex +
( task . agiWeight / 100 ) * this . agi +
( task . chaWeight / 100 ) * this . cha ;
statWeight -= ( 3.5 * task . difficulty ) ;
if ( statWeight <= 0 ) { return 0 ; }
var territoryMult = AllGangs [ Player . gang . facName ] . territory ;
2017-08-18 19:20:51 +02:00
if ( territoryMult <= 0 ) { return 0 ; }
2018-10-02 23:54:56 +02:00
var respectMult = Player . gang . getWantedPenalty ( ) ;
2017-08-13 07:01:33 +02:00
return 5 * task . baseMoney * statWeight * territoryMult * respectMult ;
}
GangMember . prototype . gainExperience = function ( numCycles = 1 ) {
var task = this . task ;
2017-10-26 00:05:12 +02:00
if ( task == null || ! ( task instanceof GangMemberTask ) ) { return ; }
2017-08-13 07:01:33 +02:00
this . hack _exp += ( task . hackWeight / 1500 ) * task . difficulty * numCycles ;
this . str _exp += ( task . strWeight / 1500 ) * task . difficulty * numCycles ;
this . def _exp += ( task . defWeight / 1500 ) * task . difficulty * numCycles ;
this . dex _exp += ( task . dexWeight / 1500 ) * task . difficulty * numCycles ;
this . agi _exp += ( task . agiWeight / 1500 ) * task . difficulty * numCycles ;
this . cha _exp += ( task . chaWeight / 1500 ) * task . difficulty * numCycles ;
}
2018-10-02 23:54:56 +02:00
GangMember . prototype . recordEarnedRespect = function ( numCycles = 1 ) {
this . earnedRespect += ( this . calculateRespectGain ( ) * numCycles ) ;
}
GangMember . prototype . ascend = function ( ) {
// Calculate ascension bonus to stat multipliers.
// This is based on the current number of multipliers from Non-Augmentation upgrades
// + Ascension Bonus = N% of current bonus from Augmentations
let hack = 1 ;
let str = 1 ;
let def = 1 ;
let dex = 1 ;
let agi = 1 ;
let cha = 1 ;
for ( let i = 0 ; i < this . upgrades . length ; ++ i ) {
let upg = GangMemberUpgrades [ this . upgrades [ i ] ] ;
if ( upg . mults . hack != null ) { hack *= upg . mults . hack ; }
if ( upg . mults . str != null ) { str *= upg . mults . str ; }
if ( upg . mults . def != null ) { def *= upg . mults . def ; }
if ( upg . mults . dex != null ) { dex *= upg . mults . dex ; }
if ( upg . mults . agi != null ) { agi *= upg . mults . agi ; }
if ( upg . mults . cha != null ) { cha *= upg . mults . cha ; }
}
// Get just the bonus multiplier part, and then record
-- hack ; -- str ; -- def ; -- dex ; -- agi ; -- cha ;
this . hack _asc _mult += ( hack * AscensionMultiplierRatio ) ;
this . str _asc _mult += ( str * AscensionMultiplierRatio ) ;
this . def _asc _mult += ( def * AscensionMultiplierRatio ) ;
this . dex _asc _mult += ( dex * AscensionMultiplierRatio ) ;
this . agi _asc _mult += ( agi * AscensionMultiplierRatio ) ;
this . cha _asc _mult += ( cha * AscensionMultiplierRatio ) ;
// Remove upgrades. Then re-calculate multipliers and stats
this . upgrades . length = 0 ;
this . hack _mult = 1 ;
this . str _mult = 1 ;
this . def _mult = 1 ;
this . dex _mult = 1 ;
this . agi _mult = 1 ;
this . cha _mult = 1 ;
for ( let i = 0 ; i < this . augmentations . length ; ++ i ) {
let aug = GangMemberUpgrades [ this . augmentations [ i ] ] ;
aug . apply ( this ) ;
}
this . updateSkillLevels ( ) ;
const respectToDeduct = this . earnedRespect ;
this . earnedRespect = 0 ;
return respectToDeduct ;
}
2017-08-13 07:01:33 +02:00
GangMember . prototype . toJSON = function ( ) {
return Generic _toJSON ( "GangMember" , this ) ;
}
GangMember . fromJSON = function ( value ) {
return Generic _fromJSON ( GangMember , value . data ) ;
}
Reviver . constructors . GangMember = GangMember ;
//Defines tasks that Gang Members can work on
function GangMemberTask ( name = "" , desc = "" ,
params = { baseRespect : 0 , baseWanted : 0 , baseMoney : 0 ,
hackWeight : 0 , strWeight : 0 , defWeight : 0 ,
dexWeight : 0 , agiWeight : 0 , chaWeight : 0 ,
difficulty : 0 } ) {
this . name = name ;
this . desc = desc ;
this . baseRespect = params . baseRespect ? params . baseRespect : 0 ;
this . baseWanted = params . baseWanted ? params . baseWanted : 0 ;
this . baseMoney = params . baseMoney ? params . baseMoney : 0 ;
//Weights must add up to 100
this . hackWeight = params . hackWeight ? params . hackWeight : 0 ;
this . strWeight = params . strWeight ? params . strWeight : 0 ;
this . defWeight = params . defWeight ? params . defWeight : 0 ;
this . dexWeight = params . dexWeight ? params . dexWeight : 0 ;
this . agiWeight = params . agiWeight ? params . agiWeight : 0 ;
this . chaWeight = params . chaWeight ? params . chaWeight : 0 ;
//1 - 100
this . difficulty = params . difficulty ? params . difficulty : 1 ;
}
GangMemberTask . prototype . toJSON = function ( ) {
return Generic _toJSON ( "GangMemberTask" , this ) ;
}
GangMemberTask . fromJSON = function ( value ) {
return Generic _fromJSON ( GangMemberTask , value . data ) ;
}
Reviver . constructors . GangMemberTask = GangMemberTask ;
//TODO Human trafficking and an equivalent hacking crime
2018-10-02 23:54:56 +02:00
const GangMemberTasks = { } ;
function addGangMemberTask ( name , desc , params ) {
GangMemberTasks [ name ] = new GangMemberTask ( name , desc , params ) ;
2017-08-13 07:01:33 +02:00
}
2018-10-02 23:54:56 +02:00
gangMemberTasksMetadata . forEach ( ( e ) => {
addGangMemberTask ( e . name , e . desc , e . params ) ;
} ) ;
2017-08-13 07:01:33 +02:00
2018-10-02 18:45:00 +02:00
function GangMemberUpgrade ( name = "" , cost = 0 , type = "w" , mults = { } ) {
2017-08-13 07:01:33 +02:00
this . name = name ;
2017-08-15 22:22:46 +02:00
this . cost = cost ;
2018-10-02 23:54:56 +02:00
this . type = type ; //w = weapon, a = armor, v = vehicle, r = rootkit, g = Aug
2018-10-02 18:45:00 +02:00
this . mults = mults ;
this . createDescription ( ) ;
}
GangMemberUpgrade . prototype . createDescription = function ( ) {
2018-10-02 23:54:56 +02:00
const lines = [ "Increases:" ] ;
2018-10-02 18:45:00 +02:00
if ( this . mults . str != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Strength by ${ Math . round ( ( this . mults . str - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
if ( this . mults . def != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Defense by ${ Math . round ( ( this . mults . def - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
if ( this . mults . dex != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Dexterity by ${ Math . round ( ( this . mults . dex - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
if ( this . mults . agi != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Agility by ${ Math . round ( ( this . mults . agi - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
if ( this . mults . cha != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Charisma by ${ Math . round ( ( this . mults . cha - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
if ( this . mults . hack != null ) {
2018-10-02 23:54:56 +02:00
lines . push ( ` * Hacking by ${ Math . round ( ( this . mults . hack - 1 ) * 100 ) } % ` ) ;
2018-10-02 18:45:00 +02:00
}
2018-10-02 23:54:56 +02:00
this . desc = lines . join ( "\n" ) ;
2017-08-13 07:01:33 +02:00
}
//Passes in a GangMember object
2018-02-09 22:11:43 +01:00
GangMemberUpgrade . prototype . apply = function ( member ) {
2018-10-02 18:45:00 +02:00
if ( this . mults . str != null ) { member . str _mult *= this . mults . str ; }
if ( this . mults . def != null ) { member . def _mult *= this . mults . def ; }
if ( this . mults . dex != null ) { member . dex _mult *= this . mults . dex ; }
if ( this . mults . agi != null ) { member . agi _mult *= this . mults . agi ; }
if ( this . mults . cha != null ) { member . cha _mult *= this . mults . cha ; }
if ( this . mults . hack != null ) { member . hack _mult *= this . mults . hack ; }
return ;
2017-08-13 07:01:33 +02:00
}
2017-08-15 22:22:46 +02:00
GangMemberUpgrade . prototype . toJSON = function ( ) {
return Generic _toJSON ( "GangMemberUpgrade" , this ) ;
}
GangMemberUpgrade . fromJSON = function ( value ) {
return Generic _fromJSON ( GangMemberUpgrade , value . data ) ;
}
Reviver . constructors . GangMemberUpgrade = GangMemberUpgrade ;
2018-10-02 23:54:56 +02:00
// Initialize Gang Member Upgrades
2018-10-02 18:45:00 +02:00
const GangMemberUpgrades = { }
function addGangMemberUpgrade ( name , cost , type , mults ) {
2018-10-02 23:54:56 +02:00
GangMemberUpgrades [ name ] = new GangMemberUpgrade ( name , cost , type , mults ) ;
2017-08-15 22:22:46 +02:00
}
2018-10-02 23:54:56 +02:00
gangMemberUpgradesMetadata . forEach ( ( e ) => {
addGangMemberUpgrade ( e . name , e . cost , e . upgType , e . mults ) ;
} ) ;
2018-10-02 18:45:00 +02:00
2017-08-15 22:22:46 +02:00
//Create a pop-up box that lets player purchase upgrades
2017-08-30 19:44:29 +02:00
let gangMemberUpgradeBoxOpened = false ;
2018-02-15 05:26:43 +01:00
function createGangMemberUpgradeBox ( initialFilter = "" ) {
var boxId = "gang-member-upgrade-popup-box" ;
if ( gangMemberUpgradeBoxOpened ) {
//Already opened, refreshing
if ( gangMemberUpgradeBoxElements == null || gangMemberUpgradeBox == null || gangMemberUpgradeBoxContent == null ) {
console . log ( "ERROR: Refreshing Gang member upgrade box throws error because required elements are null" ) ;
return ;
2017-08-15 22:22:46 +02:00
}
2018-02-15 05:26:43 +01:00
for ( var i = 1 ; i < gangMemberUpgradeBoxElements . length ; ++ i ) {
removeElement ( gangMemberUpgradeBoxElements [ i ] ) ;
}
gangMemberUpgradeBoxElements = [ gangMemberUpgradeBoxFilter ] ;
var filter = gangMemberUpgradeBoxFilter . value . toString ( ) ;
for ( var i = 0 ; i < Player . gang . members . length ; ++ i ) {
if ( Player . gang . members [ i ] . name . indexOf ( filter ) > - 1 || Player . gang . members [ i ] . task . name . indexOf ( filter ) > - 1 ) {
var newPanel = createGangMemberUpgradePanel ( Player . gang . members [ i ] ) ;
gangMemberUpgradeBoxContent . appendChild ( newPanel ) ;
gangMemberUpgradeBoxElements . push ( newPanel ) ;
}
}
2017-08-15 22:22:46 +02:00
} else {
2018-02-15 05:26:43 +01:00
//New popup
gangMemberUpgradeBoxFilter = createElement ( "input" , {
type : "text" , placeholder : "Filter gang members" ,
value : initialFilter ,
onkeyup : ( ) => {
var filterValue = gangMemberUpgradeBoxFilter . value . toString ( ) ;
createGangMemberUpgradeBox ( filterValue ) ;
}
} ) ;
gangMemberUpgradeBoxElements = [ gangMemberUpgradeBoxFilter ] ;
var filter = gangMemberUpgradeBoxFilter . value . toString ( ) ;
for ( var i = 0 ; i < Player . gang . members . length ; ++ i ) {
if ( Player . gang . members [ i ] . name . indexOf ( filter ) > - 1 || Player . gang . members [ i ] . task . name . indexOf ( filter ) > - 1 ) {
gangMemberUpgradeBoxElements . push ( createGangMemberUpgradePanel ( Player . gang . members [ i ] ) ) ;
}
}
gangMemberUpgradeBox = createPopup ( boxId , gangMemberUpgradeBoxElements ) ;
gangMemberUpgradeBoxContent = document . getElementById ( boxId + "-content" ) ;
gangMemberUpgradeBoxOpened = true ;
2017-08-15 22:22:46 +02:00
}
2018-02-15 05:26:43 +01:00
}
//Create upgrade panels for each individual Gang Member
function createGangMemberUpgradePanel ( memberObj ) {
var container = createElement ( "div" , {
border : "1px solid white" ,
} ) ;
var header = createElement ( "h1" , {
innerText : memberObj . name + " (" + memberObj . task . name + ")"
} ) ;
container . appendChild ( header ) ;
var text = createElement ( "pre" , {
fontSize : "14px" , display : "inline-block" , width : "20%" ,
innerText :
"Hack: " + memberObj . hack + " (x" + formatNumber ( memberObj . hack _mult , 2 ) + ")\n" +
"Str: " + memberObj . str + " (x" + formatNumber ( memberObj . str _mult , 2 ) + ")\n" +
"Def: " + memberObj . def + " (x" + formatNumber ( memberObj . def _mult , 2 ) + ")\n" +
"Dex: " + memberObj . dex + " (x" + formatNumber ( memberObj . dex _mult , 2 ) + ")\n" +
"Agi: " + memberObj . agi + " (x" + formatNumber ( memberObj . agi _mult , 2 ) + ")\n" +
"Cha: " + memberObj . cha + " (x" + formatNumber ( memberObj . cha _mult , 2 ) + ")\n" ,
} ) ;
//Already purchased upgrades
var ownedUpgradesElements = [ ] ;
for ( var i = 0 ; i < memberObj . upgrades . length ; ++ i ) {
var upg = GangMemberUpgrades [ memberObj . upgrades [ i ] ] ;
if ( upg == null ) {
console . log ( "ERR: Could not find this upgrade: " + memberObj . upgrades [ i ] ) ;
continue ;
}
var e = createElement ( "div" , {
border : "1px solid white" , innerText : memberObj . upgrades [ i ] ,
margin : "1px" , padding : "1px" , tooltip : upg . desc , fontSize : "12px" ,
} ) ;
ownedUpgradesElements . push ( e ) ;
2017-08-15 22:22:46 +02:00
}
2018-02-15 05:26:43 +01:00
var ownedUpgrades = createElement ( "div" , {
display : "inline-block" , marginLeft : "6px" , width : "75%" , innerText : "Purchased Upgrades:" ,
} ) ;
for ( var i = 0 ; i < ownedUpgradesElements . length ; ++ i ) {
ownedUpgrades . appendChild ( ownedUpgradesElements [ i ] ) ;
2017-08-15 22:22:46 +02:00
}
2018-02-15 05:26:43 +01:00
container . appendChild ( text ) ;
container . appendChild ( ownedUpgrades ) ;
container . appendChild ( createElement ( "br" , { } ) ) ;
//Upgrade buttons. Only show upgrades that can be afforded
2018-10-02 23:54:56 +02:00
const weaponUpgrades = [ ] ;
const armorUpgrades = [ ] ;
const vehicleUpgrades = [ ] ;
const rootkitUpgrades = [ ] ;
const augUpgrades = [ ] ;
for ( let upgName in GangMemberUpgrades ) {
2018-02-15 05:26:43 +01:00
if ( GangMemberUpgrades . hasOwnProperty ( upgName ) ) {
2018-10-02 23:54:56 +02:00
let upg = GangMemberUpgrades [ upgName ] ;
2018-02-15 05:26:43 +01:00
if ( Player . money . lt ( upg . cost ) || memberObj . upgrades . includes ( upgName ) ) { continue ; }
switch ( upg . type ) {
case "w" :
weaponUpgrades . push ( upg ) ;
break ;
case "a" :
armorUpgrades . push ( upg ) ;
break ;
case "v" :
vehicleUpgrades . push ( upg ) ;
break ;
case "r" :
rootkitUpgrades . push ( upg ) ;
break ;
2018-10-02 23:54:56 +02:00
case "g" :
augUpgrades . push ( upg ) ;
2018-02-15 05:26:43 +01:00
default :
2018-10-02 23:54:56 +02:00
console . error ( ` ERROR: Invalid Gang Member Upgrade Type: ${ upg . type } ` ) ;
2018-02-15 05:26:43 +01:00
}
}
2017-08-15 22:22:46 +02:00
}
2017-08-20 03:36:19 +02:00
2018-10-02 23:54:56 +02:00
const weaponDiv = createElement ( "div" , { width : "16%" , display : "inline-block" } ) ;
const armorDiv = createElement ( "div" , { width : "16%" , display : "inline-block" } ) ;
const vehicleDiv = createElement ( "div" , { width : "16%" , display : "inline-block" } ) ;
const rootkitDiv = createElement ( "div" , { width : "16%" , display : "inline-block" } ) ;
const augDiv = createElement ( "div" , { width : "16%" , display : "inline-block" } ) ;
const upgrades = [ weaponUpgrades , armorUpgrades , vehicleUpgrades , rootkitUpgrades , augUpgrades ] ;
const divs = [ weaponDiv , armorDiv , vehicleDiv , rootkitDiv , augDiv ] ;
for ( let i = 0 ; i < upgrades . length ; ++ i ) {
let upgradeArray = upgrades [ i ] ;
let div = divs [ i ] ;
for ( let j = 0 ; j < upgradeArray . length ; ++ j ) {
let upg = upgradeArray [ j ] ;
2018-02-15 05:26:43 +01:00
( function ( upg , div , memberObj ) {
div . appendChild ( createElement ( "a" , {
2018-09-12 17:53:08 +02:00
innerText : upg . name + " - " + numeralWrapper . format ( upg . cost , "$0.000a" ) ,
2018-02-15 05:26:43 +01:00
class : "a-link-button" , margin : "2px" , padding : "2px" , display : "block" ,
2018-10-02 23:54:56 +02:00
fontSize : "11px" ,
2018-02-15 05:26:43 +01:00
tooltip : upg . desc ,
clickListener : ( ) => {
2018-10-02 23:54:56 +02:00
if ( Player . money . lt ( upg . cost ) ) { return false ; }
2018-02-15 05:26:43 +01:00
Player . loseMoney ( upg . cost ) ;
2018-10-02 23:54:56 +02:00
if ( upg . type === "g" ) {
memberObj . augmentations . push ( upg . name ) ;
} else {
memberObj . upgrades . push ( upg . name ) ;
}
2018-02-15 05:26:43 +01:00
upg . apply ( memberObj ) ;
var initFilterValue = gangMemberUpgradeBoxFilter . value . toString ( ) ;
createGangMemberUpgradeBox ( initFilterValue ) ;
return false ;
}
} ) ) ;
} ) ( upg , div , memberObj ) ;
2017-08-15 22:22:46 +02:00
}
}
2018-02-15 05:26:43 +01:00
container . appendChild ( weaponDiv ) ;
container . appendChild ( armorDiv ) ;
container . appendChild ( vehicleDiv ) ;
container . appendChild ( rootkitDiv ) ;
return container ;
2017-08-13 07:01:33 +02:00
}
2018-02-09 22:11:43 +01:00
//Gang DOM elements
let gangContentCreated = false ,
gangContainer = null , managementButton = null , territoryButton = null ;
//Subpages
let gangManagementSubpage = null , gangTerritorySubpage = null ;
//Gang Management Elements
let gangDesc = null , gangInfo = null ,
gangRecruitMemberButton = null , gangRecruitRequirementText = null ,
gangExpandAllButton = null , gangCollapseAllButton , gangMemberFilter = null ,
2018-02-15 05:26:43 +01:00
gangManageEquipmentButton = null ,
2018-02-09 22:11:43 +01:00
gangMemberList = null ;
2018-02-15 05:26:43 +01:00
//Gang Equipment Upgrade Elements
let gangMemberUpgradeBox = null , gangMemberUpgradeBoxContent = null ,
gangMemberUpgradeBoxFilter = null , gangMemberUpgradeBoxElements = null ;
2018-02-09 22:11:43 +01:00
//Gang Territory Elements
let gangTerritoryDescText = null , gangTerritoryInfoText = null ;
2017-08-13 07:01:33 +02:00
function displayGangContent ( ) {
2018-02-09 22:11:43 +01:00
if ( ! gangContentCreated || gangContainer == null ) {
2017-08-13 07:01:33 +02:00
gangContentCreated = true ;
//Create gang container
2018-02-09 22:11:43 +01:00
gangContainer = createElement ( "div" , {
id : "gang-container" , class : "generic-menupage-container" ,
} ) ;
2017-08-13 07:01:33 +02:00
//Get variables
2018-02-09 22:11:43 +01:00
var facName = Player . gang . facName ,
members = Player . gang . members ,
wanted = Player . gang . wanted ,
respect = Player . gang . respect ;
2017-08-13 07:01:33 +02:00
2018-03-27 02:46:21 +02:00
//Back button
gangContainer . appendChild ( createElement ( "a" , {
class : "a-link-button" , display : "inline-block" , innerText : "Back" ,
clickListener : ( ) => {
Engine . loadFactionContent ( ) ;
displayFactionContent ( facName ) ;
return false ;
}
} ) ) ;
2017-08-13 07:01:33 +02:00
//Buttons to switch between panels
2018-02-09 22:11:43 +01:00
managementButton = createElement ( "a" , {
id : "gang-management-subpage-button" , class : "a-link-button-inactive" ,
display : "inline-block" , innerHTML : "Gang Management (1)" ,
clickListener : ( ) => {
gangManagementSubpage . style . display = "block" ;
gangTerritorySubpage . style . display = "none" ;
managementButton . classList . toggle ( "a-link-button-inactive" ) ;
managementButton . classList . toggle ( "a-link-button" ) ;
territoryButton . classList . toggle ( "a-link-button-inactive" ) ;
territoryButton . classList . toggle ( "a-link-button" ) ;
updateGangContent ( ) ;
return false ;
}
} )
territoryButton = createElement ( "a" , {
id : "gang-territory-subpage-button" , class : "a-link-button" ,
display : "inline-block" , innerHTML : "Gang Territory (2)" ,
clickListener : ( ) => {
gangManagementSubpage . style . display = "none" ;
gangTerritorySubpage . style . display = "block" ;
managementButton . classList . toggle ( "a-link-button-inactive" ) ;
managementButton . classList . toggle ( "a-link-button" ) ;
territoryButton . classList . toggle ( "a-link-button-inactive" ) ;
territoryButton . classList . toggle ( "a-link-button" ) ;
updateGangContent ( ) ;
return false ;
}
2017-08-13 07:01:33 +02:00
} ) ;
2018-02-09 22:11:43 +01:00
gangContainer . appendChild ( managementButton ) ;
gangContainer . appendChild ( territoryButton ) ;
2017-08-13 07:01:33 +02:00
2018-02-09 22:11:43 +01:00
//Subpage for managing gang members
gangManagementSubpage = createElement ( "div" , {
display : "block" , id : "gang-management-subpage" ,
2017-08-13 07:01:33 +02:00
} ) ;
2018-02-09 22:11:43 +01:00
var lowerWantedTask = "" ;
if ( Player . gang . isHackingGang ) {
lowerWantedTask = "Ethical Hacking" ;
} else {
lowerWantedTask = "Vigilante Justice" ;
}
gangDesc = createElement ( "p" , { width : "70%" ,
innerHTML :
"This page is used to manage your gang members and get an overview of your " +
"gang's stats.<br><br>" +
"If a gang member is not earning much money or respect, the task that you " +
"have assigned to that member might be too difficult. Consider training that " +
"member's stats or choosing an easier task. The tasks closer to the " +
"top of the dropdown list are generally easier. Alternatively, the gang member's " +
"low production might be due to the fact that your wanted level is too high. " +
"Consider assigning a few members to the '" + lowerWantedTask + "' " +
"task to lower your wanted level. <br><br>" +
"Installing Augmentations does NOT reset your progress with your Gang. " +
"Furthermore, after installing Augmentations, you will " +
"automatically be a member of whatever Faction you created your gang with.<br><br>"
} ) ;
gangManagementSubpage . appendChild ( gangDesc ) ;
gangInfo = createElement ( "p" , { id : "gang-info" , width : "70%" } ) ;
gangManagementSubpage . appendChild ( gangInfo ) ;
gangRecruitMemberButton = createElement ( "a" , {
id : "gang-management-recruit-member-btn" , class : "a-link-button-inactive" ,
innerHTML : "Recruit Gang Member" , display : "inline-block" , margin : "10px" ,
clickListener : ( ) => {
var yesBtn = yesNoTxtInpBoxGetYesButton ( ) , noBtn = yesNoTxtInpBoxGetNoButton ( ) ;
yesBtn . innerHTML = "Recruit Gang Member" ;
noBtn . innerHTML = "Cancel" ;
yesBtn . addEventListener ( "click" , ( ) => {
var name = yesNoTxtInpBoxGetInput ( ) ;
if ( name === "" ) {
dialogBoxCreate ( "You must enter a name for your Gang member!" ) ;
} else {
for ( var i = 0 ; i < Player . gang . members . length ; ++ i ) {
if ( name == Player . gang . members [ i ] . name ) {
dialogBoxCreate ( "You already have a gang member with this name!" ) ;
return false ;
}
2017-08-13 07:01:33 +02:00
}
2018-02-09 22:11:43 +01:00
var member = new GangMember ( name ) ;
Player . gang . members . push ( member ) ;
createGangMemberDisplayElement ( member ) ;
updateGangContent ( ) ;
2017-08-13 07:01:33 +02:00
}
2018-02-09 22:11:43 +01:00
yesNoTxtInpBoxClose ( ) ;
} ) ;
noBtn . addEventListener ( "click" , ( ) => {
yesNoTxtInpBoxClose ( ) ;
} ) ;
yesNoTxtInpBoxCreate ( "Please enter a name for your new Gang member:" ) ;
return false ;
}
2017-08-13 07:01:33 +02:00
} ) ;
2018-02-15 05:26:43 +01:00
gangManagementSubpage . appendChild ( gangRecruitMemberButton ) ;
2017-08-13 07:01:33 +02:00
//Text for how much reputation is required for recruiting next memberList
2018-02-09 22:11:43 +01:00
gangRecruitRequirementText = createElement ( "p" , { color : "red" , id : "gang-recruit-requirement-text" } ) ;
gangManagementSubpage . appendChild ( gangRecruitRequirementText ) ;
//Gang Member List management buttons (Expand/Collapse All, select a single member)
gangManagementSubpage . appendChild ( createElement ( "br" , { } ) ) ;
gangExpandAllButton = createElement ( "a" , {
2018-02-15 05:26:43 +01:00
class : "a-link-button" , display : "inline-block" ,
2018-02-09 22:11:43 +01:00
innerHTML : "Expand All" ,
clickListener : ( ) => {
var allHeaders = gangManagementSubpage . getElementsByClassName ( "accordion-header" ) ;
2018-02-15 05:26:43 +01:00
for ( var i = 0 ; i < allHeaders . length ; ++ i ) {
var hdr = allHeaders [ i ] ;
2018-02-09 22:11:43 +01:00
if ( ! hdr . classList . contains ( "active" ) ) {
hdr . click ( ) ;
}
2018-02-15 05:26:43 +01:00
}
return false ;
2018-02-09 22:11:43 +01:00
}
} ) ;
gangCollapseAllButton = createElement ( "a" , {
2018-02-15 05:26:43 +01:00
class : "a-link-button" , display : "inline-block" ,
2018-02-09 22:11:43 +01:00
innerHTML : "Collapse All" ,
clickListener : ( ) => {
var allHeaders = gangManagementSubpage . getElementsByClassName ( "accordion-header" ) ;
2018-02-15 05:26:43 +01:00
for ( var i = 0 ; i < allHeaders . length ; ++ i ) {
var hdr = allHeaders [ i ] ;
2018-02-09 22:11:43 +01:00
if ( hdr . classList . contains ( "active" ) ) {
hdr . click ( ) ;
}
2018-02-15 05:26:43 +01:00
}
return false ;
2018-02-09 22:11:43 +01:00
}
} ) ;
gangMemberFilter = createElement ( "input" , {
2018-02-15 05:26:43 +01:00
type : "text" , placeholder : "Filter gang members" , margin : "5px" , padding : "5px" ,
2018-02-09 22:11:43 +01:00
onkeyup : ( ) => {
displayGangMemberList ( ) ;
}
} ) ;
2018-02-15 05:26:43 +01:00
gangManageEquipmentButton = createElement ( "a" , {
class : "a-link-button" , display : "inline-block" ,
innerHTML : "Manage Equipment" ,
clickListener : ( ) => {
createGangMemberUpgradeBox ( ) ;
}
} ) ;
2018-02-09 22:11:43 +01:00
gangManagementSubpage . appendChild ( gangExpandAllButton ) ;
gangManagementSubpage . appendChild ( gangCollapseAllButton ) ;
gangManagementSubpage . appendChild ( gangMemberFilter ) ;
2018-02-15 05:26:43 +01:00
gangManagementSubpage . appendChild ( gangManageEquipmentButton ) ;
2018-02-09 22:11:43 +01:00
//Gang Member list
gangMemberList = createElement ( "ul" , { id : "gang-member-list" } ) ;
displayGangMemberList ( ) ;
gangManagementSubpage . appendChild ( gangMemberList ) ;
2017-08-13 07:01:33 +02:00
//Subpage for seeing gang territory information
2018-02-09 22:11:43 +01:00
gangTerritorySubpage = createElement ( "div" , {
id : "gang-territory-subpage" , display : "none"
} ) ;
2017-08-13 07:01:33 +02:00
//Info text for territory page
2018-02-09 22:11:43 +01:00
gangTerritoryDescText = createElement ( "p" , {
width : "70%" ,
innerHTML : "This page shows how much territory your Gang controls. This statistic is listed as a percentage, " +
2017-08-13 07:01:33 +02:00
"which represents how much of the total territory you control.<br><br>" +
"Territory gain and loss is processed automatically and is updated every ~30 seconds. Your chances " +
"to gain and lose territory depend on your Gang's power, which is listed in the display below. " +
"Your gang's power is determined by the stats of all Gang members you have assigned to the " +
"'Territory Warfare' task. Gang members that are not assigned to this task do not contribute to " +
"your Gang's power.<br><br>" +
"The amount of territory you have affects all aspects of your Gang members' production, including " +
"money, respect, and wanted level. It is very beneficial to have high territory control.<br><br>"
2018-02-09 22:11:43 +01:00
} ) ;
gangTerritorySubpage . appendChild ( gangTerritoryDescText ) ;
2017-08-13 07:01:33 +02:00
2018-02-09 22:11:43 +01:00
var territoryBorder = createElement ( "fieldset" , { width : "50%" , display : "inline-block" } ) ;
2017-08-13 07:01:33 +02:00
2018-02-09 22:11:43 +01:00
gangTerritoryInfoText = createElement ( "p" , { id : "gang-territory-info" } ) ;
2017-08-13 07:01:33 +02:00
2018-02-09 22:11:43 +01:00
territoryBorder . appendChild ( gangTerritoryInfoText ) ;
gangTerritorySubpage . appendChild ( territoryBorder ) ;
2017-08-13 07:01:33 +02:00
2018-02-15 05:26:43 +01:00
gangContainer . appendChild ( gangTerritorySubpage ) ;
2018-02-09 22:11:43 +01:00
gangContainer . appendChild ( gangManagementSubpage ) ;
document . getElementById ( "entire-game-container" ) . appendChild ( gangContainer ) ;
2017-08-13 07:01:33 +02:00
}
2018-02-09 22:11:43 +01:00
gangContainer . style . display = "block" ;
2017-08-13 07:01:33 +02:00
updateGangContent ( ) ;
}
2018-02-09 22:11:43 +01:00
function displayGangMemberList ( ) {
removeChildrenFromElement ( gangMemberList ) ;
2018-02-15 05:26:43 +01:00
var members = Player . gang . members ;
2018-02-09 22:11:43 +01:00
var filter = gangMemberFilter . value . toString ( ) ;
for ( var i = 0 ; i < members . length ; ++ i ) {
2018-02-15 05:26:43 +01:00
if ( members [ i ] . name . indexOf ( filter ) > - 1 || members [ i ] . task . name . indexOf ( filter ) > - 1 ) {
2018-02-09 22:11:43 +01:00
createGangMemberDisplayElement ( members [ i ] ) ;
}
}
//setGangMemberClickHandlers(); //Set buttons to toggle the gang member info panels
}
2017-08-13 07:01:33 +02:00
function updateGangContent ( ) {
if ( ! gangContentCreated || ! Player . inGang ( ) ) { return ; }
2018-02-09 22:11:43 +01:00
if ( gangTerritorySubpage . style . display === "block" ) {
2017-08-13 07:01:33 +02:00
//Update territory information
2018-02-09 22:11:43 +01:00
gangTerritoryInfoText . innerHTML = "" ;
2017-08-13 07:01:33 +02:00
for ( var gangname in AllGangs ) {
if ( AllGangs . hasOwnProperty ( gangname ) ) {
2018-02-15 05:26:43 +01:00
var gangTerritoryInfo = AllGangs [ gangname ] ;
2018-05-07 19:25:44 +02:00
let territory = gangTerritoryInfo . territory * 100 ;
//Fix some rounding issues graphically
let displayNumber ;
if ( territory <= 0 ) {
displayNumber = formatNumber ( 0 , 2 ) ;
} else if ( territory >= 100 ) {
displayNumber = formatNumber ( 100 , 2 ) ;
} else {
displayNumber = formatNumber ( territory , 2 ) ;
}
2017-08-13 07:01:33 +02:00
if ( gangname == Player . gang . facName ) {
2018-02-15 05:26:43 +01:00
gangTerritoryInfoText . innerHTML += ( "<b>" + gangname + "</b><br>(Power: " + formatNumber ( gangTerritoryInfo . power , 6 ) + "): " +
2018-05-07 19:25:44 +02:00
displayNumber + "%<br><br>" ) ;
2017-08-13 07:01:33 +02:00
} else {
2018-02-15 05:26:43 +01:00
gangTerritoryInfoText . innerHTML += ( gangname + "<br>(Power: " + formatNumber ( gangTerritoryInfo . power , 6 ) + "): " +
2018-05-07 19:25:44 +02:00
displayNumber + "%<br><br>" ) ;
2017-08-13 07:01:33 +02:00
}
}
}
} else {
//Update information for overall gang
2018-02-15 05:26:43 +01:00
if ( gangInfo instanceof Element ) {
2017-08-13 07:01:33 +02:00
var faction = Factions [ Player . gang . facName ] ;
var rep ;
if ( ! ( faction instanceof Faction ) ) {
rep = "ERROR" ;
} else {
rep = faction . playerReputation ;
}
2018-02-09 22:11:43 +01:00
removeChildrenFromElement ( gangInfo ) ;
gangInfo . appendChild ( createElement ( "p" , { //Respect
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-02-09 22:11:43 +01:00
innerText : "Respect: " + formatNumber ( Player . gang . respect , 6 ) +
" (" + formatNumber ( 5 * Player . gang . respectGainRate , 6 ) + " / sec)" ,
tooltip : "Represents the amount of respect your gang has from other gangs and criminal " +
"organizations. Your respect affects the amount of money " +
"your gang members will earn, and also determines how much " +
"reputation you are earning with your gang's corresponding Faction."
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2018-02-09 22:11:43 +01:00
gangInfo . appendChild ( createElement ( "p" , { //Wanted level
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-02-09 22:11:43 +01:00
innerText : "Wanted Level: " + formatNumber ( Player . gang . wanted , 6 ) +
" (" + formatNumber ( 5 * Player . gang . wantedGainRate , 6 ) + " / sec)" ,
tooltip : "Represents how much the gang is wanted by law enforcement. The higher " +
"your gang's wanted level, the harder it will be for your gang members " +
"to make money and earn respect. Note that the minimum wanted level is 1."
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2018-02-09 22:11:43 +01:00
2018-10-02 23:54:56 +02:00
var wantedPenalty = Player . gang . getWantedPenalty ( ) ;
2018-02-09 22:11:43 +01:00
wantedPenalty = ( 1 - wantedPenalty ) * 100 ;
gangInfo . appendChild ( createElement ( "p" , { //Wanted Level multiplier
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-10-02 23:54:56 +02:00
innerText : ` Wanted Level Penalty: - ${ formatNumber ( wantedPenalty , 2 ) } % ` ,
2018-02-09 22:11:43 +01:00
tooltip : "Penalty for respect and money gain rates due to Wanted Level"
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2018-02-09 22:11:43 +01:00
gangInfo . appendChild ( createElement ( "p" , { //Money gain rate
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-10-02 23:54:56 +02:00
innerText : ` Money gain rate: ${ numeralWrapper . format ( 5 * Player . gang . moneyGainRate , $0 . 000 a ) } / sec ` ) ;
2018-02-09 22:11:43 +01:00
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2018-02-09 22:11:43 +01:00
2018-05-07 19:25:44 +02:00
//Fix some rounding issues graphically
var territoryMult = AllGangs [ Player . gang . facName ] . territory * 100 ;
let displayNumber ;
if ( territoryMult <= 0 ) {
displayNumber = formatNumber ( 0 , 2 ) ;
} else if ( territoryMult >= 100 ) {
displayNumber = formatNumber ( 100 , 2 ) ;
} else {
displayNumber = formatNumber ( territoryMult , 2 ) ;
}
2018-02-09 22:11:43 +01:00
gangInfo . appendChild ( createElement ( "p" , { //Territory multiplier
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-10-02 23:54:56 +02:00
innerText : ` Territory: ${ formatNumber ( displayNumber , 3 ) } % ` ,
2018-02-09 22:11:43 +01:00
tooltip : "The percentage of total territory your Gang controls"
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2018-02-09 22:11:43 +01:00
gangInfo . appendChild ( createElement ( "p" , { //Faction reputation
2018-02-15 05:26:43 +01:00
display : "inline-block" ,
2018-02-09 22:11:43 +01:00
innerText : "Faction reputation: " + formatNumber ( rep , 3 )
} ) ) ;
2018-02-15 05:26:43 +01:00
gangInfo . appendChild ( createElement ( "br" , { } ) ) ;
2017-08-13 07:01:33 +02:00
} else {
console . log ( "ERROR: gang-info DOM element DNE" ) ;
}
//Toggle the 'Recruit member button' if valid
var numMembers = Player . gang . members . length ;
2018-10-02 23:54:56 +02:00
const respectCost = Player . gang . getRespectNeededToRecruitMember ( ) ;
2018-10-02 18:45:00 +02:00
if ( numMembers >= MaximumGangMembers ) {
2017-08-13 07:01:33 +02:00
btn . className = "a-link-button-inactive" ;
2018-02-09 22:11:43 +01:00
gangRecruitRequirementText . style . display = "block" ;
2018-10-02 23:54:56 +02:00
gangRecruitRequirementText . innerHTML = "You have reached the maximum amount of gang members" ;
} else if ( Player . gang . canRecruitMember ( ) ) {
2017-08-13 07:01:33 +02:00
btn . className = "a-link-button" ;
2018-02-09 22:11:43 +01:00
gangRecruitRequirementText . style . display = "none" ;
2017-08-13 07:01:33 +02:00
} else {
btn . className = "a-link-button-inactive" ;
2018-02-09 22:11:43 +01:00
gangRecruitRequirementText . style . display = "block" ;
2018-10-02 23:54:56 +02:00
gangRecruitRequirementText . innerHTML = ` ${ formatNumber ( repCost , 2 ) } respect needed to recruit next member ` ;
2017-08-13 07:01:33 +02:00
}
//Update information for each gang member
2018-10-02 23:54:56 +02:00
for ( let i = 0 ; i < Player . gang . members . length ; ++ i ) {
2017-08-13 07:01:33 +02:00
updateGangMemberDisplayElement ( Player . gang . members [ i ] ) ;
}
}
}
//Takes in a GangMember object
function createGangMemberDisplayElement ( memberObj ) {
if ( ! gangContentCreated || ! Player . inGang ( ) ) { return ; }
var name = memberObj . name ;
2018-02-09 22:11:43 +01:00
var accordion = createAccordionElement ( {
id : name + "gang-member" ,
hdrText : name ,
} ) ;
var li = accordion [ 0 ] ;
2018-02-15 05:26:43 +01:00
var hdr = accordion [ 1 ] ;
var gangMemberDiv = accordion [ 2 ] ;
2017-08-13 07:01:33 +02:00
//Gang member content divided into 3 panels:
//Stats Panel
2018-02-09 22:11:43 +01:00
var statsDiv = createElement ( "div" , {
id : name + "gang-member-stats" , class : "gang-member-info-div" ,
width : "30%" , display : "inline"
} ) ;
var statsP = createElement ( "p" , {
id : name + "gang-member-stats-text" , display : "inline"
} ) ;
2017-08-13 07:01:33 +02:00
statsDiv . appendChild ( statsP ) ;
2018-02-09 22:11:43 +01:00
//statsDiv.appendChild(upgradeButton);
2017-08-13 07:01:33 +02:00
//Panel for Selecting task and show respect/wanted gain
2018-02-09 22:11:43 +01:00
var taskDiv = createElement ( "div" , {
id : name + "gang-member-task" , class : "gang-member-info-div" ,
width : "30%" , display : "inline"
} ) ;
var taskSelector = createElement ( "select" , {
color : "white" , backgroundColor : "black" ,
id : name + "gang-member-task-selector"
} ) ;
2018-02-15 05:26:43 +01:00
2017-08-13 07:01:33 +02:00
var tasks = null ;
if ( Player . gang . isHackingGang ) {
tasks = [ "---" , "Ransomware" , "Phishing" , "Identity Theft" , "DDoS Attacks" ,
"Plant Virus" , "Fraud & Counterfeiting" , "Money Laundering" ,
"Cyberterrorism" , "Ethical Hacking" , "Train Combat" ,
"Train Hacking" , "Territory Warfare" ] ;
} else {
tasks = [ "---" , "Mug People" , "Deal Drugs" , "Run a Con" , "Armed Robbery" ,
"Traffick Illegal Arms" , "Threaten & Blackmail" ,
"Terrorism" , "Vigilante Justice" , "Train Combat" ,
"Train Hacking" , "Territory Warfare" ] ;
}
for ( var i = 0 ; i < tasks . length ; ++ i ) {
var option = document . createElement ( "option" ) ;
option . text = tasks [ i ] ;
taskSelector . add ( option ) ;
}
taskSelector . addEventListener ( "change" , function ( ) {
var task = taskSelector . options [ taskSelector . selectedIndex ] . text ;
memberObj . assignToTask ( task ) ;
setGangMemberTaskDescription ( memberObj , task ) ;
updateGangContent ( ) ;
} ) ;
//Set initial task in selector element
if ( memberObj . task instanceof GangMemberTask ) {
var taskName = memberObj . task . name ;
var taskIndex = 0 ;
2017-08-30 19:44:29 +02:00
for ( let i = 0 ; i < tasks . length ; ++ i ) {
2017-08-13 07:01:33 +02:00
if ( taskName == tasks [ i ] ) {
taskIndex = i ;
break ;
}
}
taskSelector . selectedIndex = taskIndex ;
}
2018-02-09 22:11:43 +01:00
var gainInfo = createElement ( "p" , { id : name + "gang-member-gain-info" } ) ;
2017-08-13 07:01:33 +02:00
taskDiv . appendChild ( taskSelector ) ;
taskDiv . appendChild ( gainInfo ) ;
//Panel for Description of task
2018-02-09 22:11:43 +01:00
var taskDescDiv = createElement ( "div" , {
id : name + "gang-member-task-desc" , class : "gang-member-info-div" ,
width : "30%" , display : "inline"
} ) ;
2017-08-13 07:01:33 +02:00
2018-02-09 22:11:43 +01:00
var taskDescP = createElement ( "p" , { id : name + "gang-member-task-description" , display : "inline" } ) ;
2017-08-13 07:01:33 +02:00
taskDescDiv . appendChild ( taskDescP ) ;
statsDiv . style . width = "30%" ;
taskDiv . style . width = "30%" ;
taskDescDiv . style . width = "30%" ;
statsDiv . style . display = "inline" ;
taskDiv . style . display = "inline" ;
taskDescDiv . style . display = "inline" ;
gangMemberDiv . appendChild ( statsDiv ) ;
gangMemberDiv . appendChild ( taskDiv ) ;
gangMemberDiv . appendChild ( taskDescDiv ) ;
2018-02-15 05:26:43 +01:00
gangMemberList . appendChild ( li ) ;
2017-08-13 07:01:33 +02:00
setGangMemberTaskDescription ( memberObj , taskName ) ; //Initialize description
updateGangMemberDisplayElement ( memberObj ) ;
}
function updateGangMemberDisplayElement ( memberObj ) {
if ( ! gangContentCreated || ! Player . inGang ( ) ) { return ; }
var name = memberObj . name ;
//TODO Add upgrade information
var stats = document . getElementById ( name + "gang-member-stats-text" ) ;
if ( stats ) {
stats . innerHTML =
2018-09-12 17:53:08 +02:00
"Hacking: " + formatNumber ( memberObj . hack , 0 ) + " (" + numeralWrapper . format ( memberObj . hack _exp , '(0.00a)' ) + " exp)<br>" +
"Strength: " + formatNumber ( memberObj . str , 0 ) + " (" + numeralWrapper . format ( memberObj . str _exp , '(0.00a)' ) + " exp)<br>" +
"Defense: " + formatNumber ( memberObj . def , 0 ) + " (" + numeralWrapper . format ( memberObj . def _exp , '(0.00a)' ) + " exp)<br>" +
"Dexterity: " + formatNumber ( memberObj . dex , 0 ) + " (" + numeralWrapper . format ( memberObj . dex _exp , '(0.00a)' ) + " exp)<br>" +
"Agility: " + formatNumber ( memberObj . agi , 0 ) + " (" + numeralWrapper . format ( memberObj . agi _exp , '(0.00a)' ) + " exp)<br>" +
"Charisma: " + formatNumber ( memberObj . cha , 0 ) + " (" + numeralWrapper . format ( memberObj . cha _exp , '(0.00a)' ) + " exp)<br>" ;
2017-08-13 07:01:33 +02:00
}
var gainInfo = document . getElementById ( name + "gang-member-gain-info" ) ;
if ( gainInfo ) {
gainInfo . innerHTML =
"Money: $" + formatNumber ( 5 * memberObj . calculateMoneyGain ( ) , 2 ) + " / sec<br>" +
"Respect: " + formatNumber ( 5 * memberObj . calculateRespectGain ( ) , 6 ) + " / sec<br>" +
"Wanted Level: " + formatNumber ( 5 * memberObj . calculateWantedLevelGain ( ) , 6 ) + " / sec<br>" ;
}
}
function setGangMemberTaskDescription ( memberObj , taskName ) {
var name = memberObj . name ;
var taskDesc = document . getElementById ( name + "gang-member-task-description" ) ;
if ( taskDesc ) {
var task = GangMemberTasks [ taskName ] ;
if ( task == null ) { return ; }
var desc = task . desc ;
taskDesc . innerHTML = desc ;
}
}
2017-08-30 19:44:29 +02:00
2018-03-12 20:39:04 +01:00
function deleteGangDisplayContent ( ) {
if ( gangContainer != null ) { removeElementById ( gangContainer . id ) ; }
gangContentCreated = false ;
gangContainer = null ;
managementButton = null ;
territoryButton = null ;
//Subpages
gangManagementSubpage = null ;
gangTerritorySubpage = null ;
//Gang Management Elements
gangDesc = null ;
gangInfo = null ;
gangRecruitMemberButton = null ;
gangRecruitRequirementText = null ;
gangExpandAllButton = null ;
gangCollapseAllButton = null ;
gangMemberFilter = null ;
gangManageEquipmentButton = null ;
gangMemberList = null ;
//Gang Equipment Upgrade Elements
gangMemberUpgradeBox = null ;
gangMemberUpgradeBoxContent = null ;
gangMemberUpgradeBoxFilter = null ;
gangMemberUpgradeBoxElements = null ;
}
2017-09-02 22:05:42 +02:00
export { Gang , displayGangContent , updateGangContent , loadAllGangs , AllGangs ,
2018-03-12 20:39:04 +01:00
resetGangs , deleteGangDisplayContent } ;