--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] local PLUGIN = PLUGIN PLUGIN.apartments = PLUGIN.apartments or {} -- Database formalia function PLUGIN:DatabaseConnected() local query = mysql:Create("ix_apartments_"..game.GetMap()) query:Create("app_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT") query:Create("app_name", "TEXT") query:Create("app_doors", "TEXT") query:Create("app_employees", "TEXT") query:Create("app_permits", "TEXT") query:Create("app_tenants", "TEXT") query:Create("app_lastactions", "TEXT") query:Create("app_rent", "TEXT") query:Create("app_payments", "TEXT") query:Create("app_type", "TEXT") query:Create("app_noassign", "TEXT") query:Create("app_rentdue", "TEXT") query:PrimaryKey("app_id") query:Callback(function() local appsQuery = mysql:Select("ix_apartments_"..game.GetMap()) appsQuery:Callback(function(appsResult) if (!istable(appsResult) or #appsResult == 0) then return end for _, v in pairs(appsResult) do local doorsCreationID = util.JSONToTable(v["app_doors"]) local doors = {} for _, v1 in pairs(doorsCreationID) do local ent = ents.GetMapCreatedEntity(v1) if (!ent) then continue end doors[#doors + 1] = ent:EntIndex() if (!ix.config.Get("shouldLockDoorsAfterRestart", true) or self.lockedApps) then continue end ent:Fire("Lock") local partner = ent:GetDoorPartner() if (IsValid(partner)) then partner:Fire("lock") end end self.apartments[tonumber(v["app_id"])] = { name = v["app_name"], doors = doors, employees = util.JSONToTable(v["app_employees"]), permits = util.JSONToTable(v["app_permits"]), tenants = util.JSONToTable(v["app_tenants"]), lastActions = util.JSONToTable(v["app_lastactions"]), rent = v["app_rent"], payments = util.JSONToTable(v["app_payments"]), type = v["app_type"], noAssign = v["app_noassign"], rentDue = v["app_rentdue"] } local employeeList = {} for cid, tEmployee in pairs(self.apartments[tonumber(v["app_id"])].employees) do employeeList[Schema:ZeroNumber(cid, 5)] = tEmployee end self.apartments[tonumber(v["app_id"])].employees = employeeList local tenantList = {} for cid, tTenant in pairs(self.apartments[tonumber(v["app_id"])].tenants) do tenantList[Schema:ZeroNumber(cid, 5)] = tTenant end self.apartments[tonumber(v["app_id"])].tenants = tenantList local lastActionList = {} for cid, osTime in pairs(self.apartments[tonumber(v["app_id"])].lastActions) do lastActionList[Schema:ZeroNumber(cid, 5)] = osTime end self.apartments[tonumber(v["app_id"])].lastActions = lastActionList local paymentList = {} for cid, tPaymentInfo in pairs(self.apartments[tonumber(v["app_id"])].payments) do paymentList[Schema:ZeroNumber(cid, 5)] = tPaymentInfo end self.apartments[tonumber(v["app_id"])].payments = paymentList end self.lockedApps = true end) appsQuery:Execute() end) query:Execute() end -- A function to create an apartment function PLUGIN:CreateApartment(client, appName, bNoNotify, sType, callback) if self:CheckIfApartmentExists(client, appName) then client:NotifyLocalized("Un appartement avec ce nom existe déjà...") return false end local permitsToAssign = {} for k, _ in pairs(ix.permits.get()) do permitsToAssign[k] = false end local queryAdd = mysql:Insert("ix_apartments_"..game.GetMap()) queryAdd:Insert("app_name", appName) queryAdd:Insert("app_doors", util.TableToJSON({})) queryAdd:Insert("app_employees", util.TableToJSON({})) queryAdd:Insert("app_permits", util.TableToJSON(permitsToAssign)) queryAdd:Insert("app_tenants", util.TableToJSON({})) queryAdd:Insert("app_lastactions", util.TableToJSON({})) queryAdd:Insert("app_rent", 0) queryAdd:Insert("app_payments", util.TableToJSON({})) queryAdd:Insert("app_type", sType) queryAdd:Insert("app_noassign", string.lower(sType) == "shop" and true or false) queryAdd:Insert("app_rentdue", os.time() + (!ix.config.Get("housingTesterMode", false) and 3600 * 24 * 7 * ix.config.Get("housingRentDueInWeeks", 1) or 10)) queryAdd:Callback(function(result, _, insertID) self.apartments[insertID] = { name = appName, doors = {}, employees = {}, permits = permitsToAssign, tenants = {}, lastActions = {}, rent = 0, payments = {}, type = sType, noAssign = string.lower(sType) == "shop" and true or false, rentDue = os.time() + (!ix.config.Get("housingTesterMode", false) and 3600 * 24 * 7 * ix.config.Get("housingRentDueInWeeks", 1) or 10) } if (callback) then callback() end self:SyncApartments(client) end) queryAdd:Execute() if !bNoNotify then client:NotifyLocalized("Vous avez ajouté avec succès un "..sType.." avec le nom : "..appName) end end -- A function to remove an apartment function PLUGIN:RemoveApartment(client, appName) local appID = self:CheckIfApartmentExists(client, appName) if appID then if self.apartments[appID] then for _, doorEntID in pairs(self.apartments[appID].doors) do local entDoor = Entity(doorEntID) if (IsValid(entDoor) and entDoor:IsDoor()) then entDoor:SetNetVar("visible", false) entDoor:SetNetVar("name", nil) local doorPlugin = ix.plugin.list["doors"] if doorPlugin then doorPlugin:SaveDoorData() end end end end self.apartments[appID] = nil local queryDelete = mysql:Delete("ix_apartments_"..game.GetMap()) queryDelete:Where("app_id", appID) queryDelete:Execute() client:NotifyLocalized("L'appartement a été retiré avec succès: "..appName) self:SyncApartments(client) else client:NotifyLocalized("Cet appartement n'existe pas..") end end -- A function to add a door to an apartment function PLUGIN:SetApartmentDoor(client, entDoor, appName) local existingAppID = self:CheckIfApartmentExists(client, appName) if !existingAppID then if ix.config.Get("shouldCreateNonExistingApartment", true) then client:NotifyLocalized("Cet appartement n'existait pas. Création d'un appartement non-prioritaire dont le nom est "..appName) self:CreateApartment(client, appName, true, "normal", function() PLUGIN:SetApartmentDoor(client, entDoor, appName) end) return else client:NotifyLocalized("Cet appartement n'existe pas.") return end end if self:CheckIfDoorAlreadyAdded(client, entDoor) then return false end self.apartments[existingAppID].doors[#self.apartments[existingAppID].doors + 1] = entDoor:EntIndex() local doors = {} for _, v in pairs(self.apartments[existingAppID].doors) do if (IsValid(Entity(v))) then local id = Entity(v):MapCreationID() if (id == -1) then continue end doors[#doors + 1] = id end end if (IsValid(entDoor) and entDoor:IsDoor()) then entDoor:SetNetVar("visible", true) if (appName:find("%S")) then entDoor:SetNetVar("name", appName) end local doorPlugin = ix.plugin.list["doors"] if doorPlugin then doorPlugin:SaveDoorData() end end local addDoor = mysql:Update("ix_apartments_"..game.GetMap()) addDoor:Where("app_id", existingAppID) addDoor:Update("app_doors", util.TableToJSON(doors)) addDoor:Execute() client:NotifyLocalized("Cette porte a été ajoutée avec succès à "..appName) self:SyncApartments(client) end -- A function to remove an door from an apartment function PLUGIN:RemoveApartmentDoor(client, entDoor) for appKey, tInfo in pairs(self.apartments) do for doorKey, doorIndex in pairs(tInfo.doors) do if doorIndex == entDoor:EntIndex() then table.remove(self.apartments[appKey].doors, doorKey) local doors = {} for _, v in pairs(self.apartments[appKey].doors) do if (IsValid(Entity(v))) then local id = Entity(v):MapCreationID() if (id == -1) then continue end doors[#doors + 1] = id end end if (IsValid(entDoor) and entDoor:IsDoor()) then entDoor:SetNetVar("visible", false) entDoor:SetNetVar("name", nil) local doorPlugin = ix.plugin.list["doors"] if doorPlugin then doorPlugin:SaveDoorData() end end local removeDoor = mysql:Update("ix_apartments_"..game.GetMap()) removeDoor:Where("app_id", appKey) removeDoor:Update("app_doors", util.TableToJSON(doors)) removeDoor:Execute() client:NotifyLocalized("Vous avez réussi à retirer cette porte de "..tInfo.name) self:SyncApartments(client) return true end end end client:NotifyLocalized("Cette porte n'a pas pu être trouvée assignée à un appartement...") return false end -- A function to set the rent of an apartment function PLUGIN:SetApartmentRent(client, appID, entDoor, newRent) if (appID) then self.apartments[appID].rent = newRent if PLUGIN.apartments[appID].type == "shop" then for _, shopTerminal in pairs(ents.FindByClass("ix_shopterminal")) do shopTerminal:UpdateScreen() end end self:UpdateApartment(appID) return true end if (entDoor) then local fetchedID = self:CheckIfDoorAlreadyAdded(client, entDoor, true) if (fetchedID) then self.apartments[fetchedID].rent = newRent self:UpdateApartment(fetchedID) client:NotifyLocalized("Prix du loyer "..self.apartments[fetchedID].name.." changé pour "..tostring(newRent).."!") else client:NotifyLocalized("Cette porte n'est ajoutée à aucun appartement !") end end end -- A function to remove a tenant from an apartment function PLUGIN:RemoveTenant(client, item, appID, bNoNotify) local itemCID = (!isnumber(tonumber(item)) and item:GetData("cid") or item) if !self.apartments[appID] then if !bNoNotify then client:NotifyLocalized("L'appartement n'a pas été trouvé.") end return end if !self.apartments[appID].tenants[itemCID] then if !bNoNotify then client:NotifyLocalized("Impossible de trouver un appartement avec ce CID comme locataire.") if !isnumber(tonumber(item)) then client:NotifyLocalized("Suppression de l'item attribué à l'appartement.") item:SetData("apartment", nil) end end return end self:LookUpCardItemIDByCID(tostring(itemCID), function(result) local idCardID = result[1].idcard or false local charID if !result then return end if !ix.item.instances[idCardID] then ix.item.LoadItemByID(idCardID, false, function(card) if !card then return end charID = card:GetData("owner") end) else charID = ix.item.instances[idCardID]:GetData("owner") end local permitsToApply = {} for k, v in pairs(self.apartments[appID].permits) do if v then permitsToApply[k] = !v end end local character = ix.char.loaded[charID] if character then for k, v in pairs(permitsToApply) do character:SetPermit(k, v) end else local query = mysql:Select("ix_characters_data") query:Where("key", "genericdata") query:Where("id", tostring(charID)) query:Select("data") query:Callback(function(genResult) if (!istable(genResult) or #genResult == 0) then return end local genericData = util.JSONToTable(genResult[1]["data"]) for k, v in pairs(permitsToApply) do genericData.permits[k] = v end local removePermits = mysql:Update("ix_characters_data") removePermits:Where("id", tostring(charID)) removePermits:Where("key", "genericdata") removePermits:Update("data", util.TableToJSON(genericData)) removePermits:Execute() end) query:Execute() end end) self.apartments[appID].tenants[itemCID] = nil self.apartments[appID].lastActions[itemCID] = nil if !isnumber(tonumber(item)) then item:SetData("apartment", nil) end if !bNoNotify then client:NotifyLocalized("Suppression du locataire "..itemCID.." de l'appartement.") end if self.apartments[appID].type == "shop" and table.IsEmpty(self.apartments[appID].tenants) then for _, shopTerminal in pairs(ents.FindByClass("ix_shopterminal")) do shopTerminal:UpdateScreen() end end self:UpdateApartment(appID) if !isnumber(tonumber(item)) then return end PLUGIN:LookUpCardItemIDByCID(tostring(itemCID), function(result) local idCardID = result[1].idcard or false if !result then return end if !ix.item.instances[idCardID] then ix.item.LoadItemByID(idCardID, false, function(cid) if !cid then return end cid:LoadOwnerGenericData(PLUGIN.RemoveTenantHousing, false, appID) end) else ix.item.instances[idCardID]:LoadOwnerGenericData(PLUGIN.RemoveTenantHousing, false, appID) end end) end function PLUGIN:RemoveEmployee(client, item, appID, bNoNotify) local itemCID = (!isnumber(tonumber(item)) and item:GetData("cid") or item) if !self.apartments[appID] then if !bNoNotify then client:NotifyLocalized("Could not find the apartment.") end return end if !self.apartments[appID].employees[itemCID] then if !bNoNotify then client:NotifyLocalized("Could not find an apartment with this CID as employee.") end return end self:LookUpCardItemIDByCID(tostring(itemCID), function(result) local idCardID = result[1].idcard or false local charID if !result then return end if !ix.item.instances[idCardID] then ix.item.LoadItemByID(idCardID, false, function(card) if !card then return end charID = card:GetData("owner") end) else charID = ix.item.instances[idCardID]:GetData("owner") end local permitsToApply = {} for k, v in pairs(self.apartments[appID].permits) do if v then permitsToApply[k] = !v end end local character = ix.char.loaded[charID] if character then for k, v in pairs(permitsToApply) do character:SetPermit(k, v) end else local query = mysql:Select("ix_characters_data") query:Where("key", "genericdata") query:Where("id", tostring(charID)) query:Select("data") query:Callback(function(gResult) if (!istable(gResult) or #gResult == 0) then return end local genericData = util.JSONToTable(gResult[1]["data"]) for k, v in pairs(permitsToApply) do genericData.permits[k] = v end local removePermits = mysql:Update("ix_characters_data") removePermits:Where("id", tostring(charID)) removePermits:Where("key", "genericdata") removePermits:Update("data", util.TableToJSON(genericData)) removePermits:Execute() end) query:Execute() end end) self.apartments[appID].employees[itemCID] = nil self.apartments[appID].lastActions[itemCID] = nil if !bNoNotify then client:NotifyLocalized("Removed the employee "..itemCID.." from the apartment.") end self:UpdateApartment(appID) if !isnumber(tonumber(item)) then return end end -- A function to add a or remove a key to an apartment function PLUGIN:AddKeyToApartment(client, item, apartment, bRemove, bNoNotify, bEmployee) local itemCID = (!isnumber(tonumber(item)) and item:GetData("cid") or item) local itemID = (!isnumber(tonumber(item)) and item:GetID() or true) if !self.apartments[apartment] then return end if !itemCID then return end if bRemove and !bEmployee then self:RemoveTenant(client, item, apartment) return elseif bRemove and bEmployee then self:RemoveEmployee(client, item, apartment) return end local assignedToShop = false local assignedToApp = false for appID, tApartment in pairs(self.apartments) do if tApartment.tenants[itemCID] or tApartment.employees[itemCID] then if tApartment.type == "shop" then assignedToShop = appID else assignedToApp = appID end end end if (self.apartments[apartment].type == "shop" and assignedToShop) then if !bNoNotify then client:NotifyLocalized("Le locataire "..itemCID.." est déjà attribué au magasin. "..self.apartments[assignedToShop].name) end return false end if (self.apartments[apartment].type != "shop" and assignedToApp) then if !bNoNotify then client:NotifyLocalized("Le locataire "..itemCID.." est déjà affecté à l'appartement "..self.apartments[assignedToApp].name) end return false end if !bEmployee then self.apartments[apartment].tenants[itemCID] = {key = itemID, autoPay = true} self.apartments[apartment].lastActions[itemCID] = os.time() else self.apartments[apartment].employees[itemCID] = {key = itemID} self.apartments[apartment].lastActions[itemCID] = os.time() end if !isnumber(tonumber(item)) and !bEmployee then item:SetData("apartment", apartment) end if !bNoNotify and !bEmployee then client:NotifyLocalized("Ajout du locataire "..itemCID.." au "..(self.apartments[apartment].type == "shop" and "shop " or "apartment ")..self.apartments[apartment].name) elseif !bNoNotify and bEmployee then client:NotifyLocalized("Ajout de l'employé "..itemCID.." au "..(self.apartments[apartment].type == "shop" and "shop " or "apartment ")..self.apartments[apartment].name) end self:UpdateApartment(apartment) return true end function PLUGIN:CheckIfCIDExistsLoaded(cid) local target = false -- Check if CID exists local cidCheck = tonumber(cid) != nil and string.utf8len( tostring(cid) ) <= 5 -- Check for cached characters for _, v in pairs(ix.char.loaded) do local targetCid = v.GetCid and v:GetCid() local name = v.GetName and v:GetName() if (cidCheck and targetCid) then if string.match( targetCid, cid ) then target = v break end elseif name and string.find(name, cid) then target = v break end end return target end function PLUGIN:CheckIfCIDExistsDatabase(cid) local target = false cid = tostring(cid) if (tonumber(cid) != nil and string.utf8len( cid ) <= 5) then local query = mysql:Select("ix_characters") query:Select("name") query:Where("cid", cid) query:Where("schema", Schema and Schema.folder or "helix") query:Callback(function(result) if (!istable(result) or #result == 0) then return end target = result end) query:Execute() end return target end -- A function to set the CID of a key function PLUGIN:SetKeyCID(client, item, cid) if !cid then if item:GetData("apartment") then client:NotifyLocalized("Vous devez d'abord supprimer l'appartement attribué.") return false end client:NotifyLocalized("CID supprimé de la clé.") item:SetData("cid", nil) return end if !self:CheckIfCIDExistsLoaded(cid) then if !self:CheckIfCIDExistsDatabase(cid) then client:NotifyLocalized("Ce CID n'existe pas !") return end end item:SetData("cid", cid) client:NotifyLocalized(" CID : "..cid.." assigné à la clé.") end -- A function for the key item to unlock/lock an apartment function PLUGIN:UnlockLockApartment(keyItem, bUnlock, entDoor) local appID = keyItem:GetData("apartment", false) local client = keyItem:GetOwner() if !appID then return false end if self:GetKeyHasAccess(keyItem, entDoor) then if (IsValid(client) and client:GetPos():Distance(entDoor:GetPos()) > 96) then client:NotifyLocalized("Vous n'êtes pas assez près de la porte !") return end if (entDoor:IsDoor()) then local partner = entDoor:GetDoorPartner() if entDoor.locked then return end if (!bUnlock) then if (IsValid(partner)) then partner:Fire("lock") end entDoor:Fire("lock") client:EmitSound("doors/door_latch3.wav") hook.Run("PlayerLockedDoor", client, entDoor, partner) else if (IsValid(partner)) then partner:Fire("unlock") end entDoor:Fire("unlock") client:EmitSound("doors/door_latch1.wav") hook.Run("PlayerUnlockedDoor", client, entDoor, partner) end end end end function PLUGIN:GetPriorityApartmentAccess(genericData) local loyaltyStatus = genericData.loyaltyStatus local tier = tonumber(self:GetNumbersFromText(loyaltyStatus)) local tierNeeded = tonumber(self:GetNumbersFromText(ix.config.Get("priorityHousingTierNeeded", "Collaborateur de Rang 1 (VERT)"))) if genericData.loyaltyStatus == "H.A.A" then return true end if (!tier or !isnumber(tier)) then return false end if (isnumber(tier) and tier < tierNeeded) then return false end return true end -- A function to assign an apartment function PLUGIN.AssignApartment(idCard, genericData, client, foundApartment) if idCard:GetCredits() < ix.config.Get("costForAnApartment", 35) then netstream.Start(client, "SendHousingErrorMessage", "PAS ASSEZ DE CRÉDITS") return end if !foundApartment then netstream.Start(client, "SendHousingErrorMessage", "AUCUN LOGEMENT TROUVÉ") return end if foundApartment == "priority" then if PLUGIN:GetPriorityApartmentAccess(genericData) then foundApartment = PLUGIN:GetWhichApartmentToAssign(foundApartment) if !foundApartment then netstream.Start(client, "SendHousingErrorMessage", "AUCUN LOGEMENT TROUVÉ") return end end end local cid = idCard:GetData("cid", false) if !cid then return false end for appID, v in pairs(PLUGIN.apartments) do if v.type == "shop" then continue end if v.tenants[cid] then PLUGIN:RemoveTenant(client, cid, appID, true) end end genericData.housing = foundApartment local combineutilities = ix.plugin.list["combineutilities"] if combineutilities and combineutilities.UpdateGenericData then combineutilities:UpdateGenericData(genericData) end local character = ix.char.loaded[genericData.id] if character then if !character:GetPurchasedItems()["apartmentkey"] then character:SetPurchasedItems("apartmentkey", 1) else client:NotifyLocalized("Il y a déjà une clé qui attend au terminal de dépôt pour ce CID. Il a été mis à jour.") end end idCard:TakeCredits(ix.config.Get("costForAnApartment", 35), "Logement", "Appartement acheté") ix.city.main:AddCredits(ix.config.Get("costForAnApartment", 35)) PLUGIN:AddKeyToApartment(client, cid, foundApartment, false, true) PLUGIN:SyncToOneApartments(client, false, foundApartment, genericData) end -- A function to update the assigned itemID of a CID tenant function PLUGIN:UpdateItemIDTenant(cid, itemID, type) for appID, v in pairs(self.apartments) do if type:find("shop") and v.type != "shop" then continue end if type:find("apartment") and v.type == "shop" then continue end if !v.tenants[cid] then continue end if v.tenants[cid].key == itemID then break end self.apartments[appID].tenants[cid].key = itemID self:UpdateApartment(appID) break end end function PLUGIN:UpdateItemIDEmployee(cid, itemID, type) for appID, v in pairs(self.apartments) do if type:find("shop") and v.type != "shop" then continue end if type:find("apartment") and v.type == "shop" then continue end if !v.employees[cid] then continue end if v.employees[cid].key == itemID then break end self.apartments[appID].employees[cid].key = itemID self:UpdateApartment(appID) break end end -- A function to handle the apartment assignment request function PLUGIN:HandleAssignment(client, cid, type) cid = self:HasCIDInInventory(client, cid) if !cid then return false end local foundApartment = type if type != "priority" then foundApartment = self:GetWhichApartmentToAssign(type) end cid:LoadOwnerGenericData(self.AssignApartment, false, client, foundApartment) end function PLUGIN:CheckTenantInteraction() local interactionWeeks = ix.config.Get("tenantDoorInteractionCheck", 2) for appID, tApartment in pairs(self.apartments) do for cid, time in pairs(tApartment.lastActions) do if (os.time() < (tonumber(time) + 3600 * 24 * 7 * interactionWeeks)) then continue end self:RemoveTenant(false, cid, appID, true) end end end function PLUGIN:LookUpCardItemIDByCID(cid, callback) local query = mysql:Select("ix_characters") query:Select("idcard") query:WhereIn("cid", cid) query:Callback(function(result) if (!istable(result) or #result == 0) then return end if (callback) then callback(result) end end) query:Execute() end function PLUGIN:PayRentOnCheck(idCard, individualRent, cid, appID) local credits = idCard and idCard.GetCredits and idCard:GetCredits() local madePayment = false if (!idCard or (idCard and !credits)) then return false end if (idCard and credits) and (credits >= individualRent) then idCard:TakeCredits(individualRent, "Logement", "Location") ix.city.main:AddCredits(individualRent) if self.apartments[appID].payments[cid] then self.apartments[appID].payments[cid] = {amount = individualRent + self.apartments[appID].payments[cid].amount, date = os.time()} else self.apartments[appID].payments[cid] = {amount = individualRent, date = os.time()} end madePayment = cid else self:RemoveTenant(false, cid, appID, true) end return madePayment end function PLUGIN:CheckRentPayments() for appID, tApartment in pairs(self.apartments) do if os.time() < tonumber(tApartment.rentDue) then continue end local remainingRent = self:GetRemainingRent(tApartment) if !remainingRent then return end if remainingRent <= 0 then self:ResetRent(appID) continue end local tenantCount = table.Count(tApartment.tenants) local individualRent = math.ceil( tApartment.rent / tenantCount ) for tenantCID, _ in pairs(tApartment.tenants) do local madePayment = false if tApartment.tenants[tenantCID].autoPay then self:LookUpCardItemIDByCID(tenantCID, function(result) local idCardID = result[1].idcard or false if !idCardID then ix.log.AddRaw("[LOGEMENT] "..tenantCID.." a été retiré de l'appartement "..appID..".") self:RemoveTenant(false, tenantCID, appID, true) return end if !ix.item.instances[tonumber(idCardID)] then ix.item.LoadItemByID(tonumber(idCardID), false, function(item) if !item then ix.log.AddRaw("[LOGEMENT] "..tenantCID.." La carte CID n'a pas été trouvée lors du traitement du paiement du loyer hors ligne pour le logement : "..appID..".") return end madePayment = self:PayRentOnCheck(ix.item.instances[tonumber(idCardID)], individualRent, tenantCID, appID) end) else madePayment = self:PayRentOnCheck(ix.item.instances[tonumber(idCardID)], individualRent, tenantCID, appID) end timer.Simple(10, function() if !madePayment then ix.log.AddRaw("[LOGEMENT] "..tenantCID.." n'a pas effectué de paiement automatique, vérifier les paiements non automatiques avant de désassigné le logement : "..appID..".") self:CheckNoAutoPayments(tApartment, appID, tenantCID) end end) end) end end timer.Simple(6, function() self:ResetRent(appID) end) end end function PLUGIN.RemovePermitsGeneric(idCard, genericData) genericData.permits = {} local combineutilities = ix.plugin.list["combineutilities"] if combineutilities and combineutilities.UpdateGenericData then combineutilities:UpdateGenericData(genericData) end end function PLUGIN:RemovePermits(tenantCID) tenantCID = Schema:ZeroNumber(tenantCID, 5) PLUGIN:LookUpCardItemIDByCID(tostring(tenantCID), function(result) local idCardID = result[1].idcard or false if !result then return end if !ix.item.instances[idCardID] then ix.item.LoadItemByID(idCardID, false, function(item) if !item then return end item:LoadOwnerGenericData(PLUGIN.RemovePermitsGeneric, false) end) else ix.item.instances[idCardID]:LoadOwnerGenericData(PLUGIN.RemovePermitsGeneric, false) end end) end function PLUGIN:CheckNoAutoPayments(tApartment, appID, tenantCID) local tenantCount = table.Count(tApartment.tenants) local individualRent = math.ceil( tApartment.rent / tenantCount ) if !tApartment.payments[tenantCID] then ix.log.AddRaw("[LOGEMENT] "..tenantCID.." n'a effectué aucun paiement manuel, supprimant l'identification du logement: "..appID..".. dev check: "..tonumber(isnumber(tenantCID))) self:RemoveTenant(false, tenantCID, appID, true) if tApartment.type == "shop" then self:RemovePermits(tenantCID) end return end for paymentCID, tPayments in pairs(tApartment.payments) do if tPayments.paidAmount and individualRent then if tPayments.paidAmount >= individualRent then continue end end if !tApartment.tenants[paymentCID] then continue end if tApartment.type == "shop" then self:RemovePermits(paymentCID) end ix.log.AddRaw("[LOGEMENT] "..paymentCID.." n'a pas payé le loyer au dessus du seuil minimum, le retirant du commerce : "..appID..".. dev check: "..isnumber(paymentCID)) self:RemoveTenant(false, paymentCID, appID, true) end end function PLUGIN:ResetRent(appID) self.apartments[appID].payments = {} self.apartments[appID].rentDue = self.apartments[appID].rentDue + (!ix.config.Get("housingTesterMode", false) and 3600 * 24 * 7 * ix.config.Get("housingRentDueInWeeks", 1) or 10) self:UpdateApartment(appID) end function PLUGIN:PreCharacterDeleted(client, character) local cid = character:GetCid() if !cid then return end for appID, tApartment in pairs(self.apartments) do if !tApartment.tenants[cid] then continue end self:RemoveTenant(client, cid, appID, true) end end function PLUGIN:OnCharacterBanned(character) local cid = character:GetCid() if !cid then return end for appID, tApartment in pairs(self.apartments) do if !tApartment.tenants[cid] then continue end self:RemoveTenant(false, cid, appID, true) end end function PLUGIN:OnCharacterBannedByID(charID) if (!ix.plugin.list.cid) then return end if !ix.plugin.list.cid.GenerateCID then return end local cid = ix.plugin.list.cid:GenerateCID(charID) for appID, tApartment in pairs(self.apartments) do if !tApartment.tenants[cid] then continue end self:RemoveTenant(false, cid, appID, true) end end do timer.Create("ixHousingCheckInteractionAndRent", ix.config.Get("housingCheckInteractionAndRentTimer", 20) * 60, 0, function() PLUGIN:CheckTenantInteraction() PLUGIN:CheckRentPayments() end) function PLUGIN.UpdateInteractionTimer(oldVal, newVal) timer.Adjust("ixHousingCheckInteractionAndRent", newVal * 60) end end