/// /// /// /// const enum EWearableBMI{ NOT_APPLICABLE = -2, ANY = -1, TOO_LOSE = 0, TOO_TIGHT = 1, ALMOST_TOO_LOSE = 2, ALMOST_TOO_TIGHT = 3, OKAY = 4 } setup.wardrobeSettings = { bmiSizeMaxDifference: 2 } setup.outfitsDefaults={ clothes:{ h:100, bmi:'$pc.bmi' } } setup.wardrobeWearableFunctions = {}; class Wardrobe{ _ownedItems:{[itemId:string]:OutfitOwnerShipData} = {} /** * Owned Item * @param {string} itemId */ item(itemId:string):OutfitOwned{ let item = OutfitItem.get(itemId) as OutfitItemClothes; // Trick Typescript let owneditem:OutfitOwned = Object.assign(item,{l:0,bmi:-2,h:-2},this._ownedItems[itemId]); // Item needs to be first, otherwise all its functions are broken return owneditem; } /** * Owned Items * @readonly * @type {{[key:string]:OutfitItem}} */ get items():{[key:string]:OutfitOwned}{ let result:{[key:string]:OutfitOwned} = {}; for(const [itemId, itemData] of Object.entries(this._ownedItems)){ //let item = OutfitItem.get(itemId); //Object.assign({l:0,bmi:-2,h:-2},item,itemData); result[itemId] = this.item(itemId); } return result; } itemsFiltered(filter:Filter){ return setup.filterDict(this.items,filter); } //#region Worn Items _wornItems:WornOutfitDefinition = { bra: null, coat: null, clothes: null, panties: null, purse: null, shoes: null } get wornItems(){ return { bra: this.bra, coat: this.coat, clothes: this.clothes, panties: this.panties, purse: this.purse, shoes: this.shoes } } get wornItemIds(){ return this._wornItems; } get bra():OutfitItemBra{ let braId = this.wornItemIds.bra; if(braId) return this.item(braId) as OutfitItemBra; return new OutfitItemBra(); } get clothes():OutfitItemClothes|OutfitItemSwimwear{ let clothesId = this.wornItemIds.clothes; if(clothesId) return this.item(clothesId) as OutfitItemClothes; return new OutfitItemClothes(); } get coat():OutfitItemCoat{ let coatId = this.wornItemIds.coat; if(coatId) return this.item(coatId) as OutfitItemCoat; return new OutfitItemCoat(); } get panties():OutfitItemPanties{ let pantiesId = this.wornItemIds.panties; if(pantiesId) return this.item(pantiesId) as OutfitItemPanties; return new OutfitItemPanties(); } get purse():OutfitItemPurse{ let purseId = this.wornItemIds.purse; if(purseId) return this.item(purseId) as OutfitItemPurse; return new OutfitItemPurse(); } get shoes():OutfitItemShoes{ let shoesId = this.wornItemIds.shoes; if(shoesId) return this.item(shoesId) as OutfitItemShoes; return new OutfitItemShoes(); } //#endregion _lastWorn:{[key:string]:WornOutfitDefinition} = { last:{ bra: null, coat: null, clothes: null, panties: null, purse: null, shoes: null } } _outfits:{[key:string]:WornOutfitDefinition} = { } outfitSports = ''; outfitSchool = ''; get outfits(){ return this._outfits; } clothingDecreaseHealth(v){ let clothesId = this._wornItems.clothes; if(clothesId in this._ownedItems){ if(this._ownedItems[clothesId].h > 0){ //Health -1 is save this._ownedItems[clothesId].h = Math.max(0,this._ownedItems[clothesId].h - v); } } } /*get clothingIsNude(){ return (!this._wornItems.clothes); }*/ /*get clothingWorn(){ return this._wornItems.clothes; }*/ /*get clothingworntype(){ if(!this._wornItems.clothes) return 'nude'; let identificator = this.itemData(this._wornItems.clothes) as OutfitDefinitionClothes; return identificator.vendor+'_'+identificator.subtype; }*/ /* get clothingwornnumber(){ if(!this._wornItems.clothes) return 0; let identificator = this.itemData(this._wornItems.clothes) as OutfitDefinitionClothes; return identificator.index; }*/ /*get coatworntype(){ if(!this._wornItems.coat) return 'none'; let identificator = this.itemData(this._wornItems.coat); return identificator.vendor; }*/ /*get coatwornnumber(){ if(!this._wornItems.coat) return 0; let identificator = this.itemData(this._wornItems.coat); return identificator.index; }*/ /*get isWearingBra(){ return (!(!this._wornItems.bra)); }*/ /*get isWearingPanties(){ return (!(!this._wornItems.panties)); }*/ get isNaked(){ return (!this.clothes.isValidItem && !this.bra.isValidItem && !this.panties.isValidItem); } /*get PCloQuality(){ if(this.clothingIsNude){ let bmi = State.variables.pc.bmi; if(bmi >= 19 && bmi < 30) return 3; return 1; } return this.wornItemData('clothes','quality',0) } get PCloThinness(){return this.wornItemData('clothes','thinness',0)} get PCloTopCut(){ const pc = State.variables.pc; let wiD = this.wornItemData('clothes','CloTopCut',0); if(wiD > 1){ if(pc.tits == 2 || pc.tits == 3) wiD += 1; else if(pc.tits >= 4) wiD += 2; if(wiD > 2 && pc.tits >= 6) wiD += 1; } return wiD; } get PCloBra(){return this.wornItemData('clothes','includesBra',0)} get PCloOnePiece(){return this.wornItemData('clothes','isOnepiece',0)} get PCloPants(){return this.wornItemData('clothes','pantsShortness',0)} get PCloSkirt(){return this.wornItemData('clothes','skirtShortness',0)} get skirtLength(){return this.PCloSkirt;} get PCloPanties(){return this.wornItemData('clothes','includesPanties',0)} get PCloDress(){return this.wornItemData('clothes','isDress',0)} get PCloStyle(){return this.wornItemData('clothes','style',0)} get PCloStyle2(){return this.wornItemData('clothes','style2',0)} get PCloStyle3(){return this.wornItemData('clothes','style3',0)} get PCloInhibit(){return this.wornItemData('clothes','inhibition',0)} get PCloBimbo(){return this.wornItemData('clothes','bimbo',0)} get PCloCoverTop(){return this.wornItemData('clothes','coverTop',4)} get PCloCoverBack(){return this.wornItemData('clothes','coverBack',4)} get PCloCoverFront(){return this.wornItemData('clothes','coverFront',4)} //get PCloCoverFront(){return this.wornItemData('clothes','coverFront',0)} */ /*get PXCloThinness(){ let PCloThinness = this.PCloThinness; switch(PCloThinness){ case 1: return 150; case 2: return 200; case 3: return 250; case 4: return 300; case 5: return 350; case 6: return 400; } if(PCloThinness > 6) return 400; return 0; }*/ /*get PXCloTopCut(){ if(this.PCloBra == 1) return 400; if(this.PCloBra == 2) return 500; let PCloTopCut = this.PCloTopCut; switch(PCloTopCut){ case 1: return 100; case 2: return 150; case 3: return 200; case 4: return 250; case 5: return 300; case 6: return 350; case 7: return 400; } if(PCloTopCut > 7) return 400; return 0; }*/ /*get PXCloBottomShortness(){ if(this.PCloPanties == 1) return 400; let PCloSkirt = this.PCloSkirt; if(PCloSkirt > 0){ switch(PCloSkirt){ case 1: return 100; case 2: return 150; case 3: return 200; case 4: return 250; case 5: return 300; case 6: return 350; case 7: return 400; } if(this.PCloThinness > 7) return 400; } let PCloPants = this.PCloPants; if(PCloPants > 0){ switch(PCloPants){ case 1: return 100; case 2: return 150; case 3: return 200; case 4: return 250; case 5: return 300; case 6: return 350; case 7: return 400; } if(PCloPants > 7) return 400; } return 0; }*/ /*get PCloswimwear(){ if(!this._wornItems.clothes) return 0; let identificator = this.itemData(this._wornItems.clothes) as OutfitDefinitionClothes; if(identificator.subtype == 'bikini' || identificator.subtype == 'swimsuit' || identificator.subtype == 'swim_one' || identificator.subtype == 'swim_two') return 1; return 0; }*/ /*get isWearingSwimwear(){ return !(!this.PCloswimwear); }*/ /*get CoverTop(){return Math.max(this.PCloCoverTop + this.PBraCover - 4,0);} get CoverBack(){return Math.max(this.PCloCoverBack + this.PPanCoverBack - 4,0);} get CoverFront(){return Math.max(this.PCloCoverFront + this.PPanCoverFront - 4,0);} get isSchoolOutfit(){ return this.wornItemData('clothes','subtype','') === 'school'; } get isSportsOutfit(){ return this.clothingworntype === 'danilovich_outfit'; }*/ // ----- Bra ----- /*get braworntype(){ if(!this._wornItems.bra) return 'none'; let identificator = this.itemData(this._wornItems.bra); return identificator.vendor; } get brawornnumber(){ if(!this._wornItems.bra) return 0; let identificator = this.itemData(this._wornItems.bra); return identificator.index; } get PBraMaterial(){return this.wornItemData('bra','material',0)} get PBraType(){return this.wornItemData('bra','subtype',0)} get PBraFun(){return this.wornItemData('bra','fun',0)} get PBraQuality(){return this.wornItemData('bra','quality',0)} get PBraThinness(){return this.wornItemData('bra','thinness',0)} get PBraCover(){return this.wornItemData('bra','cover',0)} get bra_appearanceBonus(){ //Todo: Should be saved in const data switch(this.braworntype){ case 'lusso': return 4; case 'fashionista': return 2; } return 0; }*/ // ----- Panties ----- /* get pantyworntype(){ //<> if(!this._wornItems.panties) return 'none'; let identificator = this.itemData(this._wornItems.panties); return identificator.vendor; } get pantywornnumber(){ //<> if(!this._wornItems.panties) return 0; let identificator = this.itemData(this._wornItems.panties); return identificator.index; } get PPanMaterial(){return this.wornItemData('panties','material',0)} get PPantyFun(){return this.wornItemData('panties','fun',0)} get PPanQuality(){return this.wornItemData('panties','quality',0)} get PPanThinness(){return this.wornItemData('panties','thinness',0)} get PPanCoverFront(){return this.wornItemData('panties','coverFront',0)} get PPanCoverBack(){return this.wornItemData('panties','coverBack',0)} get PPanType(){return this.wornItemData('panties','subtype',0)} get panties_appearanceBonus(){ //Todo: Should be saved in const data switch(this.pantyworntype){ case 'lusso': return 4; case 'fashionista': return 2; } return 0; }*/ // ----- Shoes ----- /** * Is the character currently wearing shoes? They could be taken manually or autoatically, because the character is inside. * @type {boolean} */ get isWearingShoes(){ //return !(!this._wornItems.shoes); if(!this.shoes.isValidItem) return false; if(!State.variables.settings.shoes_keepOnPrivateIndoors && !State.variables.location.isPublic && !State.variables.location.isOutdoors) return false; return true; } itemImage(itemId:string):string{ return OutfitItem.get(itemId).image; } /*get shoeworntype(){ //<> if(!this._wornItems.shoes) return 'none'; let identificator = this.itemData(this._wornItems.shoes); return identificator.vendor; } get shoewornnumber(){ //<> if(!this._wornItems.shoes) return 0; let identificator = this.itemData(this._wornItems.shoes); return identificator.index; } get PShoQuaility(){ if(this.isWearingShoes) return this.wornItemData('shoes','quality',0) return 0; } get PShoCut(){ if(this.isWearingShoes) return this.wornItemData('shoes','cut',0) return 0; } get PShoHeels(){ if(this.isWearingShoes) return this.wornItemData('shoes','heels',0) return 0; } get PShoStyle(){ if(this.isWearingShoes) return this.wornItemData('shoes','style',0) return 0; }*/ /** * Return heel height of worn shoes in mm. * @readonly * @type {(0 | 60 | 100 | 150 | 200 | 240 | 280 | 300)} */ /*get shoesHeight(){ switch(this.PShoHeels){ case 0: return 0; case 1: return 0; case 2: return 60; case 3: return 100; case 4: return 150; case 5: return 200; case 6: return 240; case 7: return 280; default: return 300; } }*/ /** * Appearance Bonus of worn shoes. * @date 6/16/2023 - 7:05:32 AM * * @readonly * @type {(25 | 50 | 100 | 150 | 200 | 300 | 400 | 0)} */ /*get PXShoHeels(){ let PShoHeels = this.PShoHeels; if(PShoHeels > 0){ switch(PShoHeels){ case 1: return 25; case 2: return 50; case 3: return 100; case 4: return 150; case 5: return 200; case 6: return 300; case 7: return 400; } if(PShoHeels > 7) return 400; } return 0; }*/ /*get shoes_appearanceBonus(){ return this.PShoQuaility; }*/ // ----- Coats ----- /*get PCoatWarm(){return this.wornItemData('coat','warm',0)} get PCoatQuality(){return this.wornItemData('coat','quality',0)} get coat_appearanceBonus(){ let location = State.variables.location; if(location.isOutdoors) return this.PCoatQuality - 2; return 0; }*/ // ----- Purses ----- /*get purseEquipped(){ return (this._wornItems.purse) ? true : false; } */ get outfitQuality(){ if(this.isWearingShoes) return Math.floor((this.clothes.quality * 2 + this.shoes.quality) / 3); return this.clothes.quality; } get outfitIndecency(){ return setup.func('outfitIndecency'); } /** * Low-Level adds an item to the wardrobe. * @param {string} itemId * @param {{}} [metadata={}] */ add(itemId:string,metadata: {}={}){ let constData = this.itemConstantData(itemId); let type_defaults = setup.outfitsDefaults[constData.type] || {}; let vendor_defaults = setup.outfitsDefaults[constData.vendor] || {}; metadata = Object.assign({},type_defaults,vendor_defaults,metadata); let iterateObject = clone(metadata); for (const [key, value] of Object.entries(iterateObject)) { if(typeof value === "string" && value.startsWith('$')) metadata[key] = State.getVar(value); } this._ownedItems[itemId] = metadata; console.log("ITEM ADDED",itemId,metadata); } /** * Low-Level removes an item from the wardrobe. * @param {string} itemId */ delete(itemId:string){ delete this._ownedItems[itemId]; } deleteOutfit(outfitId:string){ return delete this.outfits[outfitId]; } dispose(itemId:string){ this.delete(itemId); } disposeWorn(type:string){ let itemId = this._wornItems[type]; if(itemId){ this.strip(type); this.dispose(itemId); } } /** * All defined items. */ get allItems(): {[key: string]: OutfitDefinition}{ return setup.outfits; } allItemsFiltered(filter:Filter){ return setup.filterDict(this.allItems,filter); } allItemIdsFiltered(filter:Filter,count=undefined,randomOrder=false){ let itemIds = Object.keys(this.allItemsFiltered(filter)); if(randomOrder) itemIds.shuffle(); if(count) itemIds = itemIds.slice(0,count); return itemIds; } /** * Returns all items (owned or not) that match filters. * @param {*} filters * @returns */ /*getItems(filters={}):{[key:string]:OutfitDefinition}{ let items:{[key:string]:OutfitDefinition} = this.filterItems(this.allItems,filters); return items; }*/ /*getItemIds(filters={},count=undefined,randomOrder=false){ let itemIds = Object.keys(this.getItems(filters)) if(randomOrder) itemIds.shuffle(); if(count) itemIds = itemIds.slice(0,count); return itemIds; }*/ /*filterItems(items:{[key:string]:OutfitDefinition},filters:Filter):{[key:string]:OutfitDefinition}{ return setup.filterDict(items,filters); }*/ // Gets a list of owned items /*getList(filters={}){ let results = []; itemloop: for (const [item_id, item_data] of Object.entries(this._ownedItems)) { let itemData = this.get(item_id); let vendor = itemData.vendor; let type = itemData.type; let subtype = itemData.subtype; let index = itemData.index; filterloop: for (const [filter_key, filter_value] of Object.entries(filters)) { if(filter_value === null || filter_value === undefined) continue filterloop; if(filter_key == 'type'){ if(type != filter_value) continue itemloop; continue filterloop; }else if(filter_key == 'vendor'){ if(vendor != filter_value) continue itemloop; continue filterloop; }else if(filter_key == 'subtype'){ if(subtype != filter_value) continue itemloop; continue filterloop; }else if(filter_key == 'index'){ if(index != filter_value) continue itemloop; continue filterloop; }else if(filter_key == 'location'){ if(Array.isArray(filter_value)){ if(!filter_value.includes(itemData[filter_key])) continue itemloop; continue filterloop; } if(filter_value == -1) continue filterloop; if(filter_value == 0){ if(!("location" in itemData) || itemData.location == 0) continue filterloop; continue itemloop; } if(!("location" in itemData)) continue itemloop; if(itemData.location != filter_value) continue itemloop; continue filterloop; }else{ if(Array.isArray(filter_value)){ if(!filter_value.includes(itemData[filter_key] || 0)) continue itemloop; continue filterloop; }else if(['string','number'].includes(typeof filter_value)){ if(itemData[filter_key] != filter_value) continue itemloop; continue filterloop; }else{ console.warn('Unreckognized filter format in $wardrobe.getlist():',filter_value); } } } let result = { id: item_id, type: type, vendor: vendor, subtype: subtype, index: index, image: this.itemImage(item_id), location: ("l" in item_data) ? item_data.l : 0, health: ("h" in item_data) ? item_data.h : -1, } results.push(result); } console.log("wardrobe.getList",filters,results); return results; }*/ has(itemId){ return (itemId in this._ownedItems); } inhibition(itemId:string){ return OutfitItem.get(itemId).inhibition; } isWearing(itemId:string):boolean{ for(const wornItemId of Object.values(this._wornItems)){ if(itemId == wornItemId) return true; } return false; } isWeargingItemAtSlot(type){ return(!(this._wornItems[type] == null)); } /** * @deprecated * @param {string} itemId * @returns {OutfitDefinition} */ itemConstantData(itemId:string):OutfitDefinition{ if(!setup.outfits[itemId]) return null; let raw = setup.outfits[itemId]; return raw; } /** * Return the constant data of an item * @deprecated * @param {string} itemId * @returns */ itemData(itemId:string):OutfitDefinition{ let constantData = this.itemConstantData(itemId); return constantData; } /*itemImage(itemId){ let identificator = this.itemData(itemId); let template = setup.outfitItemImagePath[identificator.type]; if(!template) console.error("ERROR: template not found",identificator); if(typeof template === "string") return template.formatUnicorn({vendor:identificator.vendor,id:identificator.index}); if(!template[identificator.vendor]?.[identificator.subtype]) console.error("ERROR: item-image-template is undefined",identificator,template[identificator.vendor]); return template[identificator.vendor][identificator.subtype].formatUnicorn({vendor:identificator.vendor,id:identificator.index}); }*/ /* itemImageAtSlot(slotId){ return this.itemImage(this._wornItems[slotId]); }*/ itemPrice(itemId,baseprice,pricemod=0){ let itemData = this.itemData(itemId); let type = itemData.type; if(type != 'shoes' && type != 'clothes') return baseprice; let quality = itemData.quality; let price_raw = (baseprice * ((5 * quality) + 100) / 100) * 1000 / (1250 - pricemod) * 3 / 2; let price_rounded = Math.round(price_raw / 50) * 50; return price_rounded; } lastWornSet(key){ this._lastWorn[key] = clone(this._wornItems); } //#region Outfit outfitAdd(key, outfitData=null){ if(!this._outfits) this._outfits = {}; if(outfitData) this._outfits[key] = clone(outfitData); else this._outfits[key] = clone(this._wornItems); } outfitIsWearable(key){ if(!(key in this._outfits)){ return false; } let slots = ['bra','clothes','panties','shoes']; for(let slot of slots){ let wearable = this.wearable(this._outfits[key][slot]); if(!wearable.total){ return false; } } return true; } //#endregion get isWearingSwimwear():boolean{ return (this.clothes.type == 'swimwear'); } get ownsSwimmingItem():boolean{ //return (this.getList({subtype:'bikini'}).length + this.getList({subtype:'swimsuit'}).length > 0) ? true : false; return (Object.keys(this.itemsFiltered({type:'swimwear'})).length > 0); } /** * Sends an item to the specified location. * Side effect: adds the item to the inventory if it isn't already in it. * @param {*} itemIdentification * @param {number} location */ sendToLocation(itemId,location){ let set = {l:location}; this.setMetadata(itemId,set); } setMetadata(itemId,metadata){ let temp = Object.assign({}, this._ownedItems[itemId], metadata); console.log("Item METADATA SET:",itemId,metadata,this._ownedItems[itemId],temp); this._ownedItems[itemId] = temp; } strip(type:string){ let item:OutfitItem = this[type]; if(!item.isValidItem) return; for(const slot of item.slots) this._wornItems[slot] = null; } stripAll(){ this.strip('bra'); this.strip('clothes'); this.strip('panties'); this.strip('shoes'); } wearable(itemId:string){ let result = { owned: true, health: true, inhibition: true, hips: true, various:[], total: true } var itemData:OutfitOwned; if(!this.has(itemId)){ result.owned = false; result.health = false; result.hips = false; result.total = false; return result; }else{ itemData = this.item(itemId); if(itemData.h == 0) result.health = false; if(itemData.bmi > 0){ result.hips = !([EWearableBMI.TOO_LOSE,EWearableBMI.TOO_TIGHT].includes(this.wearableBMI(itemId))); } } if(!this.wearbleInhibition(itemId)) result.inhibition = false; result.total = (result.owned && result.health && result.inhibition && result.hips); for(const wardrobeWearableFunction of Object.values(setup.wardrobeWearableFunctions)){ let functionValue = wardrobeWearableFunction(itemData); if(functionValue){ result.total = false; result.various.push(functionValue); } } return result; } wearableBMI(itemId:string):EWearableBMI{ const itemData = this.item(itemId); if(itemData.bmi === undefined) return EWearableBMI.NOT_APPLICABLE; if(!itemData.bmi) return EWearableBMI.ANY; if(itemData.bmi < 0) return EWearableBMI.NOT_APPLICABLE; const pcbmi = State.variables.pc.bmi; if(itemData.bmi - pcbmi > setup.wardrobeSettings.bmiSizeMaxDifference) return EWearableBMI.TOO_TIGHT; if(pcbmi - itemData.bmi > setup.wardrobeSettings.bmiSizeMaxDifference) return EWearableBMI.TOO_LOSE; if(itemData.bmi - pcbmi > setup.wardrobeSettings.bmiSizeMaxDifference * 0.75) return EWearableBMI.ALMOST_TOO_TIGHT; if(pcbmi - itemData.bmi > setup.wardrobeSettings.bmiSizeMaxDifference * 0.75) return EWearableBMI.ALMOST_TOO_LOSE; return EWearableBMI.OKAY; } //Return 0 if inhibition blocks, 1 if exciting and 2 in every other case wearbleInhibition(itemId){ const inhibition = this.inhibition(itemId); let playerInhib = State.variables.pc.pcs_inhib; if(inhibition <= playerInhib) return 2; if(inhibition - 10 <= playerInhib) return 1; return 0; } /** * Wear the specified item. Send it to the default wardrobe section. Adds the item to the inventory, if it isn't in it. * @param {*} itemIdentification * @param {boolean} [replace=true] replace what's currently worn? If false only adds the item to the inventory. */ wear(itemId,replace=true):boolean{ if(!this.has(itemId)) this.add(itemId); //let itemType = this.itemData(itemId).type; if(!replace){ let item = OutfitItem.get(itemId); for(const slot of item.slots){ let itemAtSlot:OutfitItem = this[slot]; if(itemAtSlot.isValidItem) return false; } } this.sendToLocation(itemId,0); console.log("WEARING NOW",itemId); this._wear(itemId); return true; } wearTemporary(itemId){ let itemType = this.itemData(itemId).type; this.strip(itemType); console.log("WEARING NOW",itemId,itemType); this._wear(itemId); } /*wear_clothes_legacy(type,vendorAndSubtype,index){ let parts = vendorAndSubtype.split('_',2); this.wear([type,parts[0],index,parts[1]]); }*/ //Caution: Unlike wear, this will not change the location of the worn item. _wear(itemOrId:string|OutfitItem){ let item:OutfitItem; if(typeof itemOrId == "string") item = OutfitItem.get(itemOrId); else item = itemOrId; for(const slot of item.slots){ this.strip(slot); this._wornItems[slot] = item.id; this._lastWorn['last'][slot] = item.id; } /*let itemType = this.itemData(itemId).type; this._wornItems[itemType] = itemId; this._lastWorn['last'][itemType] = itemId;*/ /*if(this.PCloBra == 1) this.strip('bra'); */ } /*wear_last(type){ this._wear(this._lastWorn['last'][type]); }*/ hasLastWorn(key){ return !(!this._lastWorn[key]); } wearLastWorn(key,consume=false){ if(!this._lastWorn[key]){ console.error("The last item set with key "+key+" has not been set!"); } this._wornItems = clone(this._lastWorn[key]); if(consume) delete this._lastWorn[key]; } wearOutfit(key){ this._wornItems = clone(this._outfits[key]); } wornItemData(type,index,def:any=0){ if(!this._wornItems[type]) return def; let id = this._wornItems[type]; let data = this.itemData(id); let returnValue = data[index] if(returnValue == undefined || returnValue == null) return def; return returnValue; } _shopitems = {} //{shopid:{expireday:day,pricemod:pricemod,list:[]}} shopItemIds(shopid:string,filters,count=30,expireday=undefined):string[] { if(shopid in this._shopitems){ if(this._shopitems[shopid].expireday >= State.variables.time.daystart){ let cachedList = this._shopitems[shopid].list; console.warn('Returning cached list',cachedList); return cachedList; } } let pricemod = rand(0,500); expireday ??= State.variables.time.daystart; let entrys:string[] = this.allItemIdsFiltered(filters,count,true); entrys = entrys.filter(itemId=>!this.has(itemId)); this.shopItemListSet(shopid,expireday,pricemod,entrys); return entrys; } shopItemList(shopid,filters,baseprice,count=30,expireday=null):{[itemId:string]:OutfitItem}{ let result:{[itemId:string]:OutfitItem} = {}; for(const itemId of this.shopItemIds(shopid,filters,count,expireday)){ let item = OutfitItem.get(itemId); Object.assign(item,{id: itemId,price: this.itemPrice(itemId,baseprice)}); result[itemId] = item; } return result; } shopItemListSet(shopid,expireday,pricemod,items){ this._shopitems[shopid] = { expireday: expireday, pricemod:pricemod, list: items } } filters = { shop_cost:true, shop_owned:false, shop_inhib_toohigh:false, shop_inhib_high:true, shop_inhib_low:true }; /*execute_every_1_hour(){ } execute_every_1_day(){ }*/ _init(wardrobe){ Object.keys(wardrobe).forEach(function (pn) { this[pn] = clone(wardrobe[pn]); }, this); return this; } clone = function () { return (new Wardrobe())._init(this); }; toJSON = function () { var ownData = {}; Object.keys(this).forEach(function (pn) { if(typeof this[pn] !== "function") ownData[pn] = clone(this[pn]); }, this); return JSON.reviveWrapper('(new Wardrobe())._init($ReviveData$)', ownData); }; } window.Wardrobe = Wardrobe; setup.outfits = {};