├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── CodingConvention.md ├── Contents └── mods │ └── CommunityAPI │ ├── media │ └── lua │ │ ├── client │ │ ├── CommunityAPI.lua │ │ ├── ItemTooltipAPI │ │ │ ├── ItemTooltipAPIClient.lua │ │ │ ├── Overrides │ │ │ │ └── ISToolTipInv.lua │ │ │ └── README.md │ │ ├── LightAPI │ │ │ ├── LightAPIClient.lua │ │ │ └── README.md │ │ ├── SpawnerAPI │ │ │ ├── README.md │ │ │ └── SpawnerAPIClient.lua │ │ └── WorldSoundAPI │ │ │ ├── README.md │ │ │ └── WorldSoundAPIClient.lua │ │ ├── server │ │ ├── CommunityAPI.lua │ │ ├── DistributionAPI │ │ │ ├── DistributionAPIServer.lua │ │ │ └── README.md │ │ └── SpawnerAPI │ │ │ ├── README.md │ │ │ └── SpawnerAPIServer.lua │ │ └── shared │ │ ├── BodyLocationsAPI │ │ ├── BodyLocationsAPIShared.lua │ │ └── README.md │ │ ├── CommunityAPI │ │ ├── ColorUtils.lua │ │ ├── InventoryUtils.lua │ │ ├── IsoUtils.lua │ │ ├── MathUtils.lua │ │ ├── README.md │ │ ├── StringUtils.lua │ │ └── TableUtils.lua │ │ └── CommunityAPIShared.lua │ ├── mod.info │ └── poster.png ├── Images ├── banner.png └── poster.png ├── LICENSE ├── README.md ├── TemplateAPI.lua.md ├── preview.png └── workshop.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: "Upload to Workshop" 2 | 3 | on: 4 | # Trigger the workflow on push or pull request, 5 | # but only for the main branch 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | upload: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: AnarkisGaming/workshop@v1 16 | with: 17 | appID: 108600 18 | publishedFileID: 2650538172 19 | #changelog: 'log of changes' 20 | env: 21 | STEAM_ACCOUNT_NAME: ${{ secrets.STEAM_USERNAME }} 22 | STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }} 23 | 24 | # Runs a set of commands using the runners shell 25 | - name: Run a multi-line script 26 | run: | 27 | echo Add other actions to build, 28 | echo test, and deploy your project. 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | .gradle/ 3 | .idea/ 4 | build/ 5 | gradle/ 6 | lib/ 7 | logs/ 8 | src/ 9 | local.properties 10 | version.properties 11 | gradlew 12 | gradlew.bat 13 | Gemfile 14 | *.blend 15 | *.blend1 16 | *.sqlite -------------------------------------------------------------------------------- /CodingConvention.md: -------------------------------------------------------------------------------- 1 | # Coding Convention 2 | **This is the convention that we agreed to use on this project.** 3 | *This is not yet fixed, it may change if we see fit until the first release.* 4 | 5 | 6 | ### GLOBAL 7 | ```lua 8 | GLOBAL_VAR = "" -- UpperCase 9 | function GlobalFunc() end -- PascalCase 10 | ``` 11 | 12 | ### LOCAL 13 | ```lua 14 | local someVariable = "" -- camelCase 15 | local function someFunction() end -- camelCase 16 | ``` 17 | 18 | ### OBJECT 19 | ```lua 20 | local MyObject = {} -- PascalCase 21 | function MyObject.StaticMethod() end -- PascalCase 22 | function MyObject:instanceMethod() end -- camelCase 23 | ``` 24 | 25 | ### PARAMETERS 26 | ```lua 27 | local function func(requiredParam) end -- camelCase 28 | local function func(_optionalParam) end -- camelCase prefixed with underscore 29 | ``` 30 | 31 | ### MULTI PARAMETERS 32 | *Separate parameters with a space after the comma.* 33 | ```lua 34 | -- Wrong 35 | function(param1,param2) 36 | -- Good 37 | function(param1, param2) 38 | ``` 39 | 40 | ### ANNOTATIONS 41 | ```lua 42 | ---@class MyClass Description of the class 43 | local MyClass = {} 44 | 45 | --- Short description of the usage of this method 46 | ---@param param1 string Description of this parameter 47 | ---@return string 48 | function MyClass:setName(param1) 49 | return param1 50 | end 51 | ``` 52 | *View [Emmylua docs](https://emmylua.github.io/) for more information about annotations.* 53 | 54 | 55 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/CommunityAPI.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPIShared") 2 | 3 | CommunityAPI.Client = { 4 | ItemTooltip = require("ItemTooltipAPI/ItemTooltipAPIClient"), 5 | Light = require("LightAPI/LightAPIClient"), 6 | Spawner = require("SpawnerAPI/SpawnerAPIClient"), 7 | WorldSound = require("WorldSoundAPI/WorldSoundAPIClient"), 8 | } 9 | 10 | ----------------------------------------------------------------------------------- 11 | 12 | print("Loading CommunityAPI [Client] =================================================") 13 | for k, v in pairs(CommunityAPI.Client) do 14 | print("CommunityAPI.Client."..k, v) 15 | end -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/ItemTooltipAPI/ItemTooltipAPIClient.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPI") 2 | require("ISBaseObject") 3 | 4 | --------------------------------------------------------------------------------- 5 | 6 | ---@class InventoryTooltipField 7 | local InventoryTooltipField = ISBaseObject:derive("InventoryTooltipField") 8 | 9 | ---@param item InventoryItem 10 | function InventoryTooltipField:getValue(item) 11 | local valueType = type(self.getValueFunc) 12 | if valueType == "function" then 13 | self.getValueFunc(self.result, item) 14 | elseif valueType == "string" or valueType == "number" or valueType == "boolean" then 15 | self.result.value = self.getValueFunc 16 | end 17 | end 18 | 19 | ---@param fieldType string field, label, progress, spacer, extra 20 | ---@param name string 21 | ---@param param string|number|boolean|function 22 | function InventoryTooltipField:new(fieldType, name, getValueFunc, labelColor) 23 | local o = ISBaseObject:new() 24 | setmetatable(o, self) 25 | self.__index = self 26 | o.fieldType = fieldType 27 | o.name = name 28 | o.result = { 29 | value = nil, 30 | color = nil, 31 | labelColor = nil, 32 | } 33 | o.getValueFunc = getValueFunc 34 | o.result.labelColor = CommunityAPI.Utils.Color.GetColorOrDefault(labelColor, { r=1, g=1, b=0.8, a=1 }) 35 | 36 | return o 37 | end 38 | 39 | --------------------------------------------------------------------------------- 40 | 41 | ---@class InventoryTooltipInstance 42 | local InventoryTooltipInstance = ISBaseObject:derive("InventoryTooltipInstance") 43 | 44 | --- Add a text field 45 | ---@param name string 46 | ---@param getValueFunc string|number|boolean|function 47 | ---@return InventoryTooltipField 48 | function InventoryTooltipInstance:addField(name, getValueFunc, labelColor) 49 | self.fields[name] = InventoryTooltipField:new("field", name, getValueFunc, labelColor) 50 | return self.fields[name] 51 | end 52 | 53 | --- Add a label 54 | ---@param getValueFunc string|function 55 | ---@return InventoryTooltipField 56 | function InventoryTooltipInstance:addLabel(getValueFunc, labelColor) 57 | local name = "label_" .. self:getFieldCount() 58 | self.fields[name] = InventoryTooltipField:new("label", name, getValueFunc, labelColor) 59 | return self.fields[name] 60 | end 61 | 62 | --- Add a progress bar 63 | ---@param name string 64 | ---@param getValueFunc number|function 65 | ---@return InventoryTooltipField 66 | function InventoryTooltipInstance:addProgress(name, getValueFunc, labelColor) 67 | self.fields[name] = InventoryTooltipField:new("progress", name, getValueFunc, labelColor) 68 | return self.fields[name] 69 | end 70 | 71 | --- Add a extra item icons 72 | ---@param name string 73 | ---@param getValueFunc number|function 74 | ---@return InventoryTooltipField 75 | function InventoryTooltipInstance:addExtraItems(name, getValueFunc, labelColor) 76 | self.fields[name] = InventoryTooltipField:new("extra", name, getValueFunc, labelColor) 77 | return self.fields[name] 78 | end 79 | 80 | --- Add a spacer 81 | ---@return InventoryTooltipField 82 | function InventoryTooltipInstance:addSpacer() 83 | local name = "spacer_" .. self:getFieldCount() 84 | self.fields[name] = InventoryTooltipField:new("spacer", name) 85 | return self.fields[name] 86 | end 87 | 88 | --- Get the total amount of field added to this tooltip 89 | ---@return number 90 | function InventoryTooltipInstance:getFieldCount() 91 | local count = 0 92 | for _ in pairs(self.fields) do count = count + 1 end 93 | return count 94 | end 95 | 96 | ---@param itemFullType string 97 | ---@return InventoryTooltipInstance 98 | function InventoryTooltipInstance:new(itemFullType) 99 | local o = ISBaseObject:new() 100 | setmetatable(o, self) 101 | 102 | self.__index = self 103 | o.itemFullType = itemFullType 104 | o.fields = {} 105 | return o 106 | end 107 | 108 | --------------------------------------------------------------------------------- 109 | 110 | ---@class ItemTooltipAPI 111 | local ItemTooltipAPI = {} 112 | local Tooltips = {} 113 | 114 | ---@return table 115 | function ItemTooltipAPI.GetTooltip(itemFullType) 116 | return Tooltips[itemFullType] 117 | end 118 | 119 | --- Create a new Tooltip for a specific Item 120 | ---@param itemFullType string Item to create the tooltip for e.g: "Base.Axe" 121 | ---@return InventoryTooltipInstance 122 | function ItemTooltipAPI.CreateToolTip(itemFullType) 123 | local newTooltip = InventoryTooltipInstance:new(itemFullType) 124 | Tooltips[itemFullType] = newTooltip 125 | return newTooltip 126 | end 127 | 128 | return ItemTooltipAPI 129 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/ItemTooltipAPI/Overrides/ISToolTipInv.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPI") 2 | require("ISUI/ISToolTipInv") 3 | 4 | local ItemTooltipAPI = CommunityAPI.Client.ItemTooltip 5 | local StringUtils = CommunityAPI.Utils.String 6 | local ColorUtils = CommunityAPI.Utils.Color 7 | 8 | ---@param tooltip ObjectTooltip 9 | ---@param item InventoryItem 10 | local function customDoTooltip(tooltip, fields, item) 11 | local font = tooltip:getFont() 12 | local lineSpacing = tooltip:getLineSpacing() 13 | local y = 5 14 | local itemName = item:getName() 15 | 16 | tooltip:render() 17 | tooltip:DrawText(font, itemName, 5.0, y, 1.0, 1.0, 0.8, 1.0); 18 | tooltip:adjustWidth(5, itemName) 19 | 20 | local height = y + lineSpacing + 5 21 | 22 | local extraX 23 | local extraY 24 | local inventoryItem 25 | 26 | --region Extra 27 | 28 | local extraItems = item:getExtraItems() 29 | if extraItems ~= nil then 30 | tooltip:DrawText(font, getText("Tooltip_item_Contains"), 5.0, height, 1.0, 1.0, 0.8, 1.0) 31 | extraX = 5 + TextManager.instance:MeasureStringX(font, getText("Tooltip_item_Contains")) + 4 32 | extraY = (lineSpacing - 10) / 2 33 | 34 | for i=0, extraItems:size()-1 do 35 | local extraItem = extraItems:get(i) 36 | inventoryItem = InventoryItemFactory.CreateItem(extraItem) 37 | tooltip:DrawTextureScaled(inventoryItem:getTex(), extraX, height + extraY, 10.0, 10.0, 1.0) 38 | extraX = extraX + 11 39 | end 40 | 41 | height = height + lineSpacing + 5 42 | end 43 | 44 | --endregion Extra 45 | 46 | --region Spices 47 | 48 | ---@type Food 49 | local food = item 50 | if instanceof(food, "Food") then 51 | local spices = food:getSpices() 52 | if spices ~= nil then 53 | tooltip:DrawText(font, getText("Tooltip_item_Spices"), 5.0, height, 1.0, 1.0, 0.8, 1.0) 54 | extraX = 5 + TextManager.instance:MeasureStringX(font, getText("Tooltip_item_Spices")) + 4 55 | extraY = (lineSpacing - 10) / 2 56 | 57 | for i=0, spices:size()-1 do 58 | local spice = spices:get(i) 59 | inventoryItem = InventoryItemFactory.CreateItem(spice) 60 | tooltip:DrawTextureScaled(inventoryItem:getTex(), extraX, height + extraY, 10.0, 10.0, 1.0) 61 | extraX = extraX + 11 62 | end 63 | 64 | height = height + lineSpacing + 5 65 | end 66 | end 67 | 68 | --endregion Spices 69 | 70 | --region CustomExtra 71 | 72 | local customExtras = {} 73 | for _, field in pairs(fields) do 74 | if field.fieldType == "extra" then 75 | local customExtra = { 76 | labelText = field.name, 77 | labelColor = field.result.labelColor, 78 | items = field.result.value, 79 | } 80 | if type(field.result.value) == "string" then 81 | customExtra.items = {field.result.value} 82 | end 83 | table.insert(customExtras, customExtra) 84 | end 85 | end 86 | 87 | local customExtraMaxWidth = 0 88 | if #customExtras > 0 then 89 | for i=1, #customExtras do 90 | local customExtra = customExtras[i] 91 | tooltip:DrawText(font, customExtra.labelText .. ":", 5.0, height, customExtra.labelColor.r, customExtra.labelColor.g, customExtra.labelColor.b, customExtra.labelColor.a) 92 | extraX = 5 + TextManager.instance:MeasureStringX(font, customExtra.labelText) + 6 93 | extraY = (lineSpacing - 10) / 2 94 | 95 | for i=1, #customExtra.items do 96 | local extra = customExtra.items[i] 97 | inventoryItem = InventoryItemFactory.CreateItem(extra) 98 | tooltip:DrawTextureScaled(inventoryItem:getTex(), extraX, height + extraY, 10.0, 10.0, 1.0) 99 | extraX = extraX + 11 100 | customExtraMaxWidth = math.max(customExtraMaxWidth, extraX) 101 | end 102 | 103 | height = height + lineSpacing + 5 104 | end 105 | customExtraMaxWidth = customExtraMaxWidth + 10 106 | end 107 | 108 | tooltip:setWidth(customExtraMaxWidth) 109 | 110 | --endregion 111 | 112 | --region Layout 113 | 114 | ---@type ObjectTooltip.Layout 115 | local layout = tooltip:beginLayout() 116 | layout:setMinLabelWidth(80) 117 | 118 | -- Weight 119 | local weightItem = layout:addItem(); 120 | weightItem:setLabel(getText("Tooltip_item_Weight")..":", 1.0, 1.0, 0.8, 1.0); 121 | local weight = 0 122 | local cleanString = "" 123 | if not instanceof(item, "HandWeapon") and not instanceof(item, "Clothing") and not instanceof(item, "DrainableComboItem") then 124 | weight = item:getUnequippedWeight() 125 | if weight > 0.0 and weight < 0.01 then 126 | weight = 0.01 127 | end 128 | weightItem:setValueRightNoPlus(weight) 129 | elseif item:isEquipped() then 130 | cleanString = StringUtils.NumberToDecimalString(item:getEquippedWeight(), 2) 131 | weightItem:setValue(cleanString .. " (" .. ItemTooltipAPI.GetFloatString(item:getUnequippedWeight()) .. " " .. getText("Tooltip_item_Unequipped") .. ")", 1.0, 1.0, 1.0, 1.0) 132 | elseif item:getAttachedSlot() > -1 then 133 | cleanString = StringUtils.NumberToDecimalString(item:getHotbarEquippedWeight(), 2) 134 | weightItem:setValue(cleanString .. " (" .. ItemTooltipAPI.GetFloatString(item:getUnequippedWeight()) .. " " .. getText("Tooltip_item_Unequipped") .. ")", 1.0, 1.0, 1.0, 1.0) 135 | else 136 | cleanString = StringUtils.NumberToDecimalString(item:getUnequippedWeight(), 2) 137 | weightItem:setValue(cleanString .. " (" .. ItemTooltipAPI.GetFloatString(item:getUnequippedWeight()) .. " " .. getText("Tooltip_item_Equipped") .. ")", 1.0, 1.0, 1.0, 1.0) 138 | end 139 | 140 | -- Weight of stack 141 | local weightOfStack = tooltip:getWeightOfStack(); 142 | if weightOfStack > 0.0 then 143 | local layoutItem = layout:addItem(); 144 | layoutItem:setLabel(getText("Tooltip_item_StackWeight")..":", 1.0, 1.0, 0.8, 1.0); 145 | if weightOfStack > 0.0 and weightOfStack < 0.01 then 146 | weightOfStack = 0.01; 147 | end 148 | layoutItem:setValueRightNoPlus(weightOfStack); 149 | end 150 | 151 | -- Custom Fields 152 | for _, field in pairs(fields) do 153 | if field.fieldType ~= "extra" and field.result then 154 | ---@type ObjectTooltip.LayoutItem 155 | local layoutItem = layout:addItem() 156 | 157 | local color 158 | local labelColor 159 | if field.fieldType == "spacer" then 160 | layoutItem:setLabel("spacer", 0, 0, 0, 0) 161 | 162 | elseif field.fieldType == "label" then 163 | labelColor = ColorUtils.GetColorOrDefault(field.result.labelColor, { r=1, g=1, b=1, a=1 }) 164 | layoutItem:setLabel(field.result.value, labelColor.r, labelColor.g, labelColor.b, labelColor.a) 165 | 166 | elseif field.fieldType == "field" then 167 | labelColor = ColorUtils.GetColorOrDefault(field.result.labelColor, { r=1, g=1, b=0.8, a=1 }) 168 | color = ColorUtils.GetColorOrDefault(field.result.color, { r=1, g=1, b=1, a=1 }) 169 | layoutItem:setLabel(field.name..":", labelColor.r, labelColor.g, labelColor.b, labelColor.a) 170 | layoutItem:setValue(field.result.value, color.r, color.g, color.b, color.a) 171 | 172 | elseif field.fieldType == "progress" and type(field.result.value) == "number" then 173 | labelColor = ColorUtils.GetColorOrDefault(field.result.labelColor, { r=1, g=1, b=0.8, a=1 }) 174 | color = ColorUtils.GetColorOrDefault(field.result.color, { r=0, g=0.6, b=0, a=0.7 }) 175 | layoutItem:setLabel(field.name..":", labelColor.r, labelColor.g, labelColor.b, labelColor.a) 176 | layoutItem:setProgress(field.result.value, color.r, color.g, color.b, color.a) 177 | end 178 | end 179 | end 180 | 181 | -- Item Tooltip 182 | if item:getTooltip() ~= nil then 183 | local layoutItem = layout:addItem(); 184 | layoutItem:setLabel(getText(item:getTooltip()), 1.0, 1.0, 0.8, 1.0); 185 | end 186 | 187 | --endregion Layout 188 | 189 | height = layout:render(5, height, tooltip) 190 | tooltip:endLayout(layout) 191 | 192 | height = height + 5 193 | tooltip:setHeight(height) 194 | 195 | if tooltip:getWidth() < 150.0 then 196 | tooltip:setWidth(150.0) 197 | end 198 | end 199 | 200 | --region ISToolTipInv:render 201 | 202 | local original_ISToolTipInv_render = ISToolTipInv.render 203 | function ISToolTipInv:render() 204 | 205 | local inventoryTooltip = ItemTooltipAPI.GetTooltip(self.item:getFullType()) 206 | 207 | if inventoryTooltip then 208 | if not ISContextMenu.instance or not ISContextMenu.instance.visibleCheck then 209 | 210 | -- Get fields with values 211 | for key in pairs(inventoryTooltip.fields) do 212 | inventoryTooltip.fields[key]:getValue(self.item) 213 | end 214 | 215 | local mx = getMouseX() + 24; 216 | local my = getMouseY() + 24; 217 | if not self.followMouse then 218 | mx = self:getX() 219 | my = self:getY() 220 | if self.anchorBottomLeft then 221 | mx = self.anchorBottomLeft.x 222 | my = self.anchorBottomLeft.y 223 | end 224 | end 225 | 226 | self.tooltip:setX(mx+11); 227 | self.tooltip:setY(my); 228 | 229 | self.tooltip:setWidth(50) 230 | self.tooltip:setMeasureOnly(true) 231 | customDoTooltip(self.tooltip, inventoryTooltip.fields, self.item) 232 | self.tooltip:setMeasureOnly(false); 233 | 234 | local myCore = getCore(); 235 | local maxX = myCore:getScreenWidth(); 236 | local maxY = myCore:getScreenHeight(); 237 | 238 | local tw = self.tooltip:getWidth(); 239 | local th = self.tooltip:getHeight(); 240 | 241 | self.tooltip:setX(math.max(0, math.min(mx + 11, maxX - tw - 1))); 242 | if not self.followMouse and self.anchorBottomLeft then 243 | self.tooltip:setY(math.max(0, math.min(my - th, maxY - th - 1))); 244 | else 245 | self.tooltip:setY(math.max(0, math.min(my, maxY - th - 1))); 246 | end 247 | 248 | self:setX(self.tooltip:getX() - 11); 249 | self:setY(self.tooltip:getY()); 250 | self:setWidth(tw + 11); 251 | self:setHeight(th); 252 | 253 | if self.followMouse then 254 | self:adjustPositionToAvoidOverlap({ x = mx - 24 * 2, y = my - 24 * 2, width = 24 * 2, height = 24 * 2 }) 255 | end 256 | 257 | self:drawRect(0, 0, self.width, self.height, self.backgroundColor.a, self.backgroundColor.r, self.backgroundColor.g, self.backgroundColor.b); 258 | self:drawRectBorder(0, 0, self.width, self.height, self.borderColor.a, self.borderColor.r, self.borderColor.g, self.borderColor.b); 259 | 260 | customDoTooltip(self.tooltip, inventoryTooltip.fields, self.item) 261 | 262 | end 263 | else 264 | original_ISToolTipInv_render(self) 265 | end 266 | 267 | end 268 | 269 | --endregion ISToolTipInv:render 270 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/ItemTooltipAPI/README.md: -------------------------------------------------------------------------------- 1 | # ItemTooltipAPI 2 | **Developer:** Konijima 3 | **Contributors:** - 4 | 5 | ## Description 6 | Make complex custom item tooltip for your new items. 7 | Can be used to override existing vanilla item completely. 8 | 9 | ## How to use 10 | 11 | 1) Create a directory `ItemTooltips` in your mod directory `media/lua/client`. 12 | 2) Create a file per item named `_.lua` inside `ItemTooltips` directory. 13 | 3) Use `require("ItemTooltipAPI/Main")` in the scripts that use it. 14 | 4) Adding `require=CommunityAPI` to your `mod.info` to make sure the API is enabled as well. 15 | 16 | Tooltip can be reloaded via your file `ItemTooltips/_.lua` 17 | 18 | **Methods** 19 | ## ItemTooltipAPI Methods 20 | ```lua 21 | ItemTooltipAPI.GetRGB(numberCurrent, numberMax) -- Get a color from Red to Green 22 | ``` 23 | ```lua 24 | ItemTooltipAPI.GetReversedRGB(numberCurrent, numberMax) -- Get a color from Green to Red 25 | ``` 26 | ```lua 27 | ItemTooltipAPI.GetFloatString(number) -- Return a decimal number as a string 28 | ``` 29 | ```lua 30 | local newTooltip = ItemTooltipAPI.CreateToolTip(itemFullType) -- Returns a tooltip instance 31 | ``` 32 | ## Tooltip Instance Methods 33 | ### addField 34 | ```lua 35 | newTooltip:addField(labelText, getValueFunction) -- Dynamic field value 36 | newTooltip:addField(labelText, valueText, labelColor) -- Fixed field value 37 | ``` 38 | ### addProgress 39 | ```lua 40 | newTooltip:addProgress(labelText, getValueFunction) -- Dynamic progress bar value 41 | newTooltip:addProgress(labelText, numberValue) -- Fixed progress bar value 42 | ``` 43 | ### addLabel 44 | ```lua 45 | newTooltip:addLabel(labelText) -- Fixed label text 46 | newTooltip:addLabel(getValueFunction) -- Dynamic label text 47 | newTooltip:addLabel(labelText, labelColor) -- Fixed label text with fixed label color 48 | ``` 49 | ### addSpacer 50 | ```lua 51 | newTooltip:addSpacer() -- Add some space in between lines 52 | ``` 53 | 54 | ### Dynamic value parameter 'getValueFunction' 55 | Set the result of this field with this function that your define. 56 | ```lua 57 | local function myGetValueFunction(result, item) 58 | result.value = 1 -- Set the value 59 | result.color = { r=1.0, g=1.0, b=1.0, a=1.0 } -- Set the value color 60 | result.labelColor = { r=1.0, g=1.0, b=1.0, a=1.0 } -- Set the label color 61 | item:getModData() -- Use the InventoryItem to check data 62 | if instanceof(item, "HandWeapon") then end -- Verify if its the right item type 63 | end 64 | newTooltip:addField("New Field", myGetValueFunction) 65 | ``` 66 | 67 | ### Color Format 68 | ```lua 69 | local color = { r=1.0, g=1.0, b=1.0, a=1.0 } 70 | ``` 71 | 72 | ## Example 73 | ```lua 74 | require("CommunityAPI") 75 | 76 | local ItemTooltipAPI = CommunityAPI.Client.ItemTooltip 77 | 78 | local function typeField(result, item) 79 | result.value = item:getType() 80 | end 81 | 82 | local function dynamicField(result, item) 83 | local usedDelta = item:getUsedDelta() 84 | result.value = ItemTooltipAPI.GetFloatString(usedDelta) 85 | result.color = ItemTooltipAPI.GetRGB(usedDelta, 1) 86 | end 87 | 88 | local function conditionProgress(result, item) 89 | result.value = 0.33 90 | result.color = ItemTooltipAPI.GetRGB(result.value, 1) 91 | end 92 | 93 | local function capacityProgress(result, item) 94 | result.value = 0.85 95 | result.color = ItemTooltipAPI.GetReversedRGB(result.value, 1) 96 | end 97 | 98 | local function customColorProgress(result, item) 99 | result.value = 0.75 100 | result.color = { r=0, g=0, b=0.6, a=0.8 } 101 | end 102 | 103 | local function dynamicLabel(result, item) 104 | result.value = "This is a very long dynamic label that can change\ndepending of the items state or what ever you need!" 105 | result.labelColor = { r=1, g=0, b=0.5, a=1 } 106 | end 107 | 108 | -- Create the new Tooltip 109 | 110 | local ItemTooltip = ItemTooltipAPI.CreateToolTip("Base.Axe") 111 | 112 | -- Add the field, progress, label or spacer 113 | 114 | ItemTooltip:addField("Type field", typeField) 115 | ItemTooltip:addField("Dynamic field", dynamicField) 116 | ItemTooltip:addField("Fixed Text field", "Some text", { r=0, g=1, b=0, a=1 }) -- Fixed label with custom label color 117 | ItemTooltip:addProgress("Progress", conditionProgress) 118 | ItemTooltip:addProgress("Reversed Progress", capacityProgress) 119 | ItemTooltip:addProgress("Fixed Progress", 0.5) 120 | ItemTooltip:addProgress("Custom Color Progress", customColorProgress) 121 | ItemTooltip:addSpacer() 122 | ItemTooltip:addLabel("This is some label between spacers!", { r=1, g=0, b=0, a=1 }) -- Fixed label with custom color 123 | ItemTooltip:addSpacer() 124 | ItemTooltip:addLabel(dynamicLabel) -- Dynamic label 125 | ItemTooltip:addSpacer() 126 | ``` 127 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/LightAPI/LightAPIClient.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPI") 2 | require("ISBaseObject") 3 | 4 | local ColorUtils = CommunityAPI.Utils.Color 5 | local StringUtils = CommunityAPI.Utils.String 6 | 7 | local DEBUG = getCore():getDebug() 8 | 9 | ---@class LightObject 10 | local LightObject = ISBaseObject:derive("LightObject") 11 | 12 | function LightObject:update() 13 | local cell = getCell() 14 | if cell then 15 | local square = cell:getGridSquare(self.position.x, self.position.y, self.position.z) 16 | if square then 17 | if self.lightSource == nil then 18 | self.lightSource = IsoLightSource.new(self.position.x, self.position.y, self.position.z, 0.0, 0.0, 1.0, self.radius) 19 | cell:addLamppost(self.lightSource) 20 | IsoGridSquare.RecalcLightTime = -1 21 | if DEBUG then print("Light source ['"..self.name.."'] created at x:"..self.position.x.." y:"..self.position.y.." z:"..self.position.z) end 22 | end 23 | self.lightSource:setRadius(self.radius) 24 | self.lightSource:setR(self.color.r) 25 | self.lightSource:setG(self.color.g) 26 | self.lightSource:setB(self.color.b) 27 | else 28 | self:destroy() 29 | end 30 | end 31 | end 32 | 33 | function LightObject:destroy() 34 | if self.lightSource ~= nil then 35 | self.lightSource:setActive(false) 36 | getCell():removeLamppost(self.lightSource) 37 | self.lightSource = nil 38 | if DEBUG then print("Light source ['"..self.name.."'] destroyed at x:"..self.position.x.." y:"..self.position.y.." z:"..self.position.z) end 39 | end 40 | end 41 | 42 | function LightObject:setRadius(radius) 43 | if type(radius) == "number" and radius > 0 then 44 | self.radius = radius 45 | self:update() 46 | end 47 | end 48 | 49 | function LightObject:setColor(color) 50 | if type(color) == "table" then 51 | self.color = ColorUtils.GetColorOrDefault(color, { r=1, g=1, b=1, a=1 }) 52 | self:update() 53 | end 54 | end 55 | 56 | function LightObject:new(name, x ,y ,z, radius, color) 57 | local o = ISBaseObject:new() 58 | setmetatable(o, self) 59 | self.__index = self 60 | 61 | o.lightSource = nil 62 | 63 | o.name = name 64 | o.position = { x=x, y=y, z=z } 65 | o.radius = 1 66 | o.color = { r=1, g=1, b=1 } 67 | 68 | o:setRadius(radius) 69 | o:setColor(color) 70 | 71 | return o 72 | end 73 | 74 | ----------------------------------------------------------------------- 75 | 76 | ---@class LightAPI 77 | local LightAPI = {} 78 | 79 | ---@type table 80 | local Lights = {} 81 | 82 | ---@param name string 83 | ---@param x number 84 | ---@param y number 85 | ---@param z number 86 | ---@param newColor table 87 | function LightAPI.SetLightColorAt(name, x, y, z, newColor) 88 | local id = StringUtils.PositionToId(x, y, z) 89 | if Lights[id] and Lights[id][name] then 90 | Lights[id][name]:setColor(newColor) 91 | end 92 | end 93 | 94 | ---@param name string 95 | ---@param x number 96 | ---@param y number 97 | ---@param z number 98 | ---@param newRadius number 99 | function LightAPI.SetLightRadiusAt(name, x, y, z, newRadius) 100 | local id = StringUtils.PositionToId(x, y, z) 101 | if Lights[id] and Lights[id][name] then 102 | Lights[id][name]:setRadius(newRadius) 103 | end 104 | end 105 | 106 | ---@param name string 107 | ---@param x number 108 | ---@param y number 109 | ---@param z number 110 | ---@param radius number 111 | ---@param color table 112 | function LightAPI.AddLightAt(name, x, y, z, radius, color) 113 | local id = StringUtils.PositionToId(x, y, z) 114 | if not Lights[id] then 115 | Lights[id] = {} 116 | end 117 | if Lights[id] and Lights[id][name] then 118 | Lights[id][name]:destroy() 119 | Lights[id][name] = nil 120 | end 121 | 122 | Lights[id][name] = LightObject:new(name, x ,y, z, radius, color) 123 | if DEBUG then print("Light ['"..name.."'] added at x:"..x.." y:"..y.." z:"..z) end 124 | end 125 | 126 | ---@param name string 127 | ---@param x number 128 | ---@param y number 129 | ---@param z number 130 | function LightAPI.RemoveLightAt(name, x, y, z) 131 | local id = StringUtils.PositionToId(x, y, z) 132 | if Lights[id] and Lights[id][name] then 133 | Lights[id][name]:destroy() 134 | Lights[id][name] = nil 135 | if DEBUG then print("Light ['"..name.."'] removed at x:"..x.." y:"..y.." z:"..z) end 136 | end 137 | end 138 | 139 | ---@param square IsoGridSquare 140 | local function onLoadGridsquare(square) 141 | local id = StringUtils.SquareToId(square) 142 | if Lights[id] then 143 | ---@param v LightObject 144 | for k, v in pairs(Lights[id]) do 145 | v:destroy() 146 | v:update() 147 | end 148 | end 149 | end 150 | Events.LoadGridsquare.Add(onLoadGridsquare) 151 | 152 | return LightAPI -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/LightAPI/README.md: -------------------------------------------------------------------------------- 1 | # LightAPI 2 | **Developer:** Konijima 3 | **Contributors:** - 4 | 5 | ## Description 6 | Easily add Lights at specific position categorized by unique name. 7 | The API take care of disposing and recreating the light source if the square is unloaded and reloaded later. 8 | 9 | ## Methods 10 | 11 | ```lua 12 | AddLightAt(name, x, y, z, radius, color) 13 | ``` 14 | 15 | ```lua 16 | SetLightColorAt(name, x, y, z, newColor) 17 | ``` 18 | 19 | ```lua 20 | SetLightRadiusAt(name, x, y, z, newRadius) 21 | ``` 22 | 23 | ```lua 24 | RemoveLightAt(name, x, y, z) 25 | ``` 26 | 27 | ## Example 28 | ```lua 29 | require("CommunityAPI") 30 | 31 | local LightAPI = CommunityAPI.Client.Light 32 | 33 | LightAPI.AddLightAt("computer_screen", position.x, position.y, position.z, 2, { r=0.20, g=0.30, b=0.20 }) 34 | LightAPI.SetLightColorAt("computer_screen", position.x, position.y, position.z, { r=0.20, g=0.30, b=0.20 }) 35 | LightAPI.SetLightRadiusAt("computer_screen", position.x, position.y, position.z, 2) 36 | LightAPI.RemoveLightAt("computer_screen", position.x, position.y, position.z) 37 | ``` 38 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/SpawnerAPI/README.md: -------------------------------------------------------------------------------- 1 | # SpawnerAPI [Client] 2 | **Developer:** Chuck 3 | **Contributors:** Konijima, Shurutsue 4 | 5 | ## Description 6 | Allows for pending the spawns of vehicles, items, zombies (with added functions supported) 7 | in order to spawn things anywhere in the world. Upon loading the cell in question the item becomes spawned in. 8 | 9 | ## How to use: 10 | **Parameters:** 11 | 12 | - itemType/vehicleType/outfitID `string` String matching the item/vehicle type (module optional); outfit ID as per the GUID table. 13 | - x `number`, y `number`, z `number` Numbers matches the x, y, z you want the object spawned on. 14 | - extraFunctions `table` Functions listed in a table to be ran against all spawned objects. Note: Zombies are spawned into an array, any added functions should take this into account. 15 | - extraParam `any` An additional parameter to apply. Note: For Zombie spawns this acts as `FemaleChance`. 16 | - processSquare `function` Function to run against the found square. 17 | 18 | **Returns:** `InventoryItem` 19 | 20 | 21 | ## Methods 22 | ```lua 23 | SpawnItem(itemType, x, y, z, extraFunctions, extraParam, processSquare) 24 | ``` 25 | ```lua 26 | SpawnVehicle(vehicleType, x, y, z, extraFunctions, extraParam, processSquare) 27 | ``` 28 | ```lua 29 | SpawnZombie(outfitID, x, y, z, extraFunctions, femaleChance, processSquare) 30 | ``` 31 | 32 | ## Example 33 | 34 | ```lua 35 | require("CommunityAPI") 36 | 37 | local SpawnerAPI = CommunityAPI.Client.Spawner 38 | 39 | --Auto Ages InventoryItems. 40 | ---@param item InventoryItem 41 | function ageInventoryItem(item) 42 | if item then 43 | item:setAutoAge() 44 | end 45 | end 46 | 47 | 48 | --Checks and returns square if outside. 49 | ---@param square IsoGridSquare 50 | ---@return IsoGridSquare 51 | function checkIfOutside(square) 52 | if not square then 53 | return 54 | end 55 | if square:isOutside() then 56 | return square 57 | end 58 | end 59 | 60 | 61 | --Example of SpawnItem 62 | ---@param player IsoPlayer | IsoGameCharacter | IsoMovingObject | IsoObject 63 | function dropTrash(player) 64 | 65 | local X, Y, Z = player:getX(), player:getY(), player:getZ() 66 | local trashItems = { "MayonnaiseEmpty", "SmashedBottle", "Pop3Empty", "PopEmpty", "Pop2Empty", "WhiskeyEmpty", "BeerCanEmpty", "BeerEmpty" } 67 | local iterations = 10 68 | 69 | for i = 1, iterations do 70 | 71 | X = X + ZombRand(-2, 3) 72 | Y = Y + ZombRand(-2, 3) 73 | 74 | local trashType = trashItems[(ZombRand(#trashItems) + 1)] 75 | --more likely to drop the same thing 76 | table.insert(trashItems, trashType) 77 | 78 | SpawnerAPI.SpawnItem(trashType, X, Y, Z, { ageInventoryItem }, nil, checkIfOutside) 79 | end 80 | end 81 | ``` 82 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/SpawnerAPI/SpawnerAPIClient.lua: -------------------------------------------------------------------------------- 1 | ---@class SpawnerAPI 2 | local SpawnerAPI = {} 3 | 4 | local function getOrSetPendingSpawnsList() 5 | local modData = ModData.getOrCreate("SpawnerAPI") 6 | if not modData.FarSquarePendingSpawns then modData.FarSquarePendingSpawns = {} end 7 | return modData.FarSquarePendingSpawns 8 | end 9 | 10 | ---@param spawned IsoObject | ArrayList 11 | ---@param functions table table of functions 12 | local function processExtraFunctionsOnto(spawned,functions) 13 | if spawned and functions and (type(functions)=="table") then 14 | for _,func in pairs(functions) do 15 | if func then 16 | func(spawned) 17 | end 18 | end 19 | end 20 | end 21 | 22 | ---@param spawnFuncType string This string is concated to the end of 'SpawnerAPI.spawn' to run a corresponding function. 23 | ---@param objectType string Module.Type for Items and Vehicles, OutfitID for Zombies 24 | ---@param x number 25 | ---@param y number 26 | ---@param z number 27 | ---@param funcsToApply table Table of functions which gets applied on the results of whatever is spawned. 28 | local function setToSpawn(spawnFuncType, objectType, x, y, z, funcsToApply, extraParam, processSquare) 29 | local farSquarePendingSpawns = getOrSetPendingSpawnsList() 30 | table.insert(farSquarePendingSpawns,{ spawnFuncType=spawnFuncType, objectType=objectType, x=x, y=y, z=z, 31 | funcsToApply=funcsToApply, extraParam=extraParam, processSquare=processSquare }) 32 | end 33 | 34 | ---@param itemType string 35 | ---@param x number 36 | ---@param y number 37 | ---@param z number 38 | ---@param extraFunctions table 39 | ---@param extraParam any 40 | ---@param processSquare function 41 | ---@return InventoryItem 42 | function SpawnerAPI.SpawnItem(itemType, x, y, z, extraFunctions, extraParam, processSquare) 43 | if not itemType then 44 | return 45 | end 46 | 47 | local currentSquare = getSquare(x,y,z) 48 | if processSquare then 49 | currentSquare = processSquare(currentSquare) 50 | end 51 | 52 | if currentSquare then 53 | x, y, z = currentSquare:getX(), currentSquare:getY(), currentSquare:getZ() 54 | local item = currentSquare:AddWorldInventoryItem(itemType, x, y, z) 55 | if item then 56 | processExtraFunctionsOnto(item,extraFunctions) 57 | end 58 | else 59 | setToSpawn("Item", itemType, x, y, z, extraFunctions, extraParam, processSquare) 60 | end 61 | end 62 | 63 | ---@param vehicleType string 64 | ---@param x number 65 | ---@param y number 66 | ---@param z number 67 | ---@param extraFunctions table 68 | ---@param extraParam any 69 | ---@param processSquare function 70 | ---@return InventoryItem 71 | function SpawnerAPI.SpawnVehicle(vehicleType, x, y, z, extraFunctions, extraParam, processSquare) 72 | if not vehicleType then 73 | return 74 | end 75 | 76 | local currentSquare = getSquare(x,y,z) 77 | if processSquare then 78 | currentSquare = processSquare(currentSquare) 79 | end 80 | 81 | if currentSquare then 82 | local vehicle = addVehicleDebug(vehicleType, IsoDirections.getRandom(), nil, currentSquare) 83 | if vehicle then 84 | processExtraFunctionsOnto(vehicle,extraFunctions) 85 | end 86 | else 87 | setToSpawn("Vehicle", vehicleType, x, y, z, extraFunctions, extraParam, processSquare) 88 | end 89 | end 90 | 91 | ---@param outfitID string 92 | ---@param x number 93 | ---@param y number 94 | ---@param z number 95 | ---@param extraFunctions table 96 | ---@param femaleChance number extraParam for other spawners 0-100 97 | ---@param processSquare function 98 | ---@return InventoryItem 99 | function SpawnerAPI.SpawnZombie(outfitID, x, y, z, extraFunctions, femaleChance, processSquare) 100 | if not outfitID then 101 | return 102 | end 103 | 104 | local currentSquare = getSquare(x,y,z) 105 | if processSquare then 106 | currentSquare = processSquare(currentSquare) 107 | end 108 | 109 | if currentSquare then 110 | x, y, z = currentSquare:getX(), currentSquare:getY(), currentSquare:getZ() 111 | local zombies = addZombiesInOutfit(x, y, z, 1, outfitID, femaleChance) 112 | if zombies and zombies:size()>0 then 113 | processExtraFunctionsOnto(zombies,extraFunctions) 114 | end 115 | else 116 | setToSpawn("Zombie", outfitID, x, y, z, extraFunctions, femaleChance, processSquare) 117 | end 118 | end 119 | 120 | ---@param square IsoGridSquare 121 | local function parseSquare(square) 122 | local farSquarePendingSpawns = getOrSetPendingSpawnsList() 123 | 124 | if #farSquarePendingSpawns < 1 then 125 | return 126 | end 127 | 128 | local sqX, sqY, sqZ = square:getX(), square:getY(), square:getZ() 129 | for key,entry in pairs(farSquarePendingSpawns) do 130 | if (not entry.spawned) and entry.x==sqX and entry.y==sqY and entry.z==sqZ then 131 | 132 | 133 | local shiftedSquare = square 134 | if entry.processSquare then 135 | shiftedSquare = entry.processSquare(shiftedSquare) 136 | end 137 | 138 | if shiftedSquare then 139 | local spawnFunc = SpawnerAPI["spawn"..entry.spawnFuncType] 140 | 141 | if type(spawnFunc) == "function" then 142 | local spawnedObject = spawnFunc(entry.objectType, sqX, sqY, sqZ, entry.funcsToApply, entry.extraParam) 143 | if not spawnedObject then 144 | print("SpawnerAPI: ERR: item not spawned: "..entry.objectType.." ("..sqX..","..sqY..","..sqZ..")") 145 | end 146 | end 147 | end 148 | farSquarePendingSpawns[key] = nil 149 | end 150 | end 151 | end 152 | Events.LoadGridsquare.Add(parseSquare) 153 | 154 | return SpawnerAPI -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/WorldSoundAPI/README.md: -------------------------------------------------------------------------------- 1 | # WorldSoundAPI 2 | **Developer:** Konijima 3 | **Contributors:** - 4 | 5 | ## Description 6 | Easily add Sounds at specific position categorized by unique name. 7 | 8 | ## Methods 9 | *soundList parameter can be a string or a list of string to chain multiple sounds.* 10 | ```lua 11 | AddSoundAt(name, x, y, z, soundList) 12 | ``` 13 | ```lua 14 | RemoveSoundAt(name, x, y, z) 15 | ``` 16 | ```lua 17 | RemoveAllSoundAt(x, y, z) 18 | ``` 19 | 20 | ## Example 21 | ```lua 22 | require("CommunityAPI") 23 | 24 | local WorldSoundAPI = CommunityAPI.Client.WorldSound 25 | 26 | WorldSoundAPI.AddSoundAt("computer_ambiant", x, y, z, {"ComputerBoot", "ComputerHum"}) 27 | WorldSoundAPI.AddSoundAt("computer_ambiant", x, y, z, "ComputerShutdown") 28 | WorldSoundAPI.RemoveSoundAt("computer_ambiant", x, y, z) 29 | WorldSoundAPI.RemoveAllSoundAt(x, y, z) 30 | ``` 31 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/client/WorldSoundAPI/WorldSoundAPIClient.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPI") 2 | require("ISBaseObject") 3 | 4 | local StringUtils = CommunityAPI.Utils.String 5 | 6 | local DEBUG = getCore():getDebug() 7 | 8 | ---@class WorldSoundObject 9 | local WorldSoundObject = ISBaseObject:derive("WorldSoundObject") 10 | 11 | function WorldSoundObject:isPlaying() 12 | return self.audio ~= nil and self.soundEmitter:isPlaying(self.audio) 13 | end 14 | 15 | function WorldSoundObject:update() 16 | if self.completed then return false; end 17 | 18 | self.soundEmitter:tick() 19 | 20 | if self.audio == nil or not self.soundEmitter:isPlaying(self.audio) then 21 | self.index = self.index + 1 22 | if self.soundList[self.index] then 23 | self.audio = self.soundEmitter:playSound(self.soundList[self.index]) 24 | else 25 | self.completed = true 26 | self.soundEmitter = nil 27 | return false 28 | end 29 | end 30 | return true 31 | end 32 | 33 | function WorldSoundObject:destroy() 34 | if self.soundEmitter then 35 | self.soundEmitter:stopAll() 36 | self.soundEmitter = nil 37 | 38 | end 39 | end 40 | 41 | function WorldSoundObject:new(name, x ,y ,z, soundList) 42 | local o = ISBaseObject:new() 43 | setmetatable(o, self) 44 | self.__index = self 45 | 46 | if type(soundList) == "table" then 47 | o.soundList = soundList 48 | elseif type(soundList) == "string" then 49 | o.soundList = {soundList} 50 | else 51 | error("WorldSoundAPI: Parameter soundList must be a string or a table of string.") 52 | end 53 | 54 | o.name = name 55 | o.position = { x=x, y=y, z=z } 56 | 57 | o.index = 0 58 | o.audio = nil 59 | o.completed = false 60 | o.soundEmitter = fmod.fmod.FMODSoundEmitter.new() 61 | o.soundEmitter:setPos(x, y, z) 62 | 63 | return o 64 | end 65 | 66 | ----------------------------------------------------------- 67 | 68 | local WorldSoundAPI = {} 69 | 70 | ---@type table 71 | local Sounds = {} 72 | 73 | ---@param name string 74 | ---@param x number 75 | ---@param y number 76 | ---@param z number 77 | ---@param soundList string|table 78 | function WorldSoundAPI.AddSoundAt(name, x, y, z, soundList) 79 | local id = StringUtils.PositionToId(x, y, z) 80 | if not Sounds[id] then 81 | Sounds[id] = {} 82 | end 83 | if Sounds[id] and Sounds[id][name] then 84 | Sounds[id][name]:destroy() 85 | Sounds[id][name] = nil 86 | end 87 | 88 | Sounds[id][name] = WorldSoundObject:new(name, x ,y, z, soundList) 89 | if DEBUG then print("World sound ['"..name.."'] added at x:"..x.." y:"..y.." z:"..z) end 90 | end 91 | 92 | ---@param name string 93 | ---@param x number 94 | ---@param y number 95 | ---@param z number 96 | function WorldSoundAPI.RemoveSoundAt(name, x, y, z) 97 | local id = StringUtils.PositionToId(x, y, z) 98 | if Sounds[id] and Sounds[id][name] then 99 | Sounds[id][name]:destroy() 100 | Sounds[id][name] = nil 101 | if DEBUG then print("World sound ['"..name.."'] removed at x:"..x.." y:"..y.." z:"..z) end 102 | end 103 | end 104 | 105 | ---@param x number 106 | ---@param y number 107 | ---@param z number 108 | function WorldSoundAPI.RemoveAllSoundAt(x, y, z) 109 | local id = StringUtils.PositionToId(x, y, z) 110 | if Sounds[id] then 111 | for name in pairs(Sounds[id]) do 112 | Sounds[id][name]:destroy() 113 | Sounds[id][name] = nil 114 | if DEBUG then print("World sound ['"..name.."'] removed at x:"..x.." y:"..y.." z:"..z) end 115 | end 116 | Sounds[id] = {} 117 | end 118 | end 119 | 120 | local function Tick() 121 | for id in pairs(Sounds) do 122 | for name in pairs(Sounds[id]) do 123 | if not Sounds[id][name].completed then 124 | Sounds[id][name]:update() 125 | else 126 | local position = Sounds[id][name].position 127 | Sounds[id][name] = nil 128 | if DEBUG then print("World sound ['"..name.."'] completed at x:"..position.x.." y:"..position.y.." z:"..position.z) end 129 | end 130 | end 131 | end 132 | end 133 | Events.OnTick.Add(Tick) 134 | 135 | return WorldSoundAPI -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/server/CommunityAPI.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPIShared") 2 | 3 | CommunityAPI.Server = { 4 | Distribution = require("DistributionAPI/DistributionAPIServer"), 5 | Spawner = require("SpawnerAPI/SpawnerAPIServer"), 6 | } 7 | 8 | ----------------------------------------------------------------------------------- 9 | 10 | print("Loading CommunityAPI [Server] =================================================") 11 | for k, v in pairs(CommunityAPI.Server) do 12 | print("CommunityAPI.Server."..k, v) 13 | end -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/server/DistributionAPI/DistributionAPIServer.lua: -------------------------------------------------------------------------------- 1 | require("CommunityAPI") 2 | require("Items/SuburbsDistributions") 3 | require("Items/ProceduralDistributions") 4 | 5 | local MainDistributionTable = {} 6 | 7 | ---@param locationParts table 8 | local function getLocation(locationParts) 9 | if type(locationParts) == "table" then 10 | local partCount = #locationParts 11 | --local location = _G[locationParts[1]]; TODO: Fix to this? 12 | local location = ProceduralDistributions 13 | local locationString = locationParts[1] 14 | 15 | if locationParts[1] == "SuburbsDistributions" then 16 | location = SuburbsDistributions 17 | elseif locationParts[1] == "ProceduralDistributions" then 18 | location = ProceduralDistributions 19 | else 20 | return 21 | end 22 | 23 | for i=2, #locationParts do 24 | if location[locationParts[i]] then 25 | locationString = locationString .. "-" .. locationParts[i] 26 | location = location[locationParts[i]] 27 | else 28 | return -- Break out of it and return nil instead of allowing incomplete location! 29 | end 30 | if i >= partCount then 31 | return location 32 | end 33 | end 34 | end 35 | end 36 | 37 | ---@param location table 38 | ---@param item string 39 | ---@param odd number 40 | ---@return boolean 41 | local function add(location, item, odd) 42 | if type(location) == "table" then 43 | table.insert(location, item) 44 | table.insert(location, odd) 45 | return true 46 | end 47 | end 48 | 49 | ---@param modName string 50 | ---@param table table 51 | ---@param location table 52 | local function process_location(modName, table, location) 53 | if location then 54 | for e=1, #table.items do 55 | local item = table.items[e][1] 56 | local odd = table.items[e][2] 57 | 58 | if not add(location, item, odd) then 59 | print(modName..": Error distribution adding table '"..item.."':'"..odd.."' at '"..table.location.."'!") 60 | error(modName..": Error distribution adding table '"..item.."':'"..odd.."' at '"..table.location.."'!") 61 | else 62 | print(modName..": Distribution added '"..item.."':'"..odd.."' to table '"..table.location.."'!") 63 | end 64 | end 65 | else 66 | print(modName..": Error distribution invalid location at '"..table.location.."'!") 67 | error(modName..": Error distribution invalid location at '"..table.location.."'!") 68 | end 69 | end 70 | 71 | ---@param modName string 72 | ---@return number 73 | local function process(modName) 74 | local errorCount = 0 75 | for t=1, #MainDistributionTable do 76 | local table = MainDistributionTable[t] 77 | local locationParts = CommunityAPI.Utils.String.SplitString(table.location, ".") 78 | --print("##### locationParts : ", locationParts, " = ",#locationParts) 79 | local location = getLocation(locationParts) 80 | 81 | if not pcall(process_location, modName, table, location) then 82 | errorCount = errorCount + 1 83 | end 84 | end 85 | return errorCount 86 | end 87 | 88 | ---@param modName string 89 | ---@param locationEntry table 90 | local function addLocation(modName, locationEntry) 91 | if type(locationEntry) ~= "table" then 92 | print(modName..": AddDistributionTable error a Location Entry must be a table, got a " .. type(locationEntry) .. "!") 93 | error(modName..": AddDistributionTable error a Location Entry must be a table, got a " .. type(locationEntry) .. "!") 94 | end 95 | if type(locationEntry.location) ~= "string" then 96 | print(modName..": AddDistributionTable error 'location' must be a string, got a " .. type(locationEntry.location) .. "!") 97 | error(modName..": AddDistributionTable error 'location' must be a string, got a " .. type(locationEntry.location) .. "!") 98 | end 99 | if type(locationEntry.items) ~= "table" then 100 | print(modName..": AddDistributionTable error 'items' must be a table, got a " .. type(locationEntry.items) .. "!") 101 | error(modName..": AddDistributionTable error 'items' must be a table, got a " .. type(locationEntry.items) .. "!") 102 | end 103 | if locationEntry.AddItem then 104 | locationEntry.AddItem = nil 105 | end 106 | 107 | table.insert(MainDistributionTable, locationEntry) 108 | end 109 | 110 | ---@param modName string 111 | ---@param locationsTable table 112 | local function addLocations(modName, locationsTable) 113 | if type(locationsTable) == "table" then 114 | for i=1, #locationsTable do 115 | addLocation(modName, locationsTable[i]) 116 | end 117 | else 118 | print(modName..": AddDistributionTable did not receive a locations table!") 119 | end 120 | end 121 | 122 | ---@class DistributionAPI 123 | local DistributionAPI = {} 124 | 125 | --- Add locations table 126 | ---@param modName string 127 | ---@param locationsTable table 128 | function DistributionAPI.Add(modName, locationsTable) 129 | if type(modName) ~= "string" then 130 | print("Distribution API: An addon didn't specify a name using the method ComputerAddDistributionLocations!") 131 | return 132 | end 133 | if not pcall(addLocations, modName, locationsTable) then 134 | print(modName..": There was an error trying to add distribution locations!") 135 | else 136 | if #locationsTable > 0 then 137 | print("---------------------------------------------------------------------------------------") 138 | local errorCount = process(modName) 139 | if errorCount == 0 then 140 | print(modName..": Adding to the distribution table process completed!") 141 | else 142 | print(modName..": Adding to the distribution table process completed with "..errorCount.." error(s)!") 143 | end 144 | print("---------------------------------------------------------------------------------------") 145 | MainDistributionTable = {} 146 | end 147 | end 148 | end 149 | 150 | ---@param locationPath string 151 | ---@param distributionTable table 152 | function DistributionAPI.CreateLocation(locationPath, distributionTable) 153 | local location = { 154 | location = locationPath, 155 | items = {}, 156 | } 157 | 158 | function location:AddItem(itemFullType, odd) 159 | table.insert(self.items, {itemFullType, odd}) 160 | end 161 | 162 | table.insert(distributionTable, location) 163 | return location 164 | end 165 | 166 | return DistributionAPI 167 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/server/DistributionAPI/README.md: -------------------------------------------------------------------------------- 1 | # Distribution API 2 | **Developer:** Konijima 3 | **Contributors:** - 4 | 5 | ## Description 6 | Add your new items to the distribution tables in a safer and more effective way. 7 | 8 | If a game update changes a distribution location, mods that are using this API will still works. 9 | Only the faulty location path will be canceled and the rest of the distribution will be added. 10 | It will logs everything so that you can easily debug if an item was added to the distribution table. 11 | Also help the users to know which mod adds what to each tables. 12 | 13 | ## How to use 14 | 15 | 1) Create your distribution file in `mods\YourMod\media\lua\server\MyServerDistributionFile.lua` as usual. 16 | 2) Use one of the example below to suit your preference. 17 | 3) Add `require=CommunityAPI` to your `mod.info` to make sure the API is enabled as well. 18 | 19 | Only paths to `SuburbsDistributions` and `ProceduralDistributions` works and must be written with dots in between. 20 | 21 | ## Methods 22 | ```lua 23 | CreateLocation(locationPath, distributionTable) 24 | ``` 25 | ```lua 26 | Add(modName, distributionTable) 27 | ``` 28 | 29 | ### Example 1 30 | ```lua 31 | require("CommunityAPI") 32 | 33 | local DistributionAPI = CommunityAPI.Server.Distribution 34 | 35 | local modName = "My_Mod_Name" 36 | local distributionTable = {} 37 | 38 | local CrateCompactDiscs = DistributionAPI.CreateLocation("ProceduralDistributions.list.CrateCompactDiscs.items", distributionTable) 39 | CrateCompactDiscs:AddItem("Base.Screwdriver", 6) 40 | CrateCompactDiscs:AddItem("Base.Disc", 4) 41 | 42 | DistributionAPI.Add(modName, distributionTable) 43 | ``` 44 | 45 | ### Example 2 46 | ```lua 47 | require("CommunityAPI") 48 | 49 | local modName = "My_Mod_Name" 50 | local distributionTable = { 51 | 52 | { 53 | location = "ProceduralDistributions.list.CrateCompactDiscs.items", 54 | items = { 55 | { "Base.Screwdriver", 6 }, 56 | { "Base.Disc", 4 }, 57 | } 58 | }, 59 | 60 | } 61 | 62 | CommunityAPI.Server.Distribution.Add(modName, distributionTable) 63 | ``` 64 | 65 | **Example of Logs Output** 66 | 67 | If no error: 68 | ``` 69 | LOG : General , > --------------------------------------------------------------------------------------- 70 | LOG : General , > My_Mod_Name: Distribution added 'Base.Screwdriver':'6' to table 'ProceduralDistributions.list.CrateCompactDiscs.items'! 71 | LOG : General , > My_Mod_Name: Distribution added 'Base.Disc':'4' to table 'ProceduralDistributions.list.CrateCompactDiscs.items'! 72 | LOG : General , > My_Mod_Name: Adding to the distribution table process completed! 73 | LOG : General , > --------------------------------------------------------------------------------------- 74 | ``` 75 | 76 | If one of the game distribution location changed after a game update: 77 | ``` 78 | LOG : General , > --------------------------------------------------------------------------------------- 79 | ERROR: General , > My_Mod_Name: Error distribution invalid location at 'ProceduralDistributions.list.CrateCompactDiscs.items2'! 80 | LOG : General , > My_Mod_Name: Distribution added 'Base.Screwdriver':'6' to table 'ProceduralDistributions.list.CrateCompactDiscs.items'! 81 | LOG : General , > My_Mod_Name: Distribution added 'Base.Disc':'4' to table 'ProceduralDistributions.list.CrateCompactDiscs.items'! 82 | LOG : General , > My_Mod_Name: Adding to the distribution table process completed with 1 error(s)! 83 | ``` 84 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/server/SpawnerAPI/README.md: -------------------------------------------------------------------------------- 1 | # SpawnerAPI [Server] 2 | **Developer:** Chuck 3 | **Contributors:** - 4 | 5 | ## Description 6 | ... 7 | 8 | ## How to use 9 | ... 10 | 11 | ## Methods 12 | ... 13 | 14 | ## Example 15 | ... -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/server/SpawnerAPI/SpawnerAPIServer.lua: -------------------------------------------------------------------------------- 1 | local SpawnerAPI = {} 2 | 3 | 4 | 5 | return SpawnerAPI -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/BodyLocationsAPI/BodyLocationsAPIShared.lua: -------------------------------------------------------------------------------- 1 | require("NPCs/BodyLocations") 2 | 3 | local BodyLocationsAPI = {}; 4 | local function customGetVal(obj, int) return getClassFieldVal(obj, getClassField(obj, int)); end 5 | local group = BodyLocations.getGroup("Human"); 6 | local list = customGetVal(group, 1); 7 | 8 | ---@param toRelocateOrCreate string 9 | ---@param locationElement string 10 | ---@param afterBoolean boolean 11 | ---@return BodyLocation 12 | function BodyLocationsAPI:moveOrCreateBeforeOrAfter(toRelocateOrCreate, locationElement, afterBoolean) 13 | -- Check type of arg 2 == string - if not error out. 14 | if type(locationElement) ~= "string" then error("Argument 2 is not of type string. Please re-check!", 2); end 15 | local itemToMoveTo = o.group:getLocation(locationElement); -- get location to move to 16 | if itemToMoveTo ~= nil then 17 | -- Check type of arg 1 == string - if not, error out. 18 | if type(toRelocateOrCreate) ~= "string" then error("Argument 1 is not of type string. Please re-check!", 2) end 19 | local curItem = group:getOrCreateLocation(toRelocateOrCreate); -- get current item - or create 20 | list:remove(curItem); -- remove from the list 21 | local index = group:indexOf(locationElement); -- get current index after removal of the location to move to 22 | if afterBoolean then index = index + 1; end -- if we want it after it, we increase the index to move to by one 23 | list:add(index, curItem); -- we add the item again 24 | return curItem; 25 | else -- we did not find the location to move to, so we throw an error. 26 | error("Could not find the BodyLocation [",locationElement,"] - please check the passed arguments!", 2); 27 | end 28 | end 29 | 30 | ---@param toRelocateOrCreate string 31 | ---@param locationElement string 32 | ---@return BodyLocation 33 | function BodyLocationsAPI.moveOrCreateBefore(toRelocateOrCreate, locationElement) -- for simpler and clearer usage 34 | return BodyLocationsAPI.moveOrCreateBeforeOrAfter(toRelocateOrCreate, locationElement, false); 35 | end 36 | 37 | 38 | ---@param toRelocateOrCreate string 39 | ---@param locationElement string 40 | ---@return BodyLocation 41 | function BodyLocationsAPI.moveOrCreateAfter(toRelocateOrCreate, locationElement) -- for simpler and clearer usage 42 | return BodyLocationsAPI.moveOrCreateBeforeOrAfter(toRelocateOrCreate, locationElement, true); 43 | end 44 | 45 | ---@param loc1 string 46 | ---@param alias string 47 | ---@return BodyLocation 48 | function BodyLocationsAPI.removeAlias(loc1, alias) -- will remove 2nd arg (alias) from location 1 49 | local item = group:getLocation(loc1); 50 | if item ~= nil and type(alias) == "string" then 51 | local aliases = customGetVal(item, 2); 52 | aliases:remove(alias); 53 | end 54 | return item; 55 | end 56 | 57 | ---@param loc1 string 58 | ---@param loc2 string 59 | ---@return BodyLocation 60 | function BodyLocationsAPI.unsetExclusive(loc1, loc2) -- will remove exclusive from each other 61 | local item1 = group:getLocation(loc1); 62 | local item2 = group:getLocation(loc2); 63 | if item1 ~= nil and item2 ~= nil then 64 | local exclusives1 = customGetVal(item1, 3); 65 | exclusives1:remove(loc2); 66 | local exclusives2 = customGetVal(item2, 3); 67 | exclusives2:remove(loc1); 68 | end 69 | return item1; 70 | end 71 | 72 | ---@param loc1 string 73 | ---@param loc2 string 74 | ---@return BodyLocation 75 | function BodyLocationsAPI.unhideModel(loc1, loc2) -- remove loc2 from loc1's hidemodel list 76 | local item1 = group:getLocation(loc1); 77 | local item2 = group:getLocation(loc2); 78 | if item1 ~= nil and item2 ~= nil then 79 | local hidemodels = customGetVal(item1, 4); 80 | hidemodels:remove(loc2); 81 | end 82 | return item1; 83 | end 84 | 85 | return BodyLocationsAPI; 86 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/BodyLocationsAPI/README.md: -------------------------------------------------------------------------------- 1 | # BodyLocations API 2 | **Developer:** Shurutsue 3 | **Contributors:** 4 | 5 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/ColorUtils.lua: -------------------------------------------------------------------------------- 1 | local ColorUtils = {} 2 | 3 | --- Get a color from Red to Green based on a current value / max value 4 | ---@param current number 5 | ---@param max number 6 | function ColorUtils.GetColorFromCurrentMax(current, max) 7 | if current < 1 and current > 0 then 8 | current = current * 100 9 | max = max * 100 10 | end 11 | local r = ((max - current) / max) 12 | local g = (current / max) 13 | return {r = r, g = g, b = 0} 14 | end 15 | 16 | --- Get a color from Green to Red based on a current value / max value 17 | ---@param current number 18 | ---@param max number 19 | function ColorUtils.GetReversedColorFromCurrentMax(current, max) 20 | if current < 1 and current > 0 then 21 | current = current * 100 22 | max = max * 100 23 | end 24 | local g = ((max - current) / max) 25 | local r = (current / max) 26 | return {r = r, g = g, b = 0} 27 | end 28 | 29 | --- Create a color object from rgba parameters 30 | ---@param r number Red 31 | ---@param g number Green 32 | ---@param b number Blue 33 | ---@param _a number|nil Alpha 34 | ---@return table 35 | function ColorUtils.RgbaToColor(r, g, b, _a) 36 | local color = { r=r, g=g, b=b, a=_a } 37 | if type(color.a) ~= "number" then color.a = 1; end 38 | return color 39 | end 40 | 41 | --- Get a color or set a default color, used to make sure the returned 42 | ---@param color table { r= number, g=number, b=number, a=number } 43 | ---@param defaultColor table { r= number, g=number, b=number, a=number } 44 | ---@return table 45 | function ColorUtils.GetColorOrDefault(color, defaultColor) 46 | if type(color) ~= "table" then 47 | return defaultColor 48 | end 49 | if type(color.r) ~= "number" then color.r = defaultColor.r; end 50 | if type(color.g) ~= "number" then color.g = defaultColor.g; end 51 | if type(color.b) ~= "number" then color.b = defaultColor.b; end 52 | if type(color.a) ~= "number" then color.a = defaultColor.a; end 53 | return color 54 | end 55 | 56 | return ColorUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/InventoryUtils.lua: -------------------------------------------------------------------------------- 1 | local InventoryUtils = {} 2 | 3 | --- Find all item in an inventory by tag 4 | ---@param inventory ItemContainer 5 | ---@param tag string 6 | ---@return ArrayList|nil 7 | function InventoryUtils.FindAllItemInInventoryByTag(inventory, tag) 8 | if instanceof(inventory, "ItemContainer") and type(tag) == "string" then 9 | local foundItems = ArrayList.new(); 10 | local validItems = getScriptManager():getItemsTag(tag); 11 | if validItems then 12 | for i=0, validItems:size()-1 do 13 | foundItems:addAll(inventory:getItemsFromFullType(validItems:get(i):getFullName())); 14 | end 15 | end 16 | return foundItems; 17 | end 18 | end 19 | 20 | return InventoryUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/IsoUtils.lua: -------------------------------------------------------------------------------- 1 | local IsoUtils = {} 2 | 3 | --- Safely get the square of an IsoObject recursively 4 | ---@param object IsoObject|IsoGridSquare 5 | ---@return IsoGridSquare 6 | function IsoUtils.RecursiveGetSquare(object) 7 | if instanceof(object, "IsoGridSquare") then 8 | return object 9 | end 10 | 11 | if not instanceof(object, "IsoObject") then 12 | return nil 13 | end 14 | 15 | local square 16 | if instanceof(object, "IsoGameCharacter") and object:getVehicle() then 17 | square = object:getVehicle() 18 | end 19 | 20 | if not instanceof(square, "IsoGridSquare") then 21 | square = square:getSquare() 22 | end 23 | 24 | return square 25 | end 26 | 27 | ---@param center IsoObject|IsoGridSquare 28 | ---@param range number tiles to scan from center, not including center. ex: range of 1 = 3x3 29 | ---@param fractalOffset number fractal offset - spreads out squares by this number 30 | ---@return table 31 | function IsoUtils.GetIsoRange(center, range, fractalOffset) 32 | center = IsoUtils.RecursiveGetSquare(center) 33 | if not center then 34 | return {} 35 | end 36 | 37 | if not fractalOffset then 38 | fractalOffset = 1 39 | else 40 | fractalOffset = (fractalOffset*2)+1 41 | end 42 | 43 | --true center 44 | local centerX, centerY = center:getX(), center:getY() 45 | --add center to squares at the start 46 | local squares = {center} 47 | 48 | --no point in running everything below, return squares 49 | if range < 1 then return squares end 50 | 51 | --create a ring of IsoGridSquare around center, i=1 skips center 52 | for i=1, range do 53 | 54 | local fractalFactor = i*fractalOffset 55 | --currentX and currentY have to pushed off center for the logic below to kick in 56 | local currentX, currentY = centerX-fractalFactor, centerY+fractalFactor 57 | -- ring refers to the path going around center, -1 to skip center 58 | local expectedRingLength = (8*i)-1 59 | 60 | for _=0, expectedRingLength do 61 | --if on top-row and not at the upper-right 62 | if (currentY == centerY+fractalFactor) and (currentX < centerX+fractalFactor) then 63 | --move-right 64 | currentX = currentX+fractalOffset 65 | --if on right-column and not the bottom-right 66 | elseif (currentX == centerX+fractalFactor) and (currentY > centerY-fractalFactor) then 67 | --move down 68 | currentY = currentY-fractalOffset 69 | --if on bottom-row and not on far-left 70 | elseif (currentY == centerY-fractalFactor) and (currentX > centerX-fractalFactor) then 71 | --move left 72 | currentX = currentX-fractalOffset 73 | --if on left-column and not on top-left 74 | elseif (currentX == centerX-fractalFactor) and (currentY < centerY+fractalFactor) then 75 | --move up 76 | currentY = currentY+fractalOffset 77 | end 78 | 79 | ---@type IsoGridSquare square 80 | local square = getCell():getOrCreateGridSquare(currentX, currentY, 0) 81 | --[DEBUG]] getWorldMarkers():addGridSquareMarker(square, 0.8, fractalOffset-1, 0, false, 0.5) 82 | table.insert(squares, square) 83 | end 84 | end 85 | --[[DEBUG 86 | print("---[ IsoRange ]---\n total "..#squares.."/"..((range*2)+1)^2) 87 | for k,v in pairs(squares) do 88 | ---@type IsoGridSquare vSquare 89 | local vSquare = v 90 | print(" "..k..": "..centerX-vSquare:getX()..", "..centerY-vSquare:getY()) 91 | end 92 | ]] 93 | return squares 94 | end 95 | 96 | --- Get all humanoid in fractal range from a center point 97 | ---@param center IsoObject|IsoGridSquare the center point 98 | ---@param range number tiles to scan from center, not including center. ex: range of 1 = 3x3 99 | ---@param fractalRange number number of rows, made up of `range`, from the center range 100 | ---@param lookForType string|nil get only a specific type 101 | ---@param addedBooleanFunctions table table of function(s) must return true to pass 102 | ---@return table 103 | function IsoUtils.GetIsoGameCharactersInFractalRange(center, range, fractalRange, lookForType, addedBooleanFunctions) 104 | center = IsoUtils.RecursiveGetSquare(center) 105 | if not center then 106 | return {} 107 | end 108 | 109 | --range and fractalRange are flipped in the parameters here because: 110 | -- "fractalRange" represents the number of rows from center out but with an offset of "range" instead 111 | local fractalCenters = IsoUtils.GetIsoRange(center, fractalRange, range) 112 | local fractalObjectsFound = {} 113 | ---print("getHumanoidsInFractalRange: centers found: "..#fractalCenters) 114 | --pass through each "center square" found 115 | for i=1, #fractalCenters do 116 | local objectsFound = IsoUtils.GetIsoGameCharactersInRange(fractalCenters[i], range, lookForType, addedBooleanFunctions) 117 | ---print(" fractal center "..i..": "..#objectsFound) 118 | --store a list of objectsFound within the fractalObjectsFound list 119 | table.insert(fractalObjectsFound, objectsFound) 120 | end 121 | 122 | return fractalObjectsFound 123 | end 124 | 125 | --- Get all humanoid in range from a center point 126 | ---@param center IsoObject|IsoGridSquare the center point 127 | ---@param range number tiles to scan from center, not including center. ex: range of 1 = 3x3 128 | ---@param lookForType string|nil get only a specific type 129 | ---@param addedBooleanFunctions table table of function(s) must return true to pass 130 | ---@return table 131 | function IsoUtils.GetIsoGameCharactersInRange(center, range, lookForType, addedBooleanFunctions) 132 | center = IsoUtils.RecursiveGetSquare(center) 133 | if not center then 134 | return {} 135 | end 136 | 137 | local squaresInRange = IsoUtils.GetIsoRange(center, range) 138 | local objectsFound = {} 139 | 140 | for sq=1, #squaresInRange do 141 | 142 | ---@type IsoGridSquare 143 | local square = squaresInRange[sq] 144 | local squareContents = square:getLuaMovingObjectList() 145 | 146 | for i=1, #squareContents do 147 | ---@type IsoMovingObject|IsoGameCharacter foundObject 148 | local foundObj = squareContents[i] 149 | 150 | if instanceof(foundObj, "IsoGameCharacter") and (not lookForType or instanceof(foundObj, lookForType)) then 151 | 152 | local booleanPass = true 153 | if addedBooleanFunctions and (#addedBooleanFunctions > 0) then 154 | for k,func in pairs(addedBooleanFunctions) do 155 | if not func(foundObj) then 156 | booleanPass = false 157 | end 158 | end 159 | end 160 | 161 | if booleanPass then 162 | table.insert(objectsFound, foundObj) 163 | 164 | end 165 | end 166 | end 167 | end 168 | 169 | return objectsFound 170 | end 171 | 172 | return IsoUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/MathUtils.lua: -------------------------------------------------------------------------------- 1 | local MathUtils = {} 2 | 3 | --- Get the distance between two point 4 | ---@param x1 number X coordinate of first point 5 | ---@param y1 number y coordinate of first point 6 | ---@param x2 number X coordinate of second point 7 | ---@param y2 number y coordinate of second point 8 | function MathUtils.GetDistance(x1, y1, x2, y2) 9 | local a = x1 - x2 10 | local b = y1 - y2 11 | return math.sqrt( a*a + b*b ) 12 | end 13 | 14 | return MathUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/README.md: -------------------------------------------------------------------------------- 1 | # Utilities 2 | Utility packages to use in API and Mods. 3 | 4 | ## How to use 5 | ```lua 6 | require("CommunityAPI") 7 | 8 | local StringUtils = CommunityAPI.Utils.String 9 | StringUtils.SplitString("Hello world", " ") 10 | ``` 11 | 12 | ### CommunityAPI.Utils.Inventory 13 | ```lua 14 | FindAllItemInInventoryByTag(inventory, tag) 15 | ``` 16 | 17 | ### CommunityAPI.Utils.Iso 18 | ```lua 19 | RecursiveGetSquare(object) 20 | 21 | GetIsoRange(center, range, fractalOffset) 22 | 23 | GetIsoGameCharactersInFractalRange(center, range, fractalRange, lookForType, addedBooleanFunctions) 24 | 25 | GetIsoGameCharactersInRange(center, range, lookForType, addedBooleanFunctions) 26 | ``` 27 | 28 | ### CommunityAPI.Utils.Math 29 | ```lua 30 | GetDistance(x1, y1, x2, y2) 31 | ``` 32 | 33 | ### CommunityAPI.Utils.String 34 | ```lua 35 | SquareToId(square) 36 | 37 | PositionToId(x, y ,z) 38 | 39 | SplitString(str, delimiter) 40 | ``` 41 | 42 | ### CommunityAPI.Utils.Table 43 | ```lua 44 | CountTableEntries(targetTable) 45 | 46 | GetTableKeys(targetTable) 47 | 48 | TableContains(table, value) 49 | 50 | GetBaseClass(object, level) 51 | 52 | GetAllBaseClasses(object, excludeCurrent) 53 | 54 | IsClassChildOf(object, class) 55 | ``` 56 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/StringUtils.lua: -------------------------------------------------------------------------------- 1 | local StringUtils = {} 2 | 3 | --- Transform a square position into a unique string 4 | ---@param square IsoGridSquare 5 | ---@return string 6 | function StringUtils.SquareToId(square) 7 | return square:getX() .. "|" .. square:getY() .. "|" .. square:getZ() 8 | end 9 | 10 | --- Transform a position into a unique string 11 | ---@param x number 12 | ---@param y number 13 | ---@param z number 14 | ---@return string 15 | function StringUtils.PositionToId(x, y ,z) 16 | return x .. "|" .. y .. "|" .. z 17 | end 18 | 19 | --- Split a string by a delimiter string 20 | ---@param str string the string to split 21 | ---@param delimiter string the string to split with 22 | ---@return table 23 | function StringUtils.SplitString(str, delimiter) 24 | local result = {} 25 | for match in (str..delimiter):gmatch("(.-)%"..delimiter) do 26 | table.insert(result, match) 27 | end 28 | return result 29 | end 30 | 31 | --- Format a number into string with decimal 32 | ---@param value number The number value to format 33 | ---@param _decimal number Amount of decimal 34 | ---@return string 35 | function StringUtils.NumberToDecimalString(value, _decimal) 36 | if not type(_decimal) == "number" then _decimal = 2 end 37 | return string.format("%.".._decimal.."f", value); 38 | end 39 | 40 | return StringUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/TableUtils.lua: -------------------------------------------------------------------------------- 1 | local TableUtils = {} 2 | 3 | --- Get the total count of entry in a table 4 | ---@param targetTable table The table to get count from 5 | function TableUtils.CountTableEntries(targetTable) 6 | local count = 0 7 | for _ in pairs(targetTable) do 8 | count = count + 1 9 | end 10 | return count 11 | end 12 | 13 | --- Get all the keys of a lua table 14 | ---@param targetTable table The table to get keys from 15 | function TableUtils.GetTableKeys(targetTable) 16 | local keys = {} 17 | for key in pairs(targetTable) do 18 | table.insert(keys, key) 19 | end 20 | return keys 21 | end 22 | 23 | --- Check if a value is found in a table 24 | ---@param table table The table to search in 25 | ---@param value any The value to find 26 | ---@return boolean 27 | function TableUtils.TableContains(table, value) 28 | if type(table) == "table" then 29 | for i=1, #table do 30 | if table[i] == value then 31 | return true 32 | end 33 | end 34 | for _, v in pairs(table) do 35 | if v == value then 36 | return true 37 | end 38 | end 39 | end 40 | return false 41 | end 42 | 43 | --- Get the base class of object, optionally choose how deep you want to check. 44 | ---@param object table Will return nil if the object is not a table. 45 | ---@param _level number Will return the deepest found if level is higher than the actual amount of base classes. 46 | function TableUtils.GetBaseClass(object, _level) 47 | if not _level or _level < 1 then _level = 1; end 48 | 49 | if type(object) == "table" then 50 | local baseClass = getmetatable(object) 51 | for i=2, _level do 52 | if type(baseClass) == "table" then 53 | local class = getmetatable(baseClass) 54 | if class then 55 | baseClass = class 56 | end 57 | end 58 | end 59 | return baseClass 60 | end 61 | end 62 | 63 | --- Get a table containing all the base class from the current to the deepest. 64 | ---@param object table Will return nil if the object is not a table. 65 | ---@param _excludeCurrent boolean optionally exclude the current object class from the list 66 | ---@return table|nil 67 | function TableUtils.GetAllBaseClasses(object, _excludeCurrent) 68 | if type(object) == "table" then 69 | local baseClasses = {} 70 | local current = getmetatable(object) 71 | 72 | local lastBaseClass 73 | for i=1, 10 do 74 | local baseClass = TableUtils.GetBaseClass(object, i) 75 | if baseClass ~= nil and lastBaseClass ~= baseClass then 76 | if not _excludeCurrent or _excludeCurrent and current ~= baseClass then 77 | table.insert(baseClasses, baseClass) 78 | end 79 | lastBaseClass = baseClass 80 | else 81 | break 82 | end 83 | end 84 | 85 | return baseClasses 86 | end 87 | end 88 | 89 | --- Check if table object derive from this class 90 | ---@param object table The table object to check 91 | ---@param class table|string The class to find 92 | ---@return boolean 93 | function TableUtils.IsClassChildOf(object, class) 94 | local classType = type(class) 95 | local allBaseClasses = TableUtils.GetAllBaseClasses(object, false) 96 | if allBaseClasses then 97 | for i=1, #allBaseClasses do 98 | if (classType == "table" and allBaseClasses[i] == class) or (classType == "string" and allBaseClasses[i].Type == class) then 99 | return true 100 | end 101 | end 102 | end 103 | return false 104 | end 105 | 106 | return TableUtils -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/media/lua/shared/CommunityAPIShared.lua: -------------------------------------------------------------------------------- 1 | ---@class CommunityAPI 2 | CommunityAPI = CommunityAPI or {} 3 | 4 | CommunityAPI.Utils = { 5 | Color = require("CommunityAPI/ColorUtils"), 6 | Inventory = require("CommunityAPI/InventoryUtils"), 7 | Iso = require("CommunityAPI/IsoUtils"), 8 | Math = require("CommunityAPI/MathUtils"), 9 | String = require("CommunityAPI/StringUtils"), 10 | Table = require("CommunityAPI/TableUtils"), 11 | } 12 | 13 | CommunityAPI.Shared = { 14 | BodyLocations = require("BodyLocationsAPI/BodyLocationsAPIShared") 15 | } 16 | 17 | ----------------------------------------------------------------------------------- 18 | 19 | print("Loading CommunityAPIShared =================================================") 20 | for k, v in pairs(CommunityAPI.Utils) do 21 | print("CommunityAPI.Utils."..k, v) 22 | end 23 | for k, v in pairs(CommunityAPI.Shared) do 24 | print("CommunityAPI.Shared."..k, v) 25 | end 26 | -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/mod.info: -------------------------------------------------------------------------------- 1 | name=Community API 2 | id=CommunityAPI 3 | description= 4 | poster=poster.png 5 | author=PZ Modder Community 6 | pzversion=41.56-IWBUMS -------------------------------------------------------------------------------- /Contents/mods/CommunityAPI/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Konijima/PZ-Community-API/0a5c1f03f7a49bf3f473ed9fe611b4c1ad22a5d8/Contents/mods/CommunityAPI/poster.png -------------------------------------------------------------------------------- /Images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Konijima/PZ-Community-API/0a5c1f03f7a49bf3f473ed9fe611b4c1ad22a5d8/Images/banner.png -------------------------------------------------------------------------------- /Images/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Konijima/PZ-Community-API/0a5c1f03f7a49bf3f473ed9fe611b4c1ad22a5d8/Images/poster.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Banner](https://github.com/Konijima/PZ-Community-API/blob/master/Images/banner.png?raw=true) 2 | 3 | ## Description 4 | Community API is a team effort to centralize & give mod creators optimized tools for creating quality mods. 5 | For mod compatibility and efficiency, working as a team ensure that the API is updated and optimized. 6 | 7 | **Game Version:** 41.56-IWBUMS 8 | **Links:** [Wiki](https://github.com/Konijima/PZ-Community-API/wiki) | [Projects](https://github.com/Konijima/PZ-Community-API/projects) | [Workshop](https://github.com/Konijima/PZ-Community-API) | [Documentation](https://quarantin.github.io/zomboid-javadoc/41.56/) | [Emmylua](https://emmylua.github.io/) 9 | 10 | ## Team 11 | **Developers:** 12 | - Konijima ([Steam](https://steamcommunity.com/id/konijima/myworkshopfiles/?appid=108600) | [Github](https://github.com/Konijima)) 13 | - Shurutsue ([Steam](https://steamcommunity.com/id/Shurutsue/myworkshopfiles/?appid=108600) | [Github](https://github.com/Shurutsue)) 14 | - Chuck ([Steam](https://steamcommunity.com/id/Chuckleberry_Finn/myworkshopfiles/?appid=108600) | [Github](https://github.com/ChuckTheSheep)) 15 | - Co ([Steam](https://steamcommunity.com/profiles/76561198056536755/myworkshopfiles/?appid=108600) | [Github](https://github.com/quarantin)) 16 | 17 | ## Informations 18 | [Coding Convention](https://github.com/Konijima/PZ-Community-API/blob/master/CodingConvention.md) | [Template API](https://github.com/Konijima/PZ-Community-API/blob/master/TemplateAPI.lua.md) | [Utilities](https://github.com/Konijima/PZ-Community-API/blob/master/Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI) 19 | 20 | ## API List 21 | - **BodyLocationsAPI** ([Shared](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/shared/BodyLocationsAPI)) 22 | Tweak body locations without overwritting BodyLocations.lua. 23 | - **DistributionAPI** ([Server](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/server/DistributionAPI)) 24 | Easily manage your distribution tables. 25 | - **ItemTooltipAPI** ([Client](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/client/ItemTooltipAPI)) 26 | Make complex custom item tooltip for your new items. 27 | - **LightAPI** ([Client](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/client/LightAPI)) 28 | Add persistent light anywhere in the world. 29 | - **SpawnerAPI** ([Client](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/client/SpawnerAPI) | [Server](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/server/SpawnerAPI)) 30 | Spawn vehicles, items and zombies anywhere in the world. 31 | - **WorldSoundAPI** ([Client](https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/client/WorldSoundAPI)) 32 | Add persistent sounds anywhere in the world. 33 | 34 | ## Workflow 35 | - Create/Publish a new branch named ` - `. 36 | - Do your work on that branch. 37 | - Commit your changes by prefixing your API name in the title. 38 | *Example -> `DistributionAPI: Added new feature`* 39 | - When you are ready to release an update create a **Pull Request**. 40 | - Assign the Pull Request to your project and assignees. 41 | - After quality control the merge will be completed. 42 | - The branch will be deleted. 43 | - Repeat the same process. 44 | 45 | ## Guideline 46 | - Commits should be prefixed with the API name. 47 | - Each API have a Github [Project](https://github.com/Konijima/PZ-Community-API/projects) to organize itself. 48 | - Each API have a Github [Wiki](https://github.com/Konijima/PZ-Community-API/wiki) section for instruction on how to use the API. 49 | - Workshop update weekly or daily if hotfix are required. 50 | - API Developers must agree together to work on someone else API. 51 | - Each API must be annoted and optimized. 52 | - Readme can be updated without creating new branches. 53 | -------------------------------------------------------------------------------- /TemplateAPI.lua.md: -------------------------------------------------------------------------------- 1 | # Example of an API structure 2 | 3 | ```lua 4 | ---@class PrivateObject 5 | local PrivateObject = ISBaseObject:derive("PrivateObject") 6 | 7 | ---@param param1 string 8 | function PrivateObject:new(param1) 9 | local o = ISBaseObject:new() 10 | setmetatable(o, self) 11 | self.__index = self 12 | o.param1 = param1 13 | return o 14 | end 15 | 16 | function PrivateObject:instanceMethod() 17 | print(self.param1) 18 | end 19 | 20 | ------------------------------------------------------------------ 21 | 22 | ---@class TemplateAPI 23 | local TemplateAPI = {} 24 | 25 | local privateVariable = {} 26 | 27 | ---@param param1 string 28 | local function privateFunction(param1) 29 | table.insert(privateVariable, PrivateObject:new(param1)) 30 | end 31 | Events.OnEvent.Add(privateFunction) 32 | 33 | function TemplateAPI.PublicFunction() 34 | return privateVariable 35 | end 36 | 37 | return TemplateAPI 38 | ``` 39 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Konijima/PZ-Community-API/0a5c1f03f7a49bf3f473ed9fe611b4c1ad22a5d8/preview.png -------------------------------------------------------------------------------- /workshop.txt: -------------------------------------------------------------------------------- 1 | version=1 2 | id=2650538172 3 | title=CommunityAPI 4 | description=Coming Soon! 5 | tags=Build 41;Framework;Misc 6 | visibility=friendsOnly 7 | --------------------------------------------------------------------------------