2019-01-10 09:20:04 +01:00
/ * *
* Module for handling the Sleeve UI
* /
2019-02-27 03:26:29 +01:00
import { createSleevePurchaseAugsPopup } from "./SleeveAugmentationsUI" ;
2019-01-10 09:20:04 +01:00
import { Sleeve } from "./Sleeve" ;
import { SleeveTaskType } from "./SleeveTaskTypesEnum" ;
2019-01-20 23:57:38 +01:00
import { SleeveFaq } from "./data/SleeveFaq" ;
2019-01-10 09:20:04 +01:00
2019-01-17 16:40:43 +01:00
import { IPlayer } from "../IPlayer" ;
2019-01-15 04:34:04 +01:00
2019-01-22 05:39:52 +01:00
import { CONSTANTS } from "../../Constants" ;
2019-01-15 04:34:04 +01:00
import { Locations } from "../../Locations" ;
2019-01-30 07:02:27 +01:00
import { Faction } from "../../Faction/Faction" ;
import { Factions } from "../../Faction/Factions" ;
2019-01-22 05:39:52 +01:00
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum" ;
2019-01-30 07:02:27 +01:00
2019-01-15 04:34:04 +01:00
import { Cities } from "../../Locations/Cities" ;
2019-01-30 07:02:27 +01:00
import { Crime } from "../../Crime/Crime" ;
2019-01-15 04:34:04 +01:00
import { Crimes } from "../../Crime/Crimes" ;
import { numeralWrapper } from "../../ui/numeralFormat" ;
2019-01-10 09:20:04 +01:00
import { Page ,
routing } from "../../ui/navigationTracking" ;
2019-01-15 04:34:04 +01:00
import { dialogBoxCreate } from "../../../utils/DialogBox" ;
2019-01-20 23:57:38 +01:00
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText" ;
2019-01-10 09:20:04 +01:00
import { exceptionAlert } from "../../../utils/helpers/exceptionAlert" ;
2019-01-30 07:02:27 +01:00
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners" ;
2019-01-10 09:20:04 +01:00
import { createElement } from "../../../utils/uiHelpers/createElement" ;
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement" ;
2019-01-22 05:39:52 +01:00
import { createPopup } from "../../../utils/uiHelpers/createPopup" ;
import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton" ;
2019-01-15 04:34:04 +01:00
import { getSelectValue } from "../../../utils/uiHelpers/getSelectData" ;
import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement" ;
2019-01-10 09:20:04 +01:00
import { removeElement } from "../../../utils/uiHelpers/removeElement" ;
2019-01-22 05:39:52 +01:00
import { removeElementById } from "../../../utils/uiHelpers/removeElementById" ;
2019-01-10 09:20:04 +01:00
// Object that keeps track of all DOM elements for the UI for a single Sleeve
interface ISleeveUIElems {
2019-01-20 23:57:38 +01:00
container : HTMLElement | null ;
statsPanel : HTMLElement | null ;
stats : HTMLElement | null ;
moreStatsButton : HTMLElement | null ;
2019-01-22 05:39:52 +01:00
travelButton : HTMLElement | null ;
2019-02-26 09:51:48 +01:00
purchaseAugsButton : HTMLElement | null ;
2019-01-20 23:57:38 +01:00
taskPanel : HTMLElement | null ;
taskSelector : HTMLSelectElement | null ;
taskDetailsSelector : HTMLSelectElement | null ;
taskDetailsSelector2 : HTMLSelectElement | null ;
taskDescription : HTMLElement | null ;
taskSetButton : HTMLElement | null ;
taskProgressBar : HTMLElement | null ;
earningsPanel : HTMLElement | null ;
currentEarningsInfo : HTMLElement | null ;
totalEarningsButton : HTMLElement | null ;
2019-01-10 09:20:04 +01:00
}
// Object that keeps track of all DOM elements for the entire Sleeve UI
interface IPageUIElems {
2019-01-17 16:40:43 +01:00
container : HTMLElement | null ;
2019-01-20 23:57:38 +01:00
docButton : HTMLElement | null ;
faqButton : HTMLElement | null ;
info : HTMLElement | null ;
sleeveList : HTMLElement | null ;
sleeves : ISleeveUIElems [ ] | null ;
2019-01-10 09:20:04 +01:00
}
const UIElems : IPageUIElems = {
container : null ,
2019-01-20 23:57:38 +01:00
docButton : null ,
faqButton : null ,
2019-01-10 09:20:04 +01:00
info : null ,
sleeveList : null ,
sleeves : null ,
}
// Creates the UI for the entire Sleeves page
2019-01-17 16:40:43 +01:00
let playerRef : IPlayer | null ;
export function createSleevesPage ( p : IPlayer ) {
2019-01-10 09:20:04 +01:00
if ( ! routing . isOn ( Page . Sleeves ) ) { return ; }
try {
2019-01-15 04:34:04 +01:00
playerRef = p ;
2019-01-10 09:20:04 +01:00
UIElems . container = createElement ( "div" , {
class : "generic-menupage-container" ,
id : "sleeves-container" ,
position : "fixed" ,
} ) ;
UIElems . info = createElement ( "p" , {
2019-01-20 23:57:38 +01:00
class : "sleeves-page-info" ,
innerHTML : "Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your " +
"consciousness has been copied. In other words, these Synthoids contain " +
2019-01-10 09:20:04 +01:00
"a perfect duplicate of your mind.<br><br>" +
2019-01-20 23:57:38 +01:00
"Sleeves can be used to perform different tasks synchronously.<br><br>" ,
} ) ;
UIElems . faqButton = createElement ( "button" , {
class : "std-button" ,
display : "inline-block" ,
innerText : "FAQ" ,
clickListener : ( ) = > {
dialogBoxCreate ( SleeveFaq , false ) ;
}
} ) ;
2019-02-22 22:26:30 +01:00
UIElems . docButton = createElement ( "a" , {
2019-01-20 23:57:38 +01:00
class : "std-button" ,
display : "inline-block" ,
2019-02-22 22:26:30 +01:00
href : "https://bitburner.readthedocs.io/en/latest/advancedgameplay/sleeves.html#duplicate-sleeves" ,
2019-01-20 23:57:38 +01:00
innerText : "Documentation" ,
2019-02-22 22:26:30 +01:00
target : "_blank" ,
2019-01-10 09:20:04 +01:00
} ) ;
UIElems . sleeveList = createElement ( "ul" ) ;
UIElems . sleeves = [ ] ;
2019-01-15 04:34:04 +01:00
// Create UI modules for all Sleeve
2019-01-10 09:20:04 +01:00
for ( const sleeve of p . sleeves ) {
2019-01-15 04:34:04 +01:00
const sleeveUi = createSleeveUi ( sleeve , p . sleeves ) ;
UIElems . sleeveList . appendChild ( sleeveUi . container ! ) ;
UIElems . sleeves . push ( sleeveUi ) ;
2019-01-10 09:20:04 +01:00
}
UIElems . container . appendChild ( UIElems . info ) ;
2019-01-20 23:57:38 +01:00
UIElems . container . appendChild ( UIElems . faqButton ) ;
2019-02-22 22:26:30 +01:00
UIElems . container . appendChild ( UIElems . docButton ) ;
2019-01-10 09:20:04 +01:00
UIElems . container . appendChild ( UIElems . sleeveList ) ;
document . getElementById ( "entire-game-container" ) ! . appendChild ( UIElems . container ) ;
} catch ( e ) {
exceptionAlert ( e ) ;
}
}
// Updates the UI for the entire Sleeves page
export function updateSleevesPage() {
if ( ! routing . isOn ( Page . Sleeves ) ) { return ; }
2019-01-20 23:57:38 +01:00
try {
for ( let i = 0 ; i < playerRef ! . sleeves . length ; ++ i ) {
const sleeve : Sleeve = playerRef ! . sleeves [ i ] ;
const elems : ISleeveUIElems = UIElems . sleeves ! [ i ] ;
updateSleeveUi ( sleeve ! , elems ! ) ;
}
} catch ( e ) {
exceptionAlert ( e ) ;
}
2019-01-10 09:20:04 +01:00
}
export function clearSleevesPage() {
2019-01-20 23:57:38 +01:00
if ( UIElems . container instanceof HTMLElement ) {
removeElement ( UIElems . container ) ;
}
2019-01-10 09:20:04 +01:00
for ( const prop in UIElems ) {
2019-01-15 04:34:04 +01:00
( < any > UIElems ) [ prop ] = null ;
2019-01-10 09:20:04 +01:00
}
2019-01-15 04:34:04 +01:00
playerRef = null ;
2019-01-10 09:20:04 +01:00
}
// Creates the UI for a single Sleeve
// Returns an object containing the DOM elements in the UI (ISleeveUIElems)
2019-01-15 04:34:04 +01:00
function createSleeveUi ( sleeve : Sleeve , allSleeves : Sleeve [ ] ) : ISleeveUIElems {
2019-01-10 09:20:04 +01:00
const elems : ISleeveUIElems = {
container : null ,
statsPanel : null ,
stats : null ,
2019-01-15 04:34:04 +01:00
moreStatsButton : null ,
2019-01-22 05:39:52 +01:00
travelButton : null ,
2019-02-26 09:51:48 +01:00
purchaseAugsButton : null ,
2019-01-10 09:20:04 +01:00
taskPanel : null ,
taskSelector : null ,
taskDetailsSelector : null ,
2019-01-15 04:34:04 +01:00
taskDetailsSelector2 : null ,
2019-01-10 09:20:04 +01:00
taskDescription : null ,
2019-01-15 04:34:04 +01:00
taskSetButton : null ,
2019-01-20 23:57:38 +01:00
taskProgressBar : null ,
2019-01-10 09:20:04 +01:00
earningsPanel : null ,
currentEarningsInfo : null ,
totalEarningsButton : null ,
}
2019-01-15 04:34:04 +01:00
if ( ! routing . isOn ( Page . Sleeves ) ) { return elems ; }
2019-01-10 09:20:04 +01:00
elems . container = createElement ( "div" , {
class : "sleeve-container" ,
display : "block" ,
} ) ;
2019-01-20 23:57:38 +01:00
elems . statsPanel = createElement ( "div" , { class : "sleeve-panel" , width : "25%" } ) ;
2019-01-17 16:40:43 +01:00
elems . stats = createElement ( "p" , { class : "sleeve-stats-text" } ) ;
2019-01-15 04:34:04 +01:00
elems . moreStatsButton = createElement ( "button" , {
class : "std-button" ,
innerText : "More Stats" ,
clickListener : ( ) = > {
dialogBoxCreate (
[
"<h2><u>Stats:</u></h2>" ,
` Hacking: ${ sleeve . hacking_skill } ( ${ numeralWrapper . formatBigNumber ( sleeve . hacking_exp ) } exp) ` ,
` Strength: ${ sleeve . strength } ( ${ numeralWrapper . formatBigNumber ( sleeve . strength_exp ) } exp) ` ,
` Defense: ${ sleeve . defense } ( ${ numeralWrapper . formatBigNumber ( sleeve . defense_exp ) } exp) ` ,
` Dexterity: ${ sleeve . dexterity } ( ${ numeralWrapper . formatBigNumber ( sleeve . dexterity_exp ) } exp) ` ,
` Agility: ${ sleeve . agility } ( ${ numeralWrapper . formatBigNumber ( sleeve . agility_exp ) } exp) ` ,
` Charisma: ${ sleeve . charisma } ( ${ numeralWrapper . formatBigNumber ( sleeve . charisma_exp ) } exp)<br> ` ,
"<h2><u>Multipliers:</u></h2>" ,
` Hacking Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . hacking_mult ) } ` ,
` Hacking Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . hacking_exp_mult ) } ` ,
` Strength Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . strength_mult ) } ` ,
` Strength Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . strength_exp_mult ) } ` ,
` Defense Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . defense_mult ) } ` ,
` Defense Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . defense_exp_mult ) } ` ,
` Dexterity Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . dexterity_mult ) } ` ,
` Dexterity Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . dexterity_exp_mult ) } ` ,
` Agility Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . agility_mult ) } ` ,
` Agility Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . agility_exp_mult ) } ` ,
` Charisma Level multiplier: ${ numeralWrapper . formatPercentage ( sleeve . charisma_mult ) } ` ,
` Charisma Experience multiplier: ${ numeralWrapper . formatPercentage ( sleeve . charisma_exp_mult ) } ` ,
` Faction Reputation Gain multiplier: ${ numeralWrapper . formatPercentage ( sleeve . faction_rep_mult ) } ` ,
` Company Reputation Gain multiplier: ${ numeralWrapper . formatPercentage ( sleeve . company_rep_mult ) } ` ,
` Salary multiplier: ${ numeralWrapper . formatPercentage ( sleeve . work_money_mult ) } ` ,
` Crime Money multiplier: ${ numeralWrapper . formatPercentage ( sleeve . crime_money_mult ) } ` ,
` Crime Success multiplier: ${ numeralWrapper . formatPercentage ( sleeve . crime_success_mult ) } ` ,
] . join ( "<br>" ) , false
) ;
}
} ) ;
2019-01-22 05:39:52 +01:00
elems . travelButton = createElement ( "button" , {
class : "std-button" ,
innerText : "Travel" ,
clickListener : ( ) = > {
const popupId : string = "sleeve-travel-popup" ;
const popupArguments : HTMLElement [ ] = [ ] ;
popupArguments . push ( createPopupCloseButton ( popupId , { class : "std-button" } ) ) ;
popupArguments . push ( createElement ( "p" , {
innerText : "Have this sleeve travel to a different city. This affects " +
"the gyms and universities at which this sleeve can study. " +
2019-01-30 07:02:27 +01:00
` Traveling to a different city costs ${ numeralWrapper . formatMoney ( CONSTANTS . TravelCost ) } . ` +
2019-01-22 05:39:52 +01:00
"It will also CANCEL the sleeve's current task (setting it to idle)" ,
} ) ) ;
for ( const label in Cities ) {
if ( sleeve . city === Cities [ label ] ) { continue ; }
( function ( sleeve , label ) {
popupArguments . push ( createElement ( "div" , {
// Reusing this css class. It adds a border and makes it so that
// the background color changes when you hover
class : "cmpy-mgmt-find-employee-option" ,
innerText : Cities [ label ] ,
clickListener : ( ) = > {
if ( ! playerRef ! . canAfford ( CONSTANTS . TravelCost ) ) {
dialogBoxCreate ( "You cannot afford to have this sleeve travel to another city" , false ) ;
return false ;
}
sleeve . city = Cities [ label ] ;
playerRef ! . loseMoney ( CONSTANTS . TravelCost ) ;
sleeve . resetTaskStatus ( ) ;
removeElementById ( popupId ) ;
updateSleeveUi ( sleeve , elems ) ;
2019-01-30 07:02:27 +01:00
updateSleeveTaskSelector ( sleeve , elems , allSleeves ) ;
2019-01-22 05:39:52 +01:00
return false ;
}
} ) ) ;
} ) ( sleeve , label ) ;
}
createPopup ( popupId , popupArguments ) ;
}
2019-02-26 09:51:48 +01:00
} ) ;
elems . purchaseAugsButton = createElement ( "button" , {
class : "std-button" ,
display : "block" ,
2019-03-03 04:08:54 +01:00
innerText : "Manage Augmentations" ,
2019-02-26 09:51:48 +01:00
clickListener : ( ) = > {
2019-02-27 03:26:29 +01:00
createSleevePurchaseAugsPopup ( sleeve , playerRef ! ) ;
2019-02-26 09:51:48 +01:00
}
} ) ;
2019-01-10 09:20:04 +01:00
elems . statsPanel . appendChild ( elems . stats ) ;
2019-01-15 04:34:04 +01:00
elems . statsPanel . appendChild ( elems . moreStatsButton ) ;
2019-01-22 05:39:52 +01:00
elems . statsPanel . appendChild ( elems . travelButton ) ;
2019-02-26 09:51:48 +01:00
if ( sleeve . shock >= 100 ) {
// You can only buy augs when shock recovery is 0
elems . statsPanel . appendChild ( elems . purchaseAugsButton ) ;
}
2019-01-10 09:20:04 +01:00
2019-01-20 23:57:38 +01:00
elems . taskPanel = createElement ( "div" , { class : "sleeve-panel" , width : "40%" } ) ;
2019-03-22 05:03:09 +01:00
elems . taskSelector = createElement ( "select" , { class : "dropdown" } ) as HTMLSelectElement ;
2019-01-10 09:20:04 +01:00
elems . taskSelector . add ( createOptionElement ( "------" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Work for Company" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Work for Faction" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Commit Crime" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Take University Course" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Workout at Gym" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Shock Recovery" ) ) ;
elems . taskSelector . add ( createOptionElement ( "Synchronize" ) ) ;
2019-03-22 05:03:09 +01:00
elems . taskDetailsSelector = createElement ( "select" , { class : "dropdown" } ) as HTMLSelectElement ;
elems . taskDetailsSelector2 = createElement ( "select" , { class : "dropdown" } ) as HTMLSelectElement ;
2019-01-10 09:20:04 +01:00
elems . taskDescription = createElement ( "p" ) ;
2019-01-20 23:57:38 +01:00
elems . taskProgressBar = createElement ( "p" ) ;
2019-01-22 05:39:52 +01:00
elems . taskSelector . addEventListener ( "change" , ( ) = > {
updateSleeveTaskSelector ( sleeve , elems , allSleeves ) ;
} ) ;
2019-01-20 23:57:38 +01:00
elems . taskSelector . selectedIndex = sleeve . currentTask ; // Set initial value for Task Selector
elems . taskSelector . dispatchEvent ( new Event ( 'change' ) ) ;
updateSleeveTaskDescription ( sleeve , elems ) ;
2019-01-15 04:34:04 +01:00
elems . taskSetButton = createElement ( "button" , {
class : "std-button" ,
innerText : "Set Task" ,
clickListener : ( ) = > {
setSleeveTask ( sleeve , elems ) ;
}
} ) ;
2019-01-10 09:20:04 +01:00
elems . taskPanel . appendChild ( elems . taskSelector ) ;
elems . taskPanel . appendChild ( elems . taskDetailsSelector ) ;
2019-01-20 23:57:38 +01:00
elems . taskPanel . appendChild ( elems . taskDetailsSelector2 ) ;
2019-01-15 04:34:04 +01:00
elems . taskPanel . appendChild ( elems . taskSetButton ) ;
2019-01-10 09:20:04 +01:00
elems . taskPanel . appendChild ( elems . taskDescription ) ;
2019-01-20 23:57:38 +01:00
elems . taskPanel . appendChild ( elems . taskProgressBar ) ;
2019-01-10 09:20:04 +01:00
2019-01-20 23:57:38 +01:00
elems . earningsPanel = createElement ( "div" , { class : "sleeve-panel" , width : "35%" } ) ;
2019-01-10 09:20:04 +01:00
elems . currentEarningsInfo = createElement ( "p" ) ;
2019-01-15 04:34:04 +01:00
elems . totalEarningsButton = createElement ( "button" , {
class : "std-button" ,
innerText : "More Earnings Info" ,
clickListener : ( ) = > {
dialogBoxCreate (
[
2019-01-20 23:57:38 +01:00
"<h2><u>Earnings for Current Task:</u></h2>" ,
2019-01-15 04:34:04 +01:00
` Money: ${ numeralWrapper . formatMoney ( sleeve . earningsForTask . money ) } ` ,
` Hacking Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . hack ) } ` ,
` Strength Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . str ) } ` ,
` Defense Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . def ) } ` ,
` Dexterity Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . dex ) } ` ,
` Agility Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . agi ) } ` ,
2019-01-20 23:57:38 +01:00
` Charisma Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForTask . cha ) } <br> ` ,
"<h2><u>Total Earnings for Host Consciousness:</u></h2>" ,
2019-01-15 04:34:04 +01:00
` Money: ${ numeralWrapper . formatMoney ( sleeve . earningsForPlayer . money ) } ` ,
` Hacking Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . hack ) } ` ,
` Strength Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . str ) } ` ,
` Defense Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . def ) } ` ,
` Dexterity Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . dex ) } ` ,
` Agility Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . agi ) } ` ,
2019-01-20 23:57:38 +01:00
` Charisma Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForPlayer . cha ) } <br> ` ,
"<h2><u>Total Earnings for Other Sleeves:</u></h2>" ,
2019-01-15 04:34:04 +01:00
` Money: ${ numeralWrapper . formatMoney ( sleeve . earningsForSleeves . money ) } ` ,
` Hacking Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . hack ) } ` ,
` Strength Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . str ) } ` ,
` Defense Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . def ) } ` ,
` Dexterity Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . dex ) } ` ,
` Agility Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . agi ) } ` ,
` Charisma Exp: ${ numeralWrapper . formatBigNumber ( sleeve . earningsForSleeves . cha ) } ` ,
] . join ( "<br>" ) , false
) ;
}
} ) ;
2019-01-10 09:20:04 +01:00
2019-01-20 23:57:38 +01:00
elems . earningsPanel . appendChild ( elems . currentEarningsInfo ) ;
elems . earningsPanel . appendChild ( elems . totalEarningsButton ) ;
updateSleeveUi ( sleeve , elems ) ;
elems . container . appendChild ( elems . statsPanel ) ;
elems . container . appendChild ( elems . taskPanel ) ;
elems . container . appendChild ( elems . earningsPanel ) ;
2019-01-10 09:20:04 +01:00
return elems ;
}
// Updates the UI for a single Sleeve
2019-01-15 04:34:04 +01:00
function updateSleeveUi ( sleeve : Sleeve , elems : ISleeveUIElems ) {
2019-01-10 09:20:04 +01:00
if ( ! routing . isOn ( Page . Sleeves ) ) { return ; }
2019-01-15 04:34:04 +01:00
elems . stats ! . innerHTML = [ ` Hacking: ${ numeralWrapper . format ( sleeve . hacking_skill , "0,0" ) } ` ,
` Strength: ${ numeralWrapper . format ( sleeve . strength , "0,0" ) } ` ,
` Defense: ${ numeralWrapper . format ( sleeve . defense , "0,0" ) } ` ,
` Dexterity: ${ numeralWrapper . format ( sleeve . dexterity , "0,0" ) } ` ,
` Agility: ${ numeralWrapper . format ( sleeve . agility , "0,0" ) } ` ,
` Charisma: ${ numeralWrapper . format ( sleeve . charisma , "0,0" ) } ` ,
2019-01-22 05:39:52 +01:00
` HP: ${ numeralWrapper . format ( sleeve . hp , "0,0" ) } / ${ numeralWrapper . format ( sleeve . max_hp , "0,0" ) } ` ,
` City: ${ sleeve . city } ` ,
2019-01-20 23:57:38 +01:00
` Shock: ${ numeralWrapper . format ( 100 - sleeve . shock , "0,0.000" ) } ` ,
2019-03-27 09:36:14 +01:00
` Sync: ${ numeralWrapper . format ( sleeve . sync , "0,0.000" ) } ` ,
` Memory: ${ numeralWrapper . format ( sleeve . memory , "0" ) } ` ] . join ( "<br>" ) ;
2019-01-20 23:57:38 +01:00
let repGainText : string = "" ;
if ( sleeve . currentTask === SleeveTaskType . Company || sleeve . currentTask === SleeveTaskType . Faction ) {
const repGain : number = sleeve . getRepGain ( playerRef ! ) ;
repGainText = ` Reputation: ${ numeralWrapper . format ( 5 * repGain , "0.00" ) } / s `
}
2019-01-15 04:34:04 +01:00
if ( sleeve . currentTask === SleeveTaskType . Crime ) {
elems . currentEarningsInfo ! . innerHTML = [
2019-01-20 23:57:38 +01:00
` Earnings (Pre-Synchronization): ` ,
` Money: ${ numeralWrapper . formatMoney ( parseFloat ( sleeve . currentTaskLocation ) ) } if successful ` ,
2019-01-15 04:34:04 +01:00
` Hacking Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . hack , "0.00" ) } (2x if successful) ` ,
` Strength Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . str , "0.00" ) } (2x if successful) ` ,
` Defense Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . def , "0.00" ) } (2x if successful) ` ,
` Dexterity Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . dex , "0.00" ) } (2x if successful) ` ,
` Agility Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . agi , "0.00" ) } (2x if successful) ` ,
` Charisma Exp: ${ numeralWrapper . format ( sleeve . gainRatesForTask . cha , "0.00" ) } (2x if successful) `
] . join ( "<br>" ) ;
2019-01-20 23:57:38 +01:00
elems . taskProgressBar ! . innerText = createProgressBarText ( {
progress : sleeve.currentTaskTime / sleeve . currentTaskMaxTime ,
totalTicks : 25 ,
} ) ;
2019-01-15 04:34:04 +01:00
} else {
2019-01-20 23:57:38 +01:00
const lines = [
` Earnings (Pre-Synchronization): ` ,
` Money: ${ numeralWrapper . formatMoney ( 5 * sleeve . gainRatesForTask . money ) } / s ` ,
` Hacking Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . hack , "0.00" ) } / s ` ,
` Strength Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . str , "0.00" ) } / s ` ,
` Defense Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . def , "0.00" ) } / s ` ,
` Dexterity Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . dex , "0.00" ) } / s ` ,
` Agility Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . agi , "0.00" ) } / s ` ,
` Charisma Exp: ${ numeralWrapper . format ( 5 * sleeve . gainRatesForTask . cha , "0.00" ) } / s `
] ;
if ( repGainText !== "" ) { lines . push ( repGainText ) ; }
elems . currentEarningsInfo ! . innerHTML = lines . join ( "<br>" ) ;
elems . taskProgressBar ! . innerText = "" ;
2019-01-15 04:34:04 +01:00
}
2019-01-10 09:20:04 +01:00
}
2019-01-15 04:34:04 +01:00
const universitySelectorOptions : string [ ] = [
"Study Computer Science" ,
"Data Structures" ,
"Networks" ,
"Algorithms" ,
"Management" ,
"Leadership"
] ;
const gymSelectorOptions : string [ ] = [
"Train Strength" ,
"Train Defense" ,
"Train Dexterity" ,
"Train Agility"
] ;
2019-01-10 09:20:04 +01:00
// Whenever a new task is selected, the "details" selector must update accordingly
function updateSleeveTaskSelector ( sleeve : Sleeve , elems : ISleeveUIElems , allSleeves : Sleeve [ ] ) {
2019-01-15 04:34:04 +01:00
if ( playerRef == null ) {
throw new Error ( ` playerRef is null in updateSleeveTaskSelector() ` ) ;
}
// Array of all companies that other sleeves are working at
const forbiddenCompanies : string [ ] = [ ] ;
for ( const otherSleeve of allSleeves ) {
if ( sleeve === otherSleeve ) { continue ; }
if ( otherSleeve . currentTask === SleeveTaskType . Company ) {
forbiddenCompanies . push ( otherSleeve . currentTaskLocation ) ;
}
}
// Array of all factions that other sleeves are working for
const forbiddenFactions : string [ ] = [ ] ;
for ( const otherSleeve of allSleeves ) {
if ( sleeve === otherSleeve ) { continue ; }
if ( otherSleeve . currentTask === SleeveTaskType . Faction ) {
forbiddenFactions . push ( otherSleeve . currentTaskLocation ) ;
}
}
2019-01-20 23:57:38 +01:00
// Reset Selectors
2019-01-15 04:34:04 +01:00
removeChildrenFromElement ( elems . taskDetailsSelector ) ;
2019-01-20 23:57:38 +01:00
removeChildrenFromElement ( elems . taskDetailsSelector2 ) ;
2019-01-30 07:02:27 +01:00
elems . taskDetailsSelector2 = clearEventListeners ( elems . taskDetailsSelector2 ! ) as HTMLSelectElement ;
2019-01-15 04:34:04 +01:00
const value : string = getSelectValue ( elems . taskSelector ) ;
switch ( value ) {
case "Work for Company" :
2019-01-22 05:39:52 +01:00
let companyCount : number = 0 ;
2019-01-15 04:34:04 +01:00
const allJobs : string [ ] = Object . keys ( playerRef ! . jobs ! ) ;
for ( let i = 0 ; i < allJobs . length ; ++ i ) {
if ( ! forbiddenCompanies . includes ( allJobs [ i ] ) ) {
elems . taskDetailsSelector ! . add ( createOptionElement ( allJobs [ i ] ) ) ;
2019-01-20 23:57:38 +01:00
// Set initial value of the 'Details' selector
if ( sleeve . currentTaskLocation === allJobs [ i ] ) {
2019-01-22 05:39:52 +01:00
elems . taskDetailsSelector ! . selectedIndex = companyCount ;
2019-01-20 23:57:38 +01:00
}
2019-01-22 05:39:52 +01:00
++ companyCount ;
2019-01-15 04:34:04 +01:00
}
2019-01-20 23:57:38 +01:00
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "------" ) ) ;
2019-01-15 04:34:04 +01:00
}
break ;
case "Work for Faction" :
2019-01-22 05:39:52 +01:00
let factionCount : number = 0 ;
2019-01-15 04:34:04 +01:00
for ( let i = 0 ; i < playerRef ! . factions ! . length ; ++ i ) {
const fac : string = playerRef ! . factions [ i ] ! ;
if ( ! forbiddenFactions . includes ( fac ) ) {
elems . taskDetailsSelector ! . add ( createOptionElement ( fac ) ) ;
2019-01-20 23:57:38 +01:00
// Set initial value of the 'Details' Selector
if ( sleeve . currentTaskLocation === fac ) {
2019-01-22 05:39:52 +01:00
elems . taskDetailsSelector ! . selectedIndex = factionCount ;
2019-01-20 23:57:38 +01:00
}
2019-01-22 05:39:52 +01:00
++ factionCount ;
2019-01-15 04:34:04 +01:00
}
}
2019-01-22 05:39:52 +01:00
2019-01-30 07:02:27 +01:00
// The available faction work types depends on the faction
elems . taskDetailsSelector ! . addEventListener ( "change" , ( ) = > {
const facName = getSelectValue ( elems . taskDetailsSelector ! ) ;
const faction : Faction | null = Factions [ facName ] ;
if ( faction == null ) {
console . warn ( ` Invalid faction name when trying to update Sleeve Task Selector: ${ facName } ` ) ;
return ;
}
const facInfo = faction . getInfo ( ) ;
removeChildrenFromElement ( elems . taskDetailsSelector2 ! ) ;
let numOptionsAdded = 0 ;
if ( facInfo . offerHackingWork ) {
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "Hacking Contracts" ) ) ;
if ( sleeve . factionWorkType === FactionWorkType . Hacking ) {
elems . taskDetailsSelector2 ! . selectedIndex = numOptionsAdded ;
}
++ numOptionsAdded ;
}
if ( facInfo . offerFieldWork ) {
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "Field Work" ) ) ;
if ( sleeve . factionWorkType === FactionWorkType . Field ) {
elems . taskDetailsSelector2 ! . selectedIndex = numOptionsAdded ;
}
++ numOptionsAdded ;
}
if ( facInfo . offerSecurityWork ) {
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "Security Work" ) ) ;
if ( sleeve . factionWorkType === FactionWorkType . Security ) {
elems . taskDetailsSelector2 ! . selectedIndex = numOptionsAdded ;
}
++ numOptionsAdded ;
}
} ) ;
elems . taskDetailsSelector ! . dispatchEvent ( new Event ( "change" ) ) ;
2019-01-15 04:34:04 +01:00
break ;
case "Commit Crime" :
2019-01-30 07:02:27 +01:00
let i = 0 ;
2019-01-15 04:34:04 +01:00
for ( const crimeLabel in Crimes ) {
const name : string = Crimes [ crimeLabel ] . name ;
elems . taskDetailsSelector ! . add ( createOptionElement ( name , crimeLabel ) ) ;
2019-01-30 07:02:27 +01:00
// Set initial value for crime type
if ( sleeve . crimeType === "" ) { continue ; }
const crime : Crime | null = Crimes [ sleeve . crimeType ] ;
if ( crime == null ) { continue ; }
if ( name === crime ! . name ) {
elems . taskDetailsSelector ! . selectedIndex = i ;
}
++ i ;
2019-01-15 04:34:04 +01:00
}
2019-01-20 23:57:38 +01:00
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "------" ) ) ;
2019-01-15 04:34:04 +01:00
break ;
case "Take University Course" :
// First selector has class type
for ( let i = 0 ; i < universitySelectorOptions . length ; ++ i ) {
elems . taskDetailsSelector ! . add ( createOptionElement ( universitySelectorOptions [ i ] ) ) ;
}
// Second selector has which university
switch ( sleeve . city ) {
case Cities . Aevum :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . AevumSummitUniversity ) ) ;
break ;
case Cities . Sector12 :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . Sector12RothmanUniversity ) ) ;
break ;
case Cities . Volhaven :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . VolhavenZBInstituteOfTechnology ) ) ;
break ;
default :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "No university available in city!" ) ) ;
break ;
}
break ;
case "Workout at Gym" :
// First selector has what stat is being trained
for ( let i = 0 ; i < gymSelectorOptions . length ; ++ i ) {
elems . taskDetailsSelector ! . add ( createOptionElement ( gymSelectorOptions [ i ] ) ) ;
2019-01-22 05:39:52 +01:00
// Set initial value
if ( sleeve . gymStatType === gymSelectorOptions [ i ] ) {
elems . taskDetailsSelector ! . selectedIndex = i ;
}
2019-01-15 04:34:04 +01:00
}
// Second selector has gym
2019-01-22 05:39:52 +01:00
// In this switch statement we also set the initial value of the second selector
2019-01-15 04:34:04 +01:00
switch ( sleeve . city ) {
case Cities . Aevum :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . AevumCrushFitnessGym ) ) ;
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . AevumSnapFitnessGym ) ) ;
2019-01-22 05:39:52 +01:00
// Set initial value
if ( sleeve . currentTaskLocation === Locations . AevumCrushFitnessGym ) {
elems . taskDetailsSelector2 ! . selectedIndex = 0 ;
} else if ( sleeve . currentTaskLocation === Locations . AevumSnapFitnessGym ) {
elems . taskDetailsSelector2 ! . selectedIndex = 1 ;
}
2019-01-15 04:34:04 +01:00
break ;
case Cities . Sector12 :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . Sector12IronGym ) ) ;
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . Sector12PowerhouseGym ) ) ;
2019-01-22 05:39:52 +01:00
// Set initial value
if ( sleeve . currentTaskLocation === Locations . Sector12IronGym ) {
elems . taskDetailsSelector2 ! . selectedIndex = 0 ;
} else if ( sleeve . currentTaskLocation === Locations . Sector12PowerhouseGym ) {
elems . taskDetailsSelector2 ! . selectedIndex = 1 ;
}
2019-01-15 04:34:04 +01:00
break ;
case Cities . Volhaven :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( Locations . VolhavenMilleniumFitnessGym ) ) ;
break ;
default :
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "No gym available in city!" ) ) ;
break ;
}
break ;
case "Shock Recovery" :
case "Synchronize" :
2019-01-20 23:57:38 +01:00
case "------" :
2019-01-15 04:34:04 +01:00
// No options in "Details" selector
2019-01-20 23:57:38 +01:00
elems . taskDetailsSelector ! . add ( createOptionElement ( "------" ) ) ;
elems . taskDetailsSelector2 ! . add ( createOptionElement ( "------" ) ) ;
2019-01-15 04:34:04 +01:00
return ;
default :
break ;
}
}
2019-01-20 23:57:38 +01:00
function setSleeveTask ( sleeve : Sleeve , elems : ISleeveUIElems ) : boolean {
2019-01-15 04:34:04 +01:00
try {
if ( playerRef == null ) {
throw new Error ( "playerRef is null in Sleeve UI's setSleeveTask()" ) ;
}
const taskValue : string = getSelectValue ( elems . taskSelector ) ;
const detailValue : string = getSelectValue ( elems . taskDetailsSelector ) ;
2019-01-20 23:57:38 +01:00
const detailValue2 : string = getSelectValue ( elems . taskDetailsSelector2 ) ;
2019-01-15 04:34:04 +01:00
let res : boolean = false ;
switch ( taskValue ) {
2019-01-20 23:57:38 +01:00
case "------" :
elems . taskDescription ! . innerText = "This sleeve is currently idle" ;
break ;
2019-01-15 04:34:04 +01:00
case "Work for Company" :
res = sleeve . workForCompany ( playerRef ! , detailValue ) ;
break ;
case "Work for Faction" :
res = sleeve . workForFaction ( playerRef ! , detailValue , detailValue2 ) ;
break ;
case "Commit Crime" :
2019-01-30 07:02:27 +01:00
res = sleeve . commitCrime ( playerRef ! , detailValue ) ;
2019-01-15 04:34:04 +01:00
break ;
case "Take University Course" :
res = sleeve . takeUniversityCourse ( playerRef ! , detailValue2 , detailValue ) ;
break ;
case "Workout at Gym" :
res = sleeve . workoutAtGym ( playerRef ! , detailValue2 , detailValue ) ;
break ;
case "Shock Recovery" :
sleeve . currentTask = SleeveTaskType . Recovery ;
2019-02-26 09:51:48 +01:00
res = sleeve . shockRecovery ( playerRef ! ) ;
2019-01-15 04:34:04 +01:00
break ;
case "Synchronize" :
2019-02-26 09:51:48 +01:00
res = sleeve . synchronize ( playerRef ! ) ;
2019-01-15 04:34:04 +01:00
break ;
default :
console . error ( ` Invalid/Unrecognized taskValue in setSleeveTask(): ${ taskValue } ` ) ;
}
2019-01-20 23:57:38 +01:00
if ( res ) {
updateSleeveTaskDescription ( sleeve , elems ) ;
} else {
2019-01-30 07:02:27 +01:00
switch ( taskValue ) {
case "Work for Faction" :
elems . taskDescription ! . innerText = "Failed to assign sleeve to task. This is most likely because the selected faction does not offer the selected work type." ;
break ;
default :
elems . taskDescription ! . innerText = "Failed to assign sleeve to task. Invalid choice(s)." ;
break ;
}
2019-01-20 23:57:38 +01:00
}
2019-01-15 04:34:04 +01:00
if ( routing . isOn ( Page . Sleeves ) ) {
updateSleevesPage ( ) ;
2019-01-22 05:39:52 +01:00
// Update the task selector for all sleeves by triggering a change event
for ( const e of UIElems . sleeves ! ) {
e . taskSelector ! . dispatchEvent ( new Event ( 'change' ) ) ;
}
2019-01-15 04:34:04 +01:00
}
2019-01-20 23:57:38 +01:00
return res ;
} catch ( e ) {
console . error ( ` Exception caught in setSleeveTask(): ${ e } ` ) ;
exceptionAlert ( e ) ;
return false ;
}
}
function updateSleeveTaskDescription ( sleeve : Sleeve , elems : ISleeveUIElems ) : void {
try {
if ( playerRef == null ) {
throw new Error ( "playerRef is null in Sleeve UI's setSleeveTask()" ) ;
}
const taskValue : string = getSelectValue ( elems . taskSelector ) ;
const detailValue : string = getSelectValue ( elems . taskDetailsSelector ) ;
const detailValue2 : string = getSelectValue ( elems . taskDetailsSelector2 ) ;
switch ( taskValue ) {
case "------" :
elems . taskDescription ! . innerText = "This sleeve is currently idle" ;
break ;
case "Work for Company" :
2019-01-30 07:02:27 +01:00
elems . taskDescription ! . innerText = ` This sleeve is currently working your job at ${ sleeve . currentTaskLocation } . ` ;
2019-01-20 23:57:38 +01:00
break ;
case "Work for Faction" :
2019-01-30 07:02:27 +01:00
elems . taskDescription ! . innerText = ` This sleeve is currently doing ${ detailValue2 } for ${ sleeve . currentTaskLocation } . ` ;
2019-01-20 23:57:38 +01:00
break ;
case "Commit Crime" :
2019-02-12 01:23:46 +01:00
elems . taskDescription ! . innerText = ` This sleeve is currently attempting to ${ Crimes [ detailValue ] . type } (Success Rate: ${ numeralWrapper . formatPercentage ( Crimes [ detailValue ] . successRate ( sleeve ) ) } ). ` ;
2019-01-20 23:57:38 +01:00
break ;
case "Take University Course" :
elems . taskDescription ! . innerText = ` This sleeve is currently studying/taking a course at ${ sleeve . currentTaskLocation } . ` ;
break ;
case "Workout at Gym" :
elems . taskDescription ! . innerText = ` This sleeve is currently working out at ${ sleeve . currentTaskLocation } . ` ;
break ;
case "Shock Recovery" :
elems . taskDescription ! . innerText = "This sleeve is currently set to focus on shock recovery. This causes " +
"the Sleeve's shock to decrease at a faster rate." ;
break ;
case "Synchronize" :
elems . taskDescription ! . innerText = "This sleeve is currently set to synchronize with the original consciousness. " +
"This causes the Sleeve's synchronization to increase."
break ;
default :
console . error ( ` Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${ taskValue } ` ) ;
}
2019-01-15 04:34:04 +01:00
} catch ( e ) {
2019-01-20 23:57:38 +01:00
console . error ( ` Exception caught in updateSleeveTaskDescription(): ${ e } ` ) ;
2019-01-15 04:34:04 +01:00
exceptionAlert ( e ) ;
}
2019-01-10 09:20:04 +01:00
}