Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local FF_LOCAL_ARMOR_DATA = false
- while not _G.ErrorOut do wait() end
- local Create = LoadLibrary('RbxUtility').Create
- local IsInventoryFull = script:WaitForChild('IsInventoryFull')
- local GetItemCost = script:WaitForChild('GetItemCost')
- local QueueUpdateArmorData = script:WaitForChild('QueueUpdateArmorData')
- local ModifierManager = Workspace:WaitForChild('ModifierManager')
- local AddModifier = ModifierManager:WaitForChild('AddModifier')
- local RemoveModifier = ModifierManager:WaitForChild('RemoveModifier')
- -- Wait for a value of a given name to be parented to a given object,
- -- and for it to have a non-default value.
- function WaitForValueObject(parent, name, defaultValue)
- local obj = parent:WaitForChild(name)
- while obj.Value == defaultValue do obj.Changed:wait() end
- return obj
- end
- -- Same as WaitForValueObject but return the value of the recieved
- -- object rather than the object itself.
- function WaitForValueObjectValue(parent, name, defaultValue)
- return WaitForValueObject(parent, name, defaultValue).Value
- end
- -- Info about pagination for GUIs
- local PAGE_WIDTH = 4
- local PAGE_HEIGHT = 4
- local TMP_PAGE_COUNT = 1
- -- Get stat
- local GetStat = Workspace:WaitForChild('DataPersistence'):WaitForChild('GetStat')
- -- the names of the models that store the armor in a charcter, per slot
- local ArmorNamesInCharacterBySlotName = {Head = 'HeadArmor', Body = 'BodyArmor', Legs = 'LegsArmor'}
- -- names of slots to slot index
- local AllSlotNames = {'Head', 'Body', 'Legs'}
- local AllEquipNames = {'HeadEquip', 'BodyEquip', 'LegsEquip'}
- -- Copy the armor data into a local rather than leaving it in the lighting
- local OriginalArmorData = game.Lighting:WaitForChild('ArmorData')
- local ArmorData = OriginalArmorData:Clone()
- -- The armor data for players
- local EquipSlots = {}
- local PlayerAllItems = {}
- local PlayerPurgatory = {} -- List of bad items that could not be properly loaded
- local PlayerInventory = {}
- local PlayerEquips = {}
- local PlayerInventorySave = {}
- local PlayerCns = {}
- local PlayerTwinsTable = {}
- local IsLoaded = {}
- local RemItemLock = false
- -- Has the armor data been loaded at least once?
- local ArmorDataLoaded = false
- local ArmorDataTriedLoad = false
- local LastAssetString = nil
- local LocalShopDataValue = script:WaitForChild('ShopData')
- function UpdateArmorData_Item(id)
- local contents = game.InsertService:LoadAsset(id):GetChildren()
- if #contents == 1 and contents[1] then
- local armorModel = contents[1]
- -- On the first run, destroy the backup items we have if we are able to find
- -- the ones on the site.
- if ArmorData:FindFirstChild(armorModel.Name) then
- if ArmorDataTriedLoad then
- -- Only use the new armor if no one in the game currently has it (so
- -- that no references will be invalidated)
- local found = false
- for _, p in pairs(game.Players:GetChildren()) do
- if PlayerAllItems[p] then
- for _, item in pairs(PlayerAllItems[p]:GetChildren()) do
- if item.Name == armorModel.Name then
- found = true
- break
- end
- end
- if found then
- break
- end
- end
- end
- if not found then
- -- No one has the item right now, clone it in
- ArmorData[armorModel.Name]:Destroy()
- OriginalArmorData[armorModel.Name]:Destroy()
- end
- else
- -- Armor data has not done an initial load yet, use the new armor
- ArmorData[armorModel.Name]:Destroy()
- OriginalArmorData[armorModel.Name]:Destroy()
- end
- end
- if not ArmorData:FindFirstChild(armorModel.Name) then
- -- create the item
- armorModel:Clone().Parent = ArmorData
- armorModel:Clone().Parent = OriginalArmorData
- end
- end
- end
- function UpdateArmorData()
- local assetString;
- if FF_LOCAL_ARMOR_DATA then
- assetString = LocalShopDataValue.Value
- else
- assetString = game.MarketplaceService:GetProductInfo(123893658).Description
- end
- if assetString == LastAssetString then
- return
- end
- LastAssetString = assetString
- --
- local itemList = assetString:gmatch('items:{(.*)}')()
- local count = assetString:gmatch('count:(%d+)')()
- count = tonumber(count) -- Note: No, this can't be wrapped into the last line
- if itemList and count then
- local items = {}
- for id in itemList:gmatch('%d+') do
- table.insert(items, tonumber(id))
- end
- --
- if #items == count then
- for _, id in pairs(items) do
- UpdateArmorData_Item(id)
- end
- ArmorDataLoaded = true
- end
- end
- --
- ArmorDataTriedLoad = true
- end
- QueueUpdateArmorData.OnInvoke = function()
- Spawn(UpdateArmorData)
- end
- -- Spawn the armor data updater thread
- UpdateArmorData()
- Spawn(function()
- while true do
- wait(30)
- UpdateArmorData()
- end
- end)
- if FF_LOCAL_ARMOR_DATA then
- LocalShopDataValue.Changed:connect(UpdateArmorData)
- end
- -- Function to make an armor
- local function MakeItem(name)
- local def = ArmorData[name]
- local item = Create'Model'{
- Name = name;
- Create'ObjectValue'{
- Name = 'Def';
- Value = def;
- };
- Create'StringValue'{
- Name = 'Index';
- Value = '';
- };
- }
- local toIgnore = {Armor = true, Name = true, Desc = true, Slot = true, Thumbnail = true}
- for _, ch in pairs(def:GetChildren()) do
- if not toIgnore[ch.Name] then
- ch:Clone().Parent = item
- end
- end
- return item
- end
- local function FitsInSlot(itemObject, slotName)
- return itemObject.Def.Value.Slot.Value == slotName
- end
- local function IsEquipped(itemObject)
- return ArmorNamesInCharacterBySlotName[itemObject.Index.Value] ~= nil
- end
- -- functions to serialize in/out the inventory state to the persistent data
- local LETTERS = {
- 'a','b','c','d','e',
- 'f','g','h','i','j',
- 'k','l','m','n','o',
- 'p','q','r','s','t',
- 'u','v','w','x','y',
- 'z'
- }
- local function NumToLetters(key)
- if key < 26 then
- return LETTERS[key%26+1]
- else
- return LETTERS[math.floor(key/26)]..LETTERS[key%26+1]
- end
- end
- function SaveInventory(player)
- if not IsLoaded[player] then return end -- don't save unloaded inventories
- local inventory = PlayerInventory[player]
- --
- local nextKey = 0
- local keys = {}
- local translated = {}
- local function translate(key)
- if not translated[key] then
- translated[key] = NumToLetters(nextKey)
- keys[translated[key]] = key
- nextKey = nextKey + 1
- end
- return translated[key]
- end
- local str = 'return{'
- for i, slotName in pairs(AllSlotNames) do
- str = str..translate(slotName)..'={'
- -- save out the normal items
- for _, itemObject in pairs(PlayerAllItems[player]:GetChildren()) do
- if itemObject.Def.Value.Slot.Value == slotName then
- str = str..'{'..translate('Ident')..'="'..translate(itemObject.Def.Value.Name)..'",'
- -- Save out props
- for _, ch in pairs(itemObject:GetChildren()) do
- if ch.Name ~= 'Def' and (ch:IsA('StringValue') or ch:IsA('NumberValue') or ch:IsA('IntValue')) then
- str = str..translate(ch.Name)..'='
- if ch:IsA('StringValue') then
- str = str..'[['..ch.Value..']],'
- else
- str = str..tostring(ch.Value)..','
- end
- end
- end
- str = str..'},'
- end
- end
- -- save out the purgatory'd items
- if i == 1 then
- for _, purgatoryItem in pairs(PlayerPurgatory[player]) do
- str = str..'{'..translate('Ident')..'="'..translate(purgatoryItem.Ident)..'",'
- -- Save out the props
- for key, value in pairs(purgatoryItem) do
- if key ~= 'Ident' then
- if type(value) == 'string' then
- str = str..translate(key)..'=[['..value..']],'
- else
- str = str..translate(key)..'='..tostring(value)..','
- end
- end
- end
- --
- str = str..'},'
- end
- end
- --
- str = str..'},'
- end
- --
- str = str..'},{'
- for k, v in pairs(keys) do
- str = str..k..'="'..v..'",'
- end
- str = str..'}'
- --
- PlayerInventorySave[player].Set(str)
- end
- function LoadInventory(player)
- local allItems = PlayerAllItems[player]
- -- clear out current entries in the inventory (There should be none)
- allItems:ClearAllChildren()
- -- empty the inventory
- local inv = {}
- PlayerInventory[player] = inv
- -- indicies that we need to fix
- local itemsToFixIndexFor = {}
- -- now load the items
- local dat = PlayerInventorySave[player].Get()
- if not player.Parent then
- -- Player left, bail out
- return
- end
- if dat ~= '' then
- local f, err = loadstring(dat)
- if err then
- _G.ErrorOut("FATAL: Invalid Inventory State for "..player.Name)
- return
- end
- local data, lookup = f()
- local reverseLookup = {}
- for k, v in pairs(lookup) do reverseLookup[v] = k end
- --
- local purgatorySet = {}
- for slotName, listing in pairs(data) do
- for _, itemData in pairs(listing) do
- local ident = reverseLookup.Ident
- if ident and itemData[ident] then
- if ArmorData:FindFirstChild(lookup[itemData[ident]]) then
- -- we have a valid item, load it in
- local itemDef = ArmorData[lookup[itemData[ident]]]
- local newObject = Create'Model'{
- Name = itemDef.Name;
- Create'ObjectValue'{
- Name = 'Def';
- Value = itemDef;
- };
- Create'StringValue'{
- Name = 'Index';
- Value = '';
- };
- }
- local toIgnore = {Armor = true, Name = true, Desc = true, Slot = true,
- Thumbnail = true}
- for _, prop in pairs(itemDef:GetChildren()) do
- if not toIgnore[prop.Name] then
- local newProp = prop:Clone()
- newProp.Parent = newObject
- if reverseLookup[newProp.Name] and itemData[reverseLookup[newProp.Name]] then
- newProp.Value = itemData[reverseLookup[newProp.Name]]
- end
- end
- end
- -- get Index
- if reverseLookup['Index'] then
- local index = itemData[reverseLookup['Index']]
- if index == '' or type(index) == 'number' then
- itemsToFixIndexFor[newObject] = index
- else
- newObject.Index.Value = index
- if ArmorNamesInCharacterBySlotName[index] then
- if PlayerEquips[player][index].Value then
- itemsToFixIndexFor[newObject] = true
- else
- PlayerEquips[player][index].Value = newObject
- end
- else
- local page, x, y = index:gmatch('(%d+):(%d+):(%d+)')()
- page, x, y = tonumber(page), tonumber(x), tonumber(y)
- if not inv[page] then inv[page] = {} end
- if not inv[page][x] then inv[page][x] = {} end
- if inv[page][x][y] then
- itemsToFixIndexFor[newObject] = true
- else
- inv[page][x][y] = newObject
- end
- end
- -- add it to the items list if it doesn't need to be fixed
- if not itemsToFixIndexFor[newObject] then
- newObject.Parent = allItems
- end
- end
- end
- else
- -- no def, put the item in purgatory.
- if not purgatorySet[itemData] then
- local purgatoryItem = {}
- purgatoryItem.Ident = lookup[itemData[ident]]
- for symbol, value in pairs(itemData) do
- if lookup[symbol] ~= 'Ident' then
- -- load all the props translated
- purgatoryItem[lookup[symbol]] = value
- end
- end
- purgatorySet[itemData] = true
- table.insert(PlayerPurgatory[player], purgatoryItem)
- end
- end
- else
- _G.ErrorOut("FATAL: Malformed data when loading inventory")
- end
- end
- end
- end
- -- fix up indicies from the old flat indexing to the new paged inventory layout
- for itemObject, index in pairs(itemsToFixIndexFor) do
- itemObject.Index.Value = ''
- if index == 1 then
- -- We should try to equip this one, it was equipped before
- if not TryToEquip(player, itemObject) then
- FindSlotFor(player, itemObject)
- end
- else
- FindSlotFor(player, itemObject)
- end
- -- add it to the items list
- itemObject.Parent = allItems
- end
- IsLoaded[player] = true
- end
- function FindSlotFor(player, itemObject)
- if itemObject.Index.Value ~= '' then return true end
- local inv = PlayerInventory[player]
- for page = 1, TMP_PAGE_COUNT do
- for y = 1, PAGE_HEIGHT do
- for x = 1, PAGE_WIDTH do
- if not inv[page] or not inv[page][x] or not inv[page][x][y] then
- if not inv[page] then inv[page] = {} end
- if not inv[page][x] then inv[page][x] = {} end
- inv[page][x][y] = itemObject
- itemObject.Index.Value = page..':'..x..':'..y
- return true
- end
- end
- end
- end
- return false
- end
- -- Returns: Whether the equip was successfull
- function TryToEquip(player, itemObject)
- if IsEquipped(itemObject) then
- -- we are already equipped
- return true
- end
- local inv = PlayerInventory[player]
- for _, slotName in pairs(AllSlotNames) do
- if FitsInSlot(itemObject, slotName) then
- local slot = PlayerEquips[player][slotName]
- if slot and not slot.Value then
- local page, x, y = itemObject.Index.Value:gmatch('(%d+):(%d+):(%d+)')()
- if page then
- inv[page][x][y] = nil
- elseif itemObject.Index.Value == '' then
- -- nothing to do
- else
- _G.ErrorOut("Bad item index found: "..itemObject.Index.Value)
- return false
- end
- slot.Value = itemObject
- itemObject.Index.Value = slotName
- return true
- end
- end
- end
- return false
- end
- function FindOriginalItemFor(player, twin)
- for itemObject, twinObject in pairs(PlayerTwinsTable[player]) do
- if twinObject == twin then
- return itemObject
- end
- end
- return nil
- end
- -- Function to reorder the inventory
- function MoveInventoryItemToSlot(player, twinItemObject, page, x, y)
- -- Error checking
- if not page or not x or not y then print("Missing arg") return end
- if page > TMP_PAGE_COUNT or page < 1 then print("Bad page") return end
- if x < 1 or y < 1 or x > PAGE_WIDTH or y > PAGE_HEIGHT then print("Bad coord") return end
- --
- local inv = PlayerInventory[player]
- local itemObject = FindOriginalItemFor(player, twinItemObject)
- --
- if not itemObject then print("Invalid item") return end
- if itemObject.Index.Value == '' then print("Empty index for item to swap") return end
- --
- local mypage, myx, myy = itemObject.Index.Value:gmatch('(%d+):(%d+):(%d+)')()
- mypage, myx, myy = tonumber(mypage), tonumber(myx), tonumber(myy)
- --
- -- if we were equipped, clear the equip
- if IsEquipped(itemObject) then
- PlayerEquips[player][itemObject.Index.Value].Value = nil
- elseif not mypage or not myx or not myy then
- print("Item at non-numeric index")
- return
- else
- inv[mypage][myx][myy] = nil
- end
- --
- local swapItemObject = ((inv[page] or {})[x] or {})[y]
- if swapItemObject then
- -- Do a swap
- if IsEquipped(itemObject) then
- -- Can't swap if one of the items would be left in a slot that it's not allowed in
- if not FitsInSlot(swapItemObject, itemObject.Index.Value) then
- print("Swap bad, equip item ", swapItemObject, "to slot", itemObject.Index.Value)
- return
- end
- swapItemObject.Index.Value = itemObject.Index.Value
- PlayerEquips[player][swapItemObject.Index.Value].Value = swapItemObject
- else
- swapItemObject.Index.Value = itemObject.Index.Value
- inv[mypage][myx][myy] = swapItemObject
- end
- end
- -- Update this item index
- itemObject.Index.Value = page..':'..x..':'..y
- -- Actually add to inv table
- if not inv[page] then inv[page] = {} end
- if not inv[page][x] then inv[page][x] = {} end
- inv[page][x][y] = itemObject
- -- And save the inv with the update
- SaveInventory(player)
- end
- -- Function to reorder the inv
- function MoveInventoryItemToEquip(player, twinItemObject, slotName)
- -- Error checking
- if not slotName then print("Missing slot name") return end
- if not ArmorNamesInCharacterBySlotName[slotName] then print("Bad slot name") return end
- --
- local inv = PlayerInventory[player]
- local itemObject = FindOriginalItemFor(player, twinItemObject)
- --
- if not itemObject then print("Invalid item") return end
- if itemObject.Index.Value == '' then print("Empty index for item to swap") return end
- --
- local mypage, myx, myy = itemObject.Index.Value:gmatch('(%d+):(%d+):(%d+)')()
- mypage, myx, myy = tonumber(mypage), tonumber(myx), tonumber(myy)
- --
- -- if we were equipped, clear the equip
- if IsEquipped(itemObject) then
- PlayerEquips[player][itemObject.Index.Value].Value = nil
- elseif not mypage or not myx or not myy then
- print("Item at non-numeric index")
- return
- else
- inv[mypage][myx][myy] = nil
- end
- --
- local swapItemObject = PlayerEquips[player][slotName].Value
- if swapItemObject then
- -- Do a swap
- if IsEquipped(itemObject) then
- -- Can't swap if one of the items would be left in a slot that it's not allowed in
- if not FitsInSlot(swapItemObject, itemObject.Index.Value) then
- print("Swap bad, equip item ", swapItemObject, "to slot", itemObject.Index.Value)
- return
- end
- swapItemObject.Index.Value = itemObject.Index.Value
- PlayerEquips[player][swapItemObject.Index.Value].Value = swapItemObject
- else
- swapItemObject.Index.Value = itemObject.Index.Value
- inv[mypage][myx][myy] = swapItemObject
- end
- end
- itemObject.Index.Value = slotName
- PlayerEquips[player][slotName].Value = itemObject
- -- And save the inv with the update
- SaveInventory(player)
- end
- -- Give a player an item
- function _G.AwardItem(player, itemName)
- -- Make sure we get the most recent armor data
- UpdateArmorData()
- if ArmorData:FindFirstChild(itemName) then
- local item = MakeItem(itemName)
- item.Parent = PlayerAllItems[player]
- return true
- else
- return false
- end
- end
- -- Get the cost of an item
- GetItemCost.OnInvoke = function(itemName)
- local item = ArmorData:FindFirstChild(itemName)
- if item then
- local cost = item:FindFirstChild('Cost')
- if cost then
- return cost.Value
- else
- return 0
- end
- else
- return nil
- end
- end
- -- check if an inv is full
- IsInventoryFull.OnInvoke = function(player)
- local inv = PlayerInventory[player]
- for page = 1, TMP_PAGE_COUNT do
- if inv[page] then
- for x = 1, PAGE_WIDTH do
- if inv[page][x] then
- for y = 1, PAGE_HEIGHT do
- if not inv[page][x][y] then
- return false
- end
- end
- else
- return false
- end
- end
- else
- return false
- end
- end
- return true
- end
- function MakeArmorstatsMirror(player)
- local armorstats = Instance.new('Model')
- armorstats.Name = 'armorstats'
- local HeadEquip = Instance.new('ObjectValue', armorstats)
- HeadEquip.Name = 'HeadEquip'
- local BodyEquip = Instance.new('ObjectValue', armorstats)
- BodyEquip.Name = 'BodyEquip'
- local LegsEquip = Instance.new('ObjectValue', armorstats)
- LegsEquip.Name = 'LegsEquip'
- local AllItems = Instance.new('Model', armorstats)
- AllItems.Name = 'AllItems'
- armorstats.Parent = player
- return armorstats
- end
- -- Handle inventory for entering and leaving players
- function onPlayerEntered(player)
- -- Make an inventory table for them
- local inv = {}
- PlayerInventory[player] = inv
- -- get the save
- PlayerInventorySave[player] = GetStat:Invoke(player, 'Inventory')()
- if not player.Parent then
- -- Bail out, player left right away
- return
- end
- -- Make the armor stats mirror
- local armorstats = MakeArmorstatsMirror(player)
- -- Make an allitems for them
- local allItems = Create'Model'{
- Name = 'AllItems';
- }
- local allItemsMirror = player.armorstats.AllItems
- PlayerAllItems[player] = allItems
- -- create purgatory
- PlayerPurgatory[player] = {}
- -- Set up tracking for that allitems twinning
- local objectToTwin = {}
- -- make the equipped slots
- local equips = {}
- local modifiers = {}
- for i, equipName in pairs(AllEquipNames) do
- local slotName = AllSlotNames[i]
- equips[slotName] = Create'ObjectValue'{
- Name = equipName;
- }
- modifiers[slotName] = {}
- equips[slotName].Changed:connect(function()
- -- Remove old modifiers
- for _, modifier in pairs(modifiers[slotName]) do
- RemoveModifier:Invoke(player, modifier)
- end
- modifiers[slotName] = {}
- -- Apply new modifiers
- local itemObject = equips[slotName].Value
- if itemObject then
- local def = itemObject:FindFirstChild('Def')
- if def and def.Value then
- local modifierList = def.Value:FindFirstChild('Modifiers')
- print(modifierList)
- if modifierList then
- for _, modifier in pairs(modifierList:GetChildren()) do
- table.insert(modifiers[slotName], AddModifier:Invoke(player, modifier.Name, modifier.Value))
- end
- end
- end
- end
- end)
- -- mirror it
- local mirror = armorstats[equipName]
- mirror.Changed:connect(function(pr)
- -- Reparenter
- if pr == 'Parent' then
- mirror.Parent = armorstats
- end
- end)
- equips[slotName].Changed:connect(function()
- if equips[slotName].Value then
- while not objectToTwin[equips[slotName].Value] do wait() end
- end
- mirror.Value = objectToTwin[equips[slotName].Value]
- end)
- end
- PlayerEquips[player] = equips
- PlayerTwinsTable[player] = objectToTwin
- local twinObjectToRecreate = {}
- local itemAddCn = allItems.ChildAdded:connect(function(itemObject)
- -- set up twinning for the child
- local lastTwinCn;
- local function makeTwin()
- if lastTwinCn then
- lastTwinCn:disconnect()
- lastTwinCn = nil
- end
- local twin = itemObject:Clone()
- objectToTwin[itemObject] = twin
- twin.Parent = allItemsMirror
- itemObject.ChildAdded:connect(function(ch)
- -- twin the child
- local chTwin = ch:Clone()
- chTwin.Parent = twin
- -- on changed update
- ch.Changed:connect(function()
- chTwin.Value = ch.Value
- end)
- end)
- lastTwinCn = itemObject.ChildRemoved:connect(function(ch)
- twin:Destroy()
- end)
- for _, ch in pairs(itemObject:GetChildren()) do
- local twinCh = twin[ch.Name]
- ch.Changed:connect(function()
- twinCh.Value = ch.Value
- end)
- end
- -- change the twin def to point to the lighting armordata
- twin.Def.Value = OriginalArmorData:FindFirstChild(itemObject.Def.Value.Name)
- -- save it
- twinObjectToRecreate[twin] = makeTwin
- return twin
- end
- makeTwin()
- -- set the inv table
- if not FindSlotFor(player, itemObject) then
- TryToEquip(player, itemObject)
- end
- -- save the change
- SaveInventory(player)
- -- handle killing it when it's condition reaches 0
- if itemObject:FindFirstChild('MaxHealth') and itemObject.MaxHealth.Value > 0 then
- local conditionValue = itemObject:FindFirstChild('Condition')
- if conditionValue then
- if conditionValue.Value == 0 then
- Delay(0, function()
- itemObject.Parent = nil
- end)
- end
- conditionValue.Changed:connect(function()
- if conditionValue.Value <= 0.00001 then
- Delay(0, function()
- itemObject.Parent = nil
- end)
- else
- SaveInventory(player)
- end
- end)
- end
- end
- end)
- local itemRemCn = allItems.ChildRemoved:connect(function(itemObject)
- if objectToTwin[itemObject] then
- RemItemLock = true
- objectToTwin[itemObject]:Destroy()
- objectToTwin[itemObject] = nil
- RemItemLock = false
- end
- -- item removed, remove it from the inv or equip slot
- if IsEquipped(itemObject) then
- PlayerEquips[player][itemObject.Index.Value].Value = nil
- else
- local page, x, y = itemObject.Index.Value:gmatch('(%d+):(%d+):(%d+)')()
- PlayerInventory[player][tonumber(page)][tonumber(x)][tonumber(y)] = nil
- end
- -- save the change
- SaveInventory(player)
- end)
- -- recreate twins on removed
- player:WaitForChild('armorstats'):WaitForChild('AllItems').ChildRemoved:connect(function(ch)
- if not RemItemLock and twinObjectToRecreate[ch] then
- twinObjectToRecreate[ch]()
- end
- end)
- armorstats.Changed:connect(function(pr)
- if pr == 'Parent' then
- -- Reparenter
- armorstats.Parent = player
- end
- end)
- allItemsMirror.Changed:connect(function(pr)
- if pr == 'Parent' then
- -- Reparenter
- allItemsMirror.Parent = armorstats
- end
- end)
- PlayerCns[player] = {itemAddCn, itemRemCn}
- -- Now, load in the inventory
- LoadInventory(player)
- -- If we have the basics, remove them from the inv
- if allItems:FindFirstChild('BasicHead') then
- allItems.BasicHead.Parent = nil
- end
- if allItems:FindFirstChild('BasicLegs') then
- allItems.BasicLegs.Parent = nil
- end
- if allItems:FindFirstChild('BasicBody') then
- allItems.BasicBody.Parent = nil
- end
- end
- function onPlayerLeaving(player)
- if not player:IsA('Player') then return end
- -- disconnect stuff
- if PlayerCns[player] then
- for _, cn in pairs(PlayerCns[player]) do
- cn:disconnect()
- end
- end
- -- clean up their values. Note, this will succeed no matter what point
- -- initialization got to.
- PlayerInventory[player] = nil
- PlayerEquips[player] = nil
- PlayerAllItems[player] = nil
- PlayerCns[player] = nil
- PlayerTwinsTable[player] = nil
- PlayerPurgatory[player] = nil
- PlayerInventorySave[player] = nil
- end
- game.Players.PlayerAdded:connect(onPlayerEntered)
- for _, player in pairs(game.Players:GetChildren()) do
- onPlayerEntered(player)
- end
- game.Players.ChildRemoved:connect(onPlayerLeaving)
- -- Handle messages
- script.ChildAdded:connect(function(ch)
- if not ch:IsA('ObjectValue') then return end
- -- wait on name
- while ch.Name == 'Value' do ch.Changed:wait() end
- while not ch.Value do ch.Changed:wait() end
- --
- local player = ch.Value
- if not player:IsA('Player') then return end
- --
- Delay(0.2, function()
- ch:Destroy()
- end)
- --
- if ch.Name == 'MoveItem' then
- local item = WaitForValueObjectValue(ch, 'Item', nil)
- if not ch.Parent then return end
- local targetIndex = WaitForValueObjectValue(ch, 'TargetIndex', '')
- if ArmorNamesInCharacterBySlotName[targetIndex] then
- MoveInventoryItemToEquip(player, item, targetIndex)
- else
- local page, x, y = targetIndex:gmatch('(%d+):(%d+):(%d+)')()
- --
- MoveInventoryItemToSlot(player, item, tonumber(page), tonumber(x), tonumber(y))
- end
- --
- elseif ch.Name == 'PluginAwardItem' then
- -- local itemName = WaitForValueObjectValue(ch, 'Ident', '')
- -- MakeItem(itemName).Parent = PlayerAllItems[player]
- elseif ch.Name == 'AblateArmor' then
- local itemModel = WaitForValueObjectValue(ch, 'Armor', nil)
- if not ch.Parent then return end
- local damage = WaitForValueObjectValue(ch, 'AblationDamage', 0)
- -- translate itemModel
- if player.Parent then
- local found = false
- for model, twin in pairs(PlayerTwinsTable[player]) do
- if twin == itemModel then
- itemModel = model
- found = true
- break
- end
- end
- if found then
- if itemModel:FindFirstChild('MaxHealth') and itemModel:FindFirstChild('Condition') then
- itemModel.Condition.Value = math.max(0, itemModel.Condition.Value - damage/itemModel.MaxHealth.Value)
- end
- end
- end
- end
- end)
- --==========================================================================================================--
- --== Armor drawing part of the code
- --==
- -- equip a character with a given armor look
- -- Returns: A connection that needs to be disconnected when the
- -- item is unequipped. (There isn't a better way to do that?)
- function DoEquipItem(player, item)
- if not player.Character then return end
- local Character = player.Character
- --
- local itemDef = WaitForValueObjectValue(item, 'Def', nil)
- if not item.Parent then return end -- check that the item still exists
- --
- local slotName = WaitForValueObjectValue(itemDef, 'Slot', '')
- if not item.Parent then return end -- check that the item still exists
- local modelName = ArmorNamesInCharacterBySlotName[slotName]
- --
- local partDefs = itemDef:WaitForChild('Armor')
- if not item.Parent then return end -- check that the item still exists
- -- get rid of the old armor if it exists
- if Character:FindFirstChild(modelName) then -- remove armor
- Character[modelName]:Destroy()
- end
- -- make a new armor
- local armorModel = Create'Model'{
- Name = modelName;
- Parent = Character;
- }
- -- copy over components from the armor def
- local allArmorFadeParts = {}
- for _, chPart in pairs(Character:GetChildren()) do
- if chPart:IsA('BasePart') then
- local basePart = partDefs:FindFirstChild(chPart.Name)
- if basePart then
- for _, w in pairs(basePart:GetChildren()) do
- if w:IsA('JointInstance') then
- -- make the armor part
- local attachedPart = w.Part1:Clone()
- attachedPart.Parent = armorModel
- local newW = w:Clone()
- newW.Parent = attachedPart
- newW.Part0 = chPart
- newW.Part1 = attachedPart
- -- is it a fade part?
- if attachedPart:FindFirstChild('Fade') and attachedPart.Fade.Value then
- table.insert(allArmorFadeParts, attachedPart)
- end
- end
- end
- end
- end
- end
- -- add coloration
- if partDefs:FindFirstChild('BaseColor') then
- partDefs.BaseColor:Clone().Parent = Character
- end
- -- handle condition
- local conditionValue = item:FindFirstChild('Condition')
- if conditionValue then
- local function UpdateCondition()
- local condition = conditionValue.Value
- if condition < 0.8 then
- condition = condition / 0.8
- local trans = 0.5*(1-condition)
- --
- for _, part in pairs(allArmorFadeParts) do
- part.Transparency = trans
- end
- end
- end
- local cn = conditionValue.Changed:connect(UpdateCondition)
- UpdateCondition()
- end
- --
- return cn
- end
- -- unequip a character of all armors in a given slot
- function DoUnequipItem(player, slotName)
- if player.Character then
- local modelName = ArmorNamesInCharacterBySlotName[slotName]
- local armorModel = player.Character:FindFirstChild(modelName)
- if armorModel then armorModel:Destroy() end
- end
- end
- -- connect up a player to do equipping of armor
- function HandlePlayer(player)
- local Armorstats = player:WaitForChild('armorstats')
- if not player.Parent then return end
- --
- local HeadEquip = Armorstats:WaitForChild('HeadEquip')
- if not player.Parent then return end
- local BodyEquip = Armorstats:WaitForChild('BodyEquip')
- if not player.Parent then return end
- local LegsEquip = Armorstats:WaitForChild('LegsEquip')
- if not player.Parent then return end
- local AllItems = Armorstats:WaitForChild('AllItems')
- if not player.Parent then return end
- --
- local SlotNameToEquipValue = {Head = HeadEquip, Body = BodyEquip, Legs = LegsEquip}
- -- for each armor slot
- for slotName, equipValue in pairs(SlotNameToEquipValue) do
- local lastEquipCn;
- local lastEquippedItem;
- -- when a new item is equipped... update
- equipValue.Changed:connect(function()
- if equipValue.Value and equipValue.Value ~= lastEquippedItem then
- if lastEquipCn then lastEquipCn:disconnect() end
- lastEquippedItem = equipValue.Value
- lastEquipCn = DoEquipItem(player, equipValue.Value)
- else
- lastEquippedItem = nil
- DoUnequipItem(player, slotName)
- end
- end)
- -- update when we first load
- if equipValue.Value and equipValue.Value ~= lastEquippedItem then
- if lastEquipCn then lastEquipCn:disconnect() end
- lastEquippedItem = equipValue.Value
- lastEquipCn = DoEquipItem(player, equipValue.Value)
- end
- -- update when a character respawns
- player.CharacterAdded:connect(function(character)
- if equipValue.Value then
- if lastEquipCn then lastEquipCn:disconnect() end
- lastEquipCn = DoEquipItem(player, equipValue.Value)
- end
- local hum = character:WaitForChild('Humanoid')
- hum.Died:wait()
- -- Make armor cancollide on death
- for _, armorModelName in pairs(ArmorNamesInCharacterBySlotName) do
- if character:FindFirstChild(armorModelName) then
- for _, part in pairs(character[armorModelName]:GetChildren()) do
- if part:IsA('BasePart') then
- part.CanCollide = true
- end
- end
- end
- end
- end)
- end
- end
- -- main connection
- game.Players.ChildAdded:connect(HandlePlayer)
- for _, p in pairs(game.Players:GetChildren()) do
- HandlePlayer(p)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement