--[[ This is the virtual sex system created by 𝓜𝓲𝓵𝓵𝓱𝓲𝓸𝓻𝓮 𝓑𝓣 For TFS-master 1.5 server The virtual sex system is a system that allows players to have sexual relations with other players, this system is fully configurable and can be modified to suit the user. -- WARNING -- > If you are a programmer and you want to modify the system, you can do it, surely you know what you are doing. > If you're not a programmer, don't modify anything you don't understand, as it may cause system errors. ]]-- local talkActionWords = "!sex" local sexSystem = { types = {"oral", "anal", "vaginal"}, intensities = {"mild", "normal", "strong", "extreme", "painful"}, conditionTimes = { -- Depending on the intensity the benefits will last longer active. mild = 60000, -- 1 Minute normal = 120000, -- 2 Minutes strong = 180000, -- 3 Minutes extreme = 240000, -- 4 Minutes painful = 300000 -- 5 Minutes }, childrenId = 6579, childrenMaintance = 10, -- 10% gold from father to mother. childrenChance = 50, -- 50% chance of getting pregnant if the condom fails. whiteListStorageBase = 670000, whiteListStorageMax = 100, blackListStorageBase = 670100, blackListStorageMax = 100 } local sexPoses = { [PLAYERSEX_FEMALE] = { oral = {"Dressed and seated", "The 69, but on the side", "On knees", "Above his mouth"}, anal = {"The doggy", "Side", "Face down", "Riding"}, vaginal = {"The back lying", "Romantic landscape", "The amazon", "The missionary"} }, [PLAYERSEX_MALE] = { oral = {"The lazy", "The supported", "The king of the world", "The automatic"}, anal = {"At the border", "Standing", "The immersion", "The little spoon"}, vaginal = {"The rabbit", "Legs to shoulder", "The cowgirl", "Forklift truck"} } } local sexCondons = { { type = "Free", security = 0.25, price = 0 }, { type = "Latex", security = 0.99, price = 100 }, { type = "Polyurethane", security = 0.75, price = 50 }, { type = "Animal skin", security = 0.50, price = 10 } } local boostTypes = { regeneration = CONDITION_REGENERATION, skills = CONDITION_ATTRIBUTES, stats = CONDITION_ATTRIBUTES, speed = CONDITION_HASTE, critical = CONDITION_ATTRIBUTES, slowness = CONDITION_PARALYZE } local boostValues = { regeneration = {"HEALTHGAIN", "MANAGAIN"}, skills = {"SKILL_AXE", "SKILL_CLUB", "SKILL_SWORD"}, stats = {"STAT_MAGICPOINTS"}, speed = {"SPEED"}, critical = {"SPECIALSKILL_CRITICALHITCHANCE", "SPECIALSKILL_CRITICALHITAMOUNT"}, slowness = {"SPEED"} } local defaultValues = { regeneration = { HEALTHTICKS = 1000, MANATICKS = 1000 } } local sexBoosts = { [PLAYERSEX_FEMALE] = { oral = {regeneration = 100, skills = 10, stats = 10, speed = 10}, anal = {regeneration = 100, skills = 30, stats = 10 , slowness = 10}, vaginal = {regeneration = 200, skills = 20, stats = 20, speed = 20} }, [PLAYERSEX_MALE] = { oral = {regeneration = 100, skills = 10, stats = 10, speed = 10}, anal = {regeneration = 100, skills = 30, stats = 10 , critical = 10}, vaginal = {regeneration = 200, skills = 20, stats = 20, speed = 20} } } function sexSystem.applyBoosts(player, request) local sexBoost = sexBoosts[player:getSex()][request.type] if not sexBoost then return end for type, value in pairs(sexBoost) do local condition = Condition(boostTypes[type]) condition:setParameter(CONDITION_PARAM_TICKS, sexSystem.conditionTimes[request.intensity]) condition:setParameter(CONDITION_PARAM_SUBID, request.playerId) for _, boost in pairs(boostValues[type] or {}) do condition:setParameter(_G[string.format("CONDITION_PARAM_%s", boost)], value) end for boostType, boostValue in pairs(defaultValues[type] or {}) do condition:setParameter(_G[string.format("CONDITION_PARAM_%s", boostType)], boostValue) end player:addCondition(condition) end addEvent(function (playerId) local player = Player(playerId) if player then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("You have received a boost for %s seconds.", math.floor(sexSystem.conditionTimes[request.intensity] / 1000))) end end, 3000, player:getId()) end local function getIndexByList(player, listName, targetId) targetId = targetId or -1 for key = sexSystem[string.format("%sStorageBase", listName)], sexSystem[string.format("%sStorageMax", listName)] - 1 do if player.storage[key] == targetId then return key end end end local function setIndexByList(player, listName, targetId, value) local key = getIndexByList(player, listName, targetId) if key then player.storage[key] = value or -1 return true end end local function hasWhiteList(player, targetId) return getIndexByList(player, "whiteList", targetId) end local function addWhiteList(player, targetId) return setIndexByList(player, "whiteList", -1, targetId) end local function removeWhiteList(player, targetId) return setIndexByList(player, "whiteList", targetId) end local function hasBlackList(player, targetId) return getIndexByList(player, "blackList", targetId) end local function addWhiteList(player, targetId) return setIndexByList(player, "blackList", -1, targetId) end local function removeWhiteList(player, targetId) return setIndexByList(player, "blackList", targetId) end local function createChildren(player, target) local children = Game.createItem(sexSystem.childrenId, 1) if children then children:setCustomAttribute("fatherGuid", player:getGuid()) children:setCustomAttribute("motherGuid", target:getGuid()) children:setAttribute(ITEM_ATTRIBUTE_NAME, string.format("%s and %s's child", player:getName(), target:getName())) children:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "Use the child to claim your maintenance.") local returnValue = target:addItemEx(children) if returnValue ~= RETURNVALUE_NOERROR then target:sendCancelMessage(returnValue) children:moveTo(target:getPosition()) end end return true end local requests = {} local function resetRequest(playerId, targetId) requests[playerId] = nil if targetId then requests[targetId] = nil end end local talkAction = TalkAction(talkActionWords) function talkAction.onSay(player, words, param) local pos = player:getPosition() pos:getNextPosition(player:getDirection()) local tile = Tile(pos) if not tile then player:sendCancelMessage("There is nothing in front of you.") return false end local target = tile:getTopVisibleCreature(player) if not target then player:sendCancelMessage("There is no one in front of you.") return false end local targetId = target:getId() if hasBlackList(player, targetId) and not hasWhiteList(player, targetId) then player:sendCancelMessage("You have this player in your blacklist.") return false end local request = requests[player:getId()] if request then if type(request) == "table" then sexSystem.handleRequest(player, target, request) return false end player:sendCancelMessage("You already have a request.") return false end local targetRequest = requests[target:getId()] if targetRequest then player:sendCancelMessage("The player already has a pending request.") return false end requests[player:getId()] = target:getId() sexSystem.sendSexTypesWindow(player, target) return false end talkAction:register() function sexSystem.handleRequest(player, target, request) if player:getId() == request.playerId then player:sendCancelMessage("You already have a pending request.") return false end local target = Player(request.playerId) if not target then player:sendCancelMessage("The requesting player is not online.") return false elseif target:getId() ~= request.playerId then player:sendCancelMessage("The player you are looking at was not the one who requested the sex.") return false end return sexSystem.sendSexHandleRequestWindow(player, target, request) end function sexSystem.sendSexHandleRequestWindow(player, target, request) local modalWindow = ModalWindow{ title = "Sex System - Request", message = string.format("The player %s wants to have sex with you, do you accept?", target:getName()) } modalWindow:addChoice("No") modalWindow:addChoice("Yes") if not hasBlackList(player, request.playerId) then modalWindow:addChoice("Add to blacklist") end if not hasWhiteList(player, request.playerId) then modalWindow:addChoice("Add to whitelist") end modalWindow:addButton("Select", function (player, button, choice) local target = Player(request.playerId) if not target then player:sendCancelMessage("The requesting player is not online.") resetRequest(player:getId(), request.playerId) return false end if not choice or not table.contains({"Yes", "Add to whitelist"}, choice.text) then if choice.text == "Add to blacklist" then if not hasBlackList(player, request.playerId) then addBlackList(player, request.playerId) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have added %s to your blacklist.", target:getName())) end end player:sendCancelMessage("You have declined the request.") resetRequest(player:getId(), request.playerId) return false end if choice.text == "Add to whitelist" then if not hasWhiteList(player, request.playerId) then addWhiteList(player, request.playerId) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have added %s to your whitelist.", target:getName())) end end sexSystem.startSex(target, player, request) resetRequest(player:getId(), request.playerId) end) modalWindow:addButton("Close") modalWindow:setDefaultEnterButton("Select") modalWindow:setDefaultEscapeButton("Close") return modalWindow:sendToPlayer(player) end function sexSystem.startSex(player, target, request) local con = request.con if player:getTotalMoney() < con.price then resetRequest(request.playerId, request.targetId) return false end player:removeTotalMoney(con.price) player:getPosition():sendMagicEffect(CONST_ME_HEARTS) target:getPosition():sendMagicEffect(CONST_ME_HEARTS) player:sendTextMessage(MESSAGE_LOOT, string.format("You have had {33780|%s} {33952|%s} sex {3035|%s} with {33780|%s}.", request.intensity, request.type, request.pose, target:getName())) target:sendTextMessage(MESSAGE_LOOT, string.format("You have had {33780|%s} {33952|%s} sex {3035|%s} with {33780|%s}.", request.intensity, request.type, request.pose, player:getName())) local childrenGenerated = nil if math.random() > con.security then if math.random(1, 100) <= sexSystem.childrenChance then local playerSex = player:getSex() if playerSex ~= target:getSex() then if playerSex == PLAYERSEX_MALE then childrenGenerated = createChildren(player, target) else childrenGenerated = createChildren(target, player) end end end end if not childrenGenerated then local fluid = Game.createItem(2016, FLUID_MILK, player:getPosition()) if fluid then fluid:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("%s Fluids", player:getName())) fluid:decay(0) end local fluid = Game.createItem(2016, FLUID_MILK, target:getPosition()) if fluid then fluid:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("%s Fluids", target:getName())) fluid:decay(0) end end sexSystem.applyBoosts(player, request) sexSystem.applyBoosts(target, request) resetRequest(request.playerId, request.targetId) end function sexSystem.sendSexTypesWindow(player, target) local modalWindow = ModalWindow{ title = "Sex System - Type", message = string.format("Select the type of sex you want to have with %s", target:getName()) } local playerSex = player:getSex() local targetSex = target:getSex() for _, sexType in pairs(sexSystem.types) do repeat if sexType == "vaginal" and playerSex == PLAYERSEX_MALE and targetSex == PLAYERSEX_MALE then break end modalWindow:addChoice(string.format("%s sex", sexType)) until true end modalWindow:addButton("Accept", function (player, button, choice) local playerId = player:getId() if not choice or choice.text == "" then resetRequest(playerId) return false end local targetId = requests[playerId] if not targetId then resetRequest(playerId) return false end local target = Player(targetId) if not target then resetRequest(playerId) return false end sexSystem.sendSexIntensitiesWindow(player, target, sexSystem.types[choice.id]) return true end) modalWindow:addButton("Cancel", function (player, button, choice) resetRequest(player:getId()) end) modalWindow:setDefaultEnterButton("Accept") modalWindow:setDefaultEscapeButton("Cancel") return modalWindow:sendToPlayer(player) end function sexSystem.sendSexIntensitiesWindow(player, target, type) local modalWindow = ModalWindow{ title = "Sex System - Intensity", message = string.format("Select the intensity with which you want to have %s sex with %s.", type, target:getName()) } for _, intensity in pairs(sexSystem.intensities) do modalWindow:addChoice(intensity) end modalWindow:addButton("Accept", function (player, button, choice) local playerId = player:getId() if not choice or choice.text == "" then resetRequest(playerId) return false end local targetId = requests[playerId] if not targetId then resetRequest(playerId) return false end local target = Player(targetId) if not target then resetRequest(playerId) return false end sexSystem.sendSexPosesWindow(player, target, type, sexSystem.intensities[choice.id]) return true end) modalWindow:addButton("Cancel", function (player, button, choice) resetRequest(player:getId()) end) modalWindow:setDefaultEnterButton("Accept") modalWindow:setDefaultEscapeButton("Cancel") return modalWindow:sendToPlayer(player) end function sexSystem.sendSexPosesWindow(player, target, type, intensity) local modalWindow = ModalWindow{ title = "Sex System - Poses", message = string.format("Select the position with which you want to have %s %s sex with %s.", intensity, type, target:getName()) } local playerId = player:getId() local poses = sexPoses[player:getSex()] if not poses then resetRequest(playerId) return false end local poses = poses[type] if not poses then resetRequest(playerId) return false end for _, pose in pairs(poses) do modalWindow:addChoice(pose) end modalWindow:addButton("Accept", function (player, button, choice) local playerId = player:getId() if not choice or choice.text == "" then resetRequest(playerId) return false end local targetId = requests[playerId] if not targetId then resetRequest(playerId) return false end local target = Player(targetId) if not target then resetRequest(playerId) return false end sexSystem.sendSexCondonsWindow(player, target, type, intensity, poses[choice.id]) return true end) modalWindow:addButton("Cancel", function (player, button, choice) resetRequest(player:getId()) end) modalWindow:setDefaultEnterButton("Accept") modalWindow:setDefaultEscapeButton("Cancel") return modalWindow:sendToPlayer(player) end function sexSystem.sendSexCondonsWindow(player, target, type, intensity, pose) local modalWindow = ModalWindow{ title = "Sex System - Condons", message = "Select the condom you want to use:" } for _, con in pairs(sexCondons) do modalWindow:addChoice(string.format("%s (%d%%) - %d gold", con.type, con.security * 100, con.price)) end modalWindow:addButton("Accept", function (player, button, choice) local playerId = player:getId() if not choice or choice.text == "" then resetRequest(playerId) return false end local targetId = requests[playerId] if not targetId then resetRequest(playerId) return false end local target = Player(targetId) if not target then resetRequest(playerId) return false end local con = sexCondons[choice.id] if not con then resetRequest(playerId) return false end if player:getTotalMoney() < con.price then player:sendTextMessage(MESSAGE_INFO_DESCR, "You don't have enough money.") resetRequest(playerId) return false end sexSystem.createRequest(player, target, type, intensity, pose, con) return true end) modalWindow:addButton("Cancel", function (player, button, choice) resetRequest(player:getId()) end) modalWindow:setDefaultEnterButton("Accept") modalWindow:setDefaultEscapeButton("Cancel") return modalWindow:sendToPlayer(player) end function sexSystem.createRequest(player, target, type, intensity, pose, con) local request = { playerId = player:getId(), targetId = target:getId(), type = type, intensity = intensity, pose = pose, con = con } requests[player:getId()] = request requests[target:getId()] = request player:sendTextMessage(MESSAGE_LOOT, string.format("You have requested to have {33780|%s} {33952|%s} sex {3035|%s} with {33780|%s}.\nWait for it to respond to your request.", intensity, type, pose, target:getName())) target:sendTextMessage(MESSAGE_LOOT, string.format("{3038|%s} has asked you to have {33780|%s} {33952|%s} sex {3035|%s}.\nTo handle the request use the command {3035|%s}.", player:getName(), intensity, type, pose, talkActionWords)) return true end local action = Action() function action.onUse(player, item, fromPos, target, toPos, isHotkey) local fatherGuid = item:getCustomAttribute("fatherGuid") local motherGuid = item:getCustomAttribute("motherGuid") if not fatherGuid or not motherGuid then return false end local mother = Player(motherGuid) if not mother or motherGuid ~= player:getGuid() then player:sendTextMessage(MESSAGE_INFO_DESCR, "You are not the mother of this child.") return true end local father = Player(fatherGuid) if not father then player:sendTextMessage(MESSAGE_INFO_DESCR, "The father of this child is offline.") return true end local maintance = math.ceil(father:getTotalMoney() * (sexSystem.childrenMaintance / 100)) if player:getTotalMoney() < maintance then player:sendTextMessage(MESSAGE_INFO_DESCR, "The father of this child doesn't have enough money to pay the maintance.") return true end father:removeTotalMoney(maintance) player:setBankBalance(player:getBankBalance() + maintance) player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You have received %d gold from the father of this child.", maintance)) child:getPosition():sendMagicEffect(CONST_ME_GIFT_WRAPS) child:remove() return true end action:id(sexSystem.childrenId) action:register()