diff --git a/behaviors/monsters/modular/targeting.behavior.patch b/behaviors/monsters/modular/targeting.behavior.patch new file mode 100644 index 00000000..b16cb1db --- /dev/null +++ b/behaviors/monsters/modular/targeting.behavior.patch @@ -0,0 +1,92 @@ +[ + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/0/child/children/1/child/children/2", + "value": { + + "title": "listPush", + "type": "action", + "name": "listPush", + "parameters": { + "entity": {"key": "self"}, + "list": {"key": "entitySelf"} + }, + "output": { + "list": "entitySelf" + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/0/child/children/1/child/children/3", + "value": { + "title": "sendEntityMessage", + "type": "action", + "name": "sendEntityMessage", + "parameters": { + "entity": {"key": "filterItem"}, + "message": {"value": "SexboundDefeat:TargetedBy"}, + "arguments": {"key": "entitySelf"} + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/0/child/children/1/child/children/4", + "value": { + "title": "listPop", + "type": "action", + "name": "listPop", + "parameters": { + "list": {"key": "entitySelf"} + }, + "output": { + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/1/child/children/1", + "value": { + + "title": "listPush", + "type": "action", + "name": "listPush", + "parameters": { + "entity": {"key": "self"}, + "list": {"key": "entitySelf"} + }, + "output": { + "list": "entitySelf" + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/1/child/children/2", + "value": { + "title": "sendEntityMessage", + "type": "action", + "name": "sendEntityMessage", + "parameters": { + "entity": {"key": "damageSource"}, + "message": {"value": "SexboundDefeat:TargetedBy"}, + "arguments": {"key": "entitySelf"} + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/1/child/children/1/child/children/3", + "value": { + "title": "listPop", + "type": "action", + "name": "listPop", + "parameters": { + "list": {"key": "entitySelf"} + }, + "output": { + } + } + } +] \ No newline at end of file diff --git a/behaviors/npc/hostiletracking.behavior.patch b/behaviors/npc/hostiletracking.behavior.patch new file mode 100644 index 00000000..94838526 --- /dev/null +++ b/behaviors/npc/hostiletracking.behavior.patch @@ -0,0 +1,103 @@ +[ + { + "op": "add", + "path": "/root/children/1/children/0/children/0/children/0/children/7", + "value": { + + "title": "listPush", + "type": "action", + "name": "listPush", + "parameters": { + "entity": {"key": "self"}, + "list": {"key": "entitySelf"} + }, + "output": { + "list": "entitySelf" + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/0/children/0/children/8", + "value": { + "title": "sendEntityMessage", + "type": "action", + "name": "sendEntityMessage", + "parameters": { + "entity": {"key": "target"}, + "message": {"value": "SexboundDefeat:TargetedBy"}, + "arguments": {"key": "entitySelf"} + } + } + }, + { + "op": "add", + "path": "/root/children/1/children/0/children/0/children/0/children/9", + "value": { + "title": "listPop", + "type": "action", + "name": "listPop", + "parameters": { + "list": {"key": "entitySelf"} + }, + "output": { + } + } + }, + { + "op": "replace", + "path": "/root/children/1/children/1/children/2/child/child", + "value": { + "title": "sequence", + "type": "composite", + "name": "sequence", + "parameters": {}, + "children": [ + { + "title": "broadcastNotification", + "type": "action", + "name": "broadcastNotification", + "parameters": { + "entityTypes": {"value": ["npc"]}, + "position": {"key": "self"}, + "range": {"value": 40}, + "target": {"key": "target"}, + "type": {"value": "attack"} + } + }, + { + "title": "listPush", + "type": "action", + "name": "listPush", + "parameters": { + "entity": {"key": "self"}, + "list": {"key": "entitySelf"} + }, + "output": { + "list": "entitySelf" + } + }, + { + "title": "sendEntityMessage", + "type": "action", + "name": "sendEntityMessage", + "parameters": { + "entity": {"key": "target"}, + "message": {"value": "SexboundDefeat:TargetedBy"}, + "arguments": {"key": "entitySelf"} + } + }, + { + "title": "listPop", + "type": "action", + "name": "listPop", + "parameters": { + "list": {"key": "entitySelf"} + }, + "output": { + } + } + ] + } + } +] \ No newline at end of file diff --git a/dialog/lustiaarcadehintconverse.config b/dialog/lustiaarcadehintconverse.config new file mode 100644 index 00000000..cdba7995 --- /dev/null +++ b/dialog/lustiaarcadehintconverse.config @@ -0,0 +1,21 @@ +{ + "greeting": { + "human": { + "default": [ + "Sorry hun~ Arcade is closed." + ] + } + }, + "converse": { + "human" : { + "default" : [ + "Been closed for a while. Real shame.", + "People loved their trading card addiction.", + "They were even selling phones!", + "Me and my pals haven't had much work out of town since then...", + "Something about \"Omnibrowser\" going out of business?", + "Omnibrowser... I wonder what that is..." + ] + } + } +} diff --git a/dungeons/sexscape/sexscape.json b/dungeons/sexscape/sexscape.json index 03310293..7c01942a 100644 --- a/dungeons/sexscape/sexscape.json +++ b/dungeons/sexscape/sexscape.json @@ -1,18 +1,11 @@ { "backgroundcolor":"#000000", "compressionlevel":-1, - "editorsettings": - { - "export": - { - "target":"." - } - }, "height":312, "infinite":false, "layers":[ { "compression":"zlib", - "data":"eJzt3e1x6rwWBlCfTnZhKSMFpKJUQWH3nAnc6DWKP7A2MdJaMxow2Mjy6M9+xhbTBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPTqktQAAAAAOI89uc6fosmDAAAAAF7H3gyo9ioLAgAAADi3RzKgrZ\/LggAAAADOYe86P+WzYH8qn8mCAAAAAM7nkfWeW90PJAsCAAAAeI5HMpt\/7XOq3w\/0eeA3AQAAAMjxaF5zy4HKZ8H+zD6XBQEAAACcw5GsZinvOZoDyYIAAAAA2jma02TnQLIgAAAAgONaZDTPyIFkQQAAAACPa5XPPCsHkgUBAAAA7Ncym3lmDiQLAgAAANiudS7z7BxIFgQAAACwLiOT+Y0cSBYEAAAAsEwOBAAAADAGORAAAADAGORAAAAAAGOQAwEAAACMQQ4EAAAAMAY5EAAAAMAY5EAAAAAAY5ADAQAAAIxBDgQAAAAwBjkQAAAAwBiyc6D3osmBAAAAAH5PyxymzHw+Z9s\/fS4HAgAAAHiOjPtyyrxny+dyIAAAAIB8Wc9oWR8IAAAA4FzkQAAAAABjkAMBAAAAjEEOBAAAADAGORAAAADAGORAAAAAAGOQAwEAAACMQQ4EAAAAMAY5EAAAAED\/PpN\/+\/3a5u8z+wQAAADgXnYm83Zt5ftMciAAAACAezHl5ya\/kQNFch8AAAAAr6h8Xmut7d33barnQG\/J\/QIAAABwb57PLLUj+65tt+wXAAAAgC9RvO85ByrHCQAAADCquL5mPxdWO\/YZz4XdxgcAAADA9zrRl41t775r9wNl9RvtLhEAAABAF2KSAwEAAACMICY5EAAAAMAo\/G88AAAAwBjkQAAAAABjyM5NallOJjkQAAAAQF12blK7HyiTHAgAAADgXkx95kCR3AcAAADAK7I+EAAAAMAY5vnMUjuy79p2y34BAAAA+BLF+55zoHKcAAAAAKOK62v2c2G1Y5\/xXNhtfAAAAAB8rxN92dj27rt2P1BWv9HuEgEAAAB0ISY5EAAAAMAIYpIDAQAAAIzC\/8YDAAAAjEEOBAAAADCG7NykluVkkgMBAAAA1GXnJrX7gTLJgQAAAADuxdRnDhTJfQAAAAC8IusDAQAAAIxhns8stSP7rm237BcAAACAL1G87zkHKscJAAAAMKq4vmY\/F1Y79hnPhd3GBwAAAMD3OtGXjW3vvmv3A2X1G+0uEQAAAEAXYpIDAQAAAIwgJjkQAAAAwCj8bzwAAADAGORAAAAAAGPIzk1qWU4mORAAAABAXXZuUrsfKJMcCAAAAOBeTH3mQJHcBwAAAMArsj4QAAAAwBjm+cxSO7Lv2nbLfgEAAAD4EsX7nnOgcpwAAAAAo4rra\/ZzYbVjn\/Fc2G18AAAAAHyvE33Z2Pbuu3Y\/UFa\/0e4SAQAAAHQhJjkQAAAAwAhikgMBAAAAjML\/xgMAAACMQQ4EAAAAMIbs3KSW5WSSAwEAAADUZecmtfuBMsmBAAAAAO7F1GcOFMl9AAAAALwi6wMBAAAAjGGezyy1I\/uubbfsFwAAAIAvUbzvOQcqxwkAAAAwqri+ZudAtWe7npED3cYHAAAAwPc60b3dDxTtLhEAAABAF2KSAwEAAACMICY5EAAAAMAo\/G88AAAAwBjkQAAAAABjyM5NallOJjkQAAAAQF12blK7HyiTHAgAAADgXkx95kCR3AcAAADAK7I+EAAAAMAYevzfeAAAAAC+RPG+5xyoHCcAAADAqOL6mv1cWO3YZzwXdhsfAAAAAN\/rRF82tr37rt0PlNVvtLtEAAAAAF2ISQ4EAAAAMIKY5EAAAAAAo\/C\/8QAAAABjkAMBAAAAjCE7N6llOZnkQAAAAAB12blJ7X6gTHIgAAAAgHsx9ZkDRXIfAAAAAK\/I+kAAAAAAY5jnM0vtyL5r2y37BQAAAOBLFO97zoHKcQIAAACMKq6v2c+F1Y59xnNht\/EBAAAA8L1O9GVj27vv2v1AWf1Gu0sEAAAA0IWY5EAAAAAAI4hJDgQAAAAwCv8bDwAAADAGORAAAADAGLJzk1qWk0kOBAAAAFCXnZvU7gfKJAcCAAAAuBdTnzlQJPcBAAAA9ONzmj7eivZve\/79yvF32\/O1cc7C+kB5RppHAAAAcHaXv3V4rdXq96V6fu7If6Y\/2\/zcltqRfde2W\/b7bOYRAAAAnE9Zn\/9Uu\/92\/X6ZfZ8hFs61pxyoHGdL5hEAAACc00\/1+avU71n3eERxrpnPhdWOfUvutxxfK+YRAAAAnNdaff6K9XvrOj429LXnvOb7HrkGR\/qNdpfIPAIAAICT21Kfv3L93moNnNjQ18g5kHkEAAAA57a1Pn\/1+v3S4FrFhr5GzYHMIwAAADi3PfV5D\/V7ixo+e32gpWtw1v+NN48AAADg3PbW573U70dreDnQf5lHAAAAcG6P1Oc91e9HavjsNWJqWU6mI+MxjwAAAGA8t\/r8\/e\/r+7Vev70vv184froeX81AzrQ+b\/a51DKMTCe7th\/\/XkeYRwAAAPCqbvV57T6O8vuF46fr8dUM5Cz1e0x95kCR3MdWo8wjAAAAeGUj3cdhfaA8I80jAAAAeIZH123pbV2XR9d2mZ\/bUjuy79p2y34fYR5ZIwgAAIBzO1Kf91i\/b63hY+Fce8qBynEuMY9kQQAAAJyf+v3x+j2Kc818Lqx27Ftyv+X4tjCP5EAAAACcn\/r9WP0eG\/rac17zfY9cgyP9xs7rYB7JgQAAADg\/9bscSA70+\/MIAAAAsh2tz3ut3\/fU8LHht3rPgcwjWRAAAADnp35vU79nrw+0dA3O8L\/x5pEcCAAAgPNTv8uB5EDnmUcAAACQZa1+bvX7739f36\/1+u39lv5vWUQtxyi\/z7Ln97PP5adrkGXn2D+yzqP8\/RHmEQAAAGR5Vv1eu49jS\/+3+rl2H0f5fZYz5UA\/XYMsZ8yBRphHAAAAkMV9HMu2\/n7s2PdRv3E\/UGzf9yPvTMaZRwAAAJCprKdrrcX32eu6HFkPZ8v3e\/S0PtAe5lHbeQQAAAAZ5vX0vLX+PqN+f1toLb7fY+m39vS7Z8xHfmup7WEetZ1HAAAA0EoUNfOZ6vfbeUVxrmeq38vz+umzjDzmDDnQD2P\/uL03j47NIwAAAMgU0\/e6Kmd4nud2PsX5TdfzW63fn\/E8z+18friW\/5f1XNie7Vb91sZXGfvHNJlHLeYRAAAAZIpr\/XxZaC2+X6vfY1a7F+e3qX6\/LLQW38e2a7n6W3v6ne975Boc6Xfj2M2jRtcSAAAAsoT6XQ7UZuzmUaNrCQAAAFlC\/S4HajN286jRtQQAAIAsMbVZt+Xoui5xsH7PXtcltl3LtHV6fmt9oL05kHl0\/FoCAABAlnhS\/b62HSv1+5EMRA7UTw40wjwCAACAV\/f+Q33+0+eV\/XZ93iPXwDwCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7zP1ayKgY=", + "data":"eJzt3c1x4zgaBmB2DHPoKwJzFLPeuyNyFJpoNom1y+IYTUMkKAL8AZ6nCiXJggQSjcv3NgkNAwBQy\/+OPgAAAAAAdiEHAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4MxulRoAAAAA57Em1\/kVNXkQAAAAwHWszYBSj7IgAAAAgHN7JgPK\/bssCAAAAOAc1u7zE98L9ivxN1kQAAAAwPk8s99zqeuBZEEAAAAA+3gms\/ls70P6eqD3Dd8JAAAAQB3P5jVjDhTfC\/Zr8ndZEAAAAMA5bMlq5vKerTmQLAgAAACgnK05Te0cSBYEAAAAsF2JjGaPHEgWBAAAAPC8UvnMXjmQLAgAAABgvZLZzJ45kCwIAAAAIF\/pXGbvHEgWBAAAALCsRiZzRA4kCwIAAACYJwcCAAAA6IMcCAAAAKAPciAAAACAPsiBAAAAAPogBwIAAADogxwIAAAAoA9yIAAAAIA+yIEAAAAA+iAHAgAAAOiDHAgAAACgD7VzoNeoyYEAAAAAjlMyh4kzn\/fJ60d\/lwMBAAAA7KPGdTlx3pPzdzkQAAAAQH217tGyPxAAAADAuciBAAAAAPogBwIAAADogxwIAAAAoA9yIAAAAIA+yIEAAAAA+iAHAgAAAOiDHAgAAACgD3IgAAAAgPa9V\/7u13ubPq85JgAAAAA\/1c5kXu4tfl6THAgAAADgpzDUz02OyIFC5TEAAAAArii+X2upre37MqRzoJfK4wIAAADw0zSfmWtb+i69LjkuAAAAAF9C9LzlHCg+TwAAAIBehftj7fvCUp\/d476w8fwAAAAA+N4n+pbZ1vZduh6o1rih3BQBAAAANCEMciAAAACAHoRBDgQAAADQC78bDwAAANAHORAAAABAH2rnJqkspyY5EAAAAEBa7dwkdT1QTXIgAAAAgJ\/C0GYOFCqPAQAAAHBF9gcCAAAA6MM0n5lrW\/ouvS45LgAAAABfQvS85RwoPk8AAACAXoX7Y+37wlKf3eO+sPH8AAAAAPjeJ\/qW2db2XboeqNa4odwUAQAAADQhDHIgAAAAgB6EQQ4EAAAA0Au\/Gw8AAADQBzkQAAAAQB9q5yapLKcmORAAAABAWu3cJHU9UE1yIAAAAICfwtBmDhQqjwEAAABwRfYHAgAAAOjDNJ+Za1v6Lr0uOS4AAAAAX0L0vOUcKD5PAAAAgF6F+2Pt+8JSn93jvrDx\/AAAAAD43if6ltnW9l26HqjWuKHcFAEAAAA0IQxyIAAAAIAehEEOBAAAANALvxsPAAAA0Ac5EAAAAEAfaucmqSynJjkQAAAAQFrt3CR1PVBNciAAAACAn8LQZg4UKo8BAAAAcEX2BwIAAADowzSfmWtb+i69LjkuAAAAAF9C9LzlHCg+TwAAAIBehftj7fvCUp\/d476w8fwAAAAA+N4n+pbZ1vZduh6o1rih3BQBAAAANCEMciAAAACAHoRBDgQAAADQC78bDwAAANAHORAAAABAH2rnJqkspyY5EAAAAEBa7dwkdT1QTXIgAAAAgJ\/C0GYOFCqPAQAAAHBF9gcCAAAA6MM0n5lrW\/ouvS45LgAAAABfQvS85RwoPk8AAACAXoX7Y+0cKHVv1x450Hh+AAAAAHzvE93a9UCh3BQBAAAANCEMciAAAACAHoRBDgQAAADQC78bDwAAANAHORAAAABAH2rnJqkspyY5EAAAAEBa7dwkdT1QTXIgAAAAgJ\/C0GYOFCqPAQAAAHBF9gcCAAAA6EOLvxsPAAAAwJcQPW85B4rPEwAAAKBX4f5Y+76w1Gf3uC9sPD8AAAAAvveJvmW2tX2XrgeqNW4oN0UAAAAATQiDHAgAAACgB2GQAwEAAAD0wu\/GAwAAAPRBDgQAAADQh9q5SSrLqUkOBAAAAJBWOzdJXQ9UkxwIAAAA4KcwtJkDhcpjAAAAAFyR\/YEAAAAA+jDNZ+balr5Lr0uOCwAAAMCXED1vOQeKzxMAAACgV+H+WPu+sNRn97gvbDw\/AAAAAL73ib5ltrV9l64HqjVuKDdFAAAAAE0IgxwIAAAAoAdhkAMBAADAVq\/D8HbVdvTcsS+\/Gw8AAADP+6hD3\/76eLxqe5cFdUUOBAAAAM+ZZkD\/\/f3Vxtf\/RG2u31+JfmOfR983\/c7xM3PfKQuidm6SynJqkgMBAACwlzgHijOY8XmcwfxTuF8qA5pmRqnnqbxIDtSP2rlJ6nqgmuRAAAAA7OHRtUBxHpO6dmeawTy6zudRDjR3jc+zOZAsqA9haDMHCpXHAAAAgFQOdOT1QDn3hU2zqrh\/zznQ57m\/RG06F0tzM81WUnvjnIX9gerpaR0BAAD05tkcKPcerq37A7ke6KfbxzmmWqp+n6vnp7b8Zvrepsc217b0XXpdcty9WUcAAAB9Ottvhdkf6E9xff6odj+6fr9N3q8hzBxrSzlQfJ4lWUcAAAB8inOgz6zlM1\/Z83Ga7Ty6fmgpP2opB3pUn1+lfq91jUeIjrXmfWGpz75UHjc+v1KsIwAAAFLOdk3Q2tZKBrRUn1+xfi9dx4eMsdYc17TvljnYMm4oN0XWEQAAAIteP+q7q7aj566EnPr8yvV7qT1wQsZYPedA1hEAAAC53u+5ytmvr7nKcebKrc+vXr\/fCsxVyBir1xzIOgIAAGCNq+QrVznOHGvq8xbq9xI1fO39gebmoOb+QFtYRwAAAKx1lXzlKse5ZG193kr9vrWGlwP9yToCAABgtGafnffJ41nbs8d59L9F7Jn6vKX6fUsNX3uPmFSWU9OW87GOAAAAiL1M6ri5Fucraz63d3v2OI\/+t6hprM+nWdmYf+XU7\/fPJzOQ2tnLGrWPJZVh1HSyuX37fOxhHQEAAMBVjfV56jqO+P2Zzw\/3zyczkLPU72FoMwcKlcfI1cs6AgAAaF3O\/R6592Ndqc\/Z7gerpafrOOwPVE9P6wgAAKBlOTlQzv1YV+tzxvvBnt23pbV9XZ7d22V6bHNtS9+l1yXHfYZ1ZI8gAACAR+RA57ClPm+xfs+t4cPMsbaUA8XnOcc6kgUBAADMkQOdg\/r9+fo9RMda876w1GdfKo8bn18O60gOBAAAMEcOdA7q9231e8gYa81xTftumYMt44aV82AdyYEAAADmyIHOQf0uB5IDHb+OAAAAWicHOt7W+rzV+n1NDR8yvqv1HMg6kgUBAAAsyanv9vot9z37jL93fQbq9zL1++d31dwfaG4Oau4PlMs6kgMBAAAskQMdT\/0uB5IDnWcdAQAAtGys31IZSvx+zndcqc9Z1D7Wrf++YxaRyjHi92tZ8\/21j+XRHNSy8tzfah1H\/P09rCMAAICWjfVb6v\/54\/dzvuNKfc5ir\/r92X\/fsX5OXccRv1\/LmXKgR3NQyxlzoB7WEQAAQMum91ClXud8x9X6nIXrOOblfn9Y0fdZR1wPFPL7vtU7kn7WEQAAQOt63R\/o6HkfLR1rifdr7+uytMfN1vfXmPuuNeNO+x6xP9Aa1lHZdQQAANCqnPruZaFdsc\/R8z5aOtbS79eo319mWon315j7rjXjrjnnLd8119awjsquIwAAgJaEqGaTA\/05H0fP\/5H1+3hcITrWM9Xv8XE9+tvcd60Zd80575EDPTj3t\/G5dbRtHQEAALQuDN\/7eqyp956pIc\/YZzoPR87\/Ge7nmc5DuD+e5X6e8XgezOW\/at0XtuZ1qXFT55c497dhsI5KrCMAAIDWhcz67kz5Tck+YTj2\/rBx\/m8zrcT7S\/++j+bh4+9Z9fttppV4P+TN5eJ3rRl32nfLHGwZN\/PcraNCcwkAANCykFnfnS2\/kQOp3x8dqxzIOpIDAQAApIXM+u5s+Y0cSP3+6FjlQNaRHAgAACAtZNZ3c\/uG5OwtctY+4UHduvf8H72vy6N5+Ph7Vv1ee1+XkDeXi9+1Zty5vkuvS46bee7WUaG5BAAAaFlI1H9Lr5+pIc\/aJzyoW4+c\/xr1+9LrR\/Pw8ffNGYgcqJ0cqId1BAAA0ItUfXf0MaWUyoGOPo89PTrf3Hl4Xfn3FpkD6wgAAKAl4\/0dr7+\/nx99TAAAAACU9++1Mr+\/nx99TAAAAACU9ffv7\/b6++fr\/yy0K\/b5bAAAAAC9WcqB\/l5oV+zztxwIAAAA6JAcCAAAAKAPciAAAACAPsiBAAAAAPogBwIAAADogxwIAAAAoA9LOdCZfu\/d78YDAAAAPG8uQzlbfiMHAgAAAHje6zC8rfk7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+\/s\/Iigt\/w==", "encoding":"base64", "height":312, "id":1, @@ -26,7 +19,7 @@ }, { "compression":"zlib", - "data":"eJzt3cFt41gSgGHmtOk4gj13AB0RA9izb45gMtBl9zITwJoYc\/o1ZUmUxHqqIr8P+LGzM+2mbQgPqIIoDgMAQD7\/laTAAAAAyMOcBkRxvgAAAORiTgOiOF8AAAByMacBUZwvAAAAuZjTgCjOFwAAgFzMaUAU5wsAAEAu5jQgivMFAAAgF3MaEMX5AgAAkIs5DYjifAEAAMjFnAZEcb4AAADkYk4DojhfAAAAcjGnAVGcLwAAALmY04AozhcAAIBczGlAFOcLAABALuY0IIrzBQAAIBdzGhDF+QIAAJCLOQ2I4nwBAADIxZwGRHG+AAAA5GJOA6I4XwAAAHIxpwFRnC8AAAC5mNOAKM4XAACAXMxpQBTnCwAAQC7mNCCK8wUAACAXcxoQxfkCAACQizkNiOJ8AQAAyMWcBkRxvgAAAORiTgOiOF8AAAByMacBUZwvAAAAuZjTgCjOFwAAgFzMaUAU5wsAAEAu5jQgivMFAAAgF3MaEMX5AgAAkIs5DYjifAEAAMjFnAZEcb4AAADkYk4DojhfAAAAcjGnAVGcLwAAALmY04AozhcAAIBczGlAFOcLAABALuY0IIrzBQAAIBdzGhDF+QIAAJCLOQ2I4nwBAADIxZwGRHG+AAAA5GJOA6I4XwAAAHIxpwFRnC8AAAC5mNOAKM4XAACAXMxpQBTnCwAAQC7mNCCK8wUAACAXcxoQxfkCAACQizkNiOJ8AQAAyMWcBkRxvgAAAORiTgOiOF8AAAByMacBUZwvAAAAuZjTgCjOFwAAgFzMaUAU5wsAAEAu5jQgivMFAAAgF3MaEMX5AgAAkIs5DYjifAEAAMjFnAZEcb4AAADkYk4DojhfAAAAcjGnAVGcLwAAALmY04AozhcAAIBczGm8B8axOV8AAAByMacd27SrOQX93afBLujonC8AAAC5mNOOq93RbL0Lav8+u6Djcr4AAADkYk47pu92M1vtgr77e+yCjsn5AgAAkIs57Xiu7WSe3QVd+3q7oONxvgAAAORiTjuWNbuYa7uc\/z34dfdcn\/1wvgAAAORiTjuOe3Yw974v6J4\/bxd0HM4XAACAXMxpx\/DI7mXtbueRe8nsgo7B+QIAAJCLOW3\/ntm53NrxPPN5QnZB++d8AQAAyMWctm9b7Fou7Xq2eL6YXdC+OV8AAAByMaft15Y7luXOZ6tnzE\/sgvbL+QIAAJCLOW2fInYrp8X\/bskuaJ+cLwAAALmY0\/YncqcSsQOa2QXtj\/MFAAAgF3PavvTYAdkFsZbzBQAAIBdz2n70fB+QXRBrOF8AAAByMaftw7Q7idrNRD4v7NLfaxe0D84XAACAXMxp+zDvTbbezdz6+6KuZw+0D84XAACAXMxp+9DuTbbazaz9eyKuZw+0D84XAACAXMxp+7Dcmzy7m7n367e+nj3QPjhfAAAAcjGn7cN3e5NHdzMZvs4eaB+cLwAAALmY0\/bh0t7k1e\/refTP2wPtg\/MFAAAgF3PaPlzbm7zyc34e\/XP2QPvgfAEAAMjFnLYPt\/Ymr3ru16P\/3R5oH5wvAAAAuZjT9mHN3uTS7mXrHdAW17MH2gfnCwAAQC7mtH1YuzdZ7mCidkDPXs8eaB+cLwAAALmY0\/bhnr3JafG\/0R65nj3QPjhfAAAAcjGn7cO9e5N7d0Af3xR5PXugfXC+AAAA5GJO24et90Brdj737IXsgY7J+QIAAJCLOW0fot8P9Cx7oGNyvgAAAORiTtsHeyAycr4AAADkYk7bB3sgMnK+AAAA5GJO2wd7IDJyvgAAAORiTtsHeyAycr4AAADkYk7bB3sgMnK+AAAA5GJO2wd7IDJyvgAAAORiTtsHeyAycr4AAADkYk7bB3sgMnK+AAAA5GJO2wd7IDJyvgAAAORiTqvv47MfX\/174+a\/9+OrofnnHtekNucLAABALua02qZdyfjZW2Bjc732fT09rmsXVJvzBQAAIBdzWn3te3MiurYHiryuHVB9zhcAAIBczGm1tTugCGv2QFHXtQuqz\/kCAACQizmtruU9YRHW3BcWdV33htXnfAEAAMjFnFaXPRDZOV8AAAByMafV1uO+sPZ5Yafh\/Hlh0delLucLAABALua0+t6\/6uF0+49soufPRBznCwAAQC7mtPrsgcjK+QIAAJCLOa0+eyCycr4AAADkYk6rb\/4snf\/c6I8NrrXFHmj6Pm59r5GfPUQ\/zhcAAIBczGn1zZ\/Z\/K8VPbsLenYP9MeF72uZz4jeB+cLAABALua0+tpnd0U1PyNsGM6fFxZ5TWpzvgAAAORiTqtt2pWMn70FNjbXa98P1OO6dkG1OV8AAAByMafVF\/3enGt7IO8H4hrnCwAAQC7mtNraHVCENXugqOvaBdXnfAEAAMjFnFbX8p6wCGvuC4u6rnvD6nO+AAAA5GJOq8seiOycLwAAALmY02rrcV9Y+7yw03D+vLDo61KX8wUAACAXc1p971\/1cLr9RzbR82cijvMFAAAgF3NaffZAZOV8AQAAyMWcVp89EFk5XwAAAHIxp9UX+Tk9S732QD1\/JuI4XwAAAHIxp9U3f2ZzDz33QD4juj7nCwAAQC7mtPraZ3dFNT8jbBjOnxcWeU1qc74AAADkYk6rbdqVjJ+9BTY212vfD9TjunZBtTlfAAAAcjGn1Rf93pxreyDvB+Ia5wsAAEAu5rTa2h1QhDV7oKjr2gXV53wBAADIxZxW1\/KesAhr7guLuq57w+pzvgAAAORiTqvLHojsnC8AAAC5mNNq63FfWPu8sNNw\/ryw6OtSl\/MFAAAgF3Nafe9f9XC6\/Uc20fNnIo7zBQAAIBdzWn32QGTlfAEAAMjFnFafPRBZOV8AAAByMafVF\/k5PUu99kA9fybiOF8AAAByMafVN39mcw8990A+I7o+5wsAAEAu5rT62md3RTU\/I2wYzp8XFnlNanO+AAAA5GJOq23alYyfvQU2Ntdr3w\/U47p2QbU5XwAAAHIxp9UX\/d6ca3sg7wfiGucLAABALua02todUIQ1e6Co69oF1ed8AQAAyMWcVtfynrAIa+4Li7que8Pqc74AAADkYk6ryx6I7JwvAAAAuZjTautxX1j7vLDTcP68sOjrUpfzBQAAIBdzWn3vX\/Vwuv1HNtHzZyKO8wUAACAXc1p99kBk5XwBAADIxZxWnz0QWTlfAAAAcjGn1Rf5OT1LvfZAPX8m4jhfAAAAcjGn1Td\/ZnMPPfdAPiO6PucLAABALua0+tpnd0U1PyNsGM6fFxZ5TWpzvgAAAORiTqtt2pWMn70FNjbXa98P1OO6dkG1OV8AAAByMafVF\/3enGt7IO8H4hrnCwAAQC7mtNraHVCENXugqOvaBdXnfAEAAMjFnFbX8p6wCGvuC4u6rnvD6nO+AAAA5GJOq8seiOycLwAAALmY02qbdiSRe6Dl88JOw\/nzwiLMP5MdUG3OFwAAgFzMafVF7oGWTrf\/yCZ6\/kzEcb4AAADkYk6rzx6IrJwvAAAAuZjT6rMHIivnCwAAQC7mtPoiP6dnqdceqOfPRBznCwAAQC7mtPrmz2zuoeceyGdE1+d8AQAAyMWcVl\/77K6o5meEDcP588Iir0ltzhcAAIBczGm1TbuScfj1eToRjc312vcD9biuXVBtzhcAAIBczGn1Rb8359oeyPuBuMb5AgAAkIs5rbZ2BxRhzR4o6rp2QfU5XwAAAHIxp9W1vCcswpr7wqKu696w+pwvAAAAuZjT6rIHIjvnCwAAQC7mtNp63BfWPi\/sNJw\/Lyz6utTlfAEAAMjFnFbf+1c9nG7\/kU30\/JmI43wBAADIxZxWnz0QWTlfAAAAcjGn1WcPRFbOFwAAgFzMafVFfk7PUq89UM+fiTjOFwAAgFzMafXNn9ncQ889kM+Irs\/5AgAAkIs5rb722V1Rzc8IG4bz54VFXpPanC8AAAC5mNNqm3Yl42dvgY3N9dr3A\/W4rl1Qbc4XAACAXMxp9UW\/N+faHsj7gbjG+QIAAJCLOa22dgcUYc0eKOq6dkH1OV8AAAByMafVtbwnLMKa+8KiruvesPqcLwAAALmY0+qyByI75wsAAEAu5rTaetwX1j4v7DScPy8s+rrU5XwBAADIxZxW3\/tXPZxu\/5FN9PyZiON8AQAAyMWcVp89EFk5XwAAAHIxp9VnD0RWzhcAAIBczGn1RX5Oz1KvPVDPn4k4zhcAAIBczGn1zZ\/Z3EPPPZDPiK7P+QIAAJCLOa2+9tldUc3PCBuG8+eFRV6T2pwvAAAAuZjTapt2JeNnb4GNzfXa9wP1uK5dUG3OFwAAgFz2MKe9D8PP7\/qxovGz7\/7OaQex5j0r7xfqKfq9Odf2QHt6P9DRX0cR9nC+AAAA7EnFOe3SvJ5pfu81z7c7oAhr9kBR143eBXkdxat4vgAAAOxZlTnt2pz+6N\/5dmN+f3v0Lx76zPLLe8IirLkvLOq6EfeGeR31VeV8AQAAOIrMc9rW8\/pS5Py+FDHL2wOt43X0OpnPFwAAgCPKOqdFzeytnvN7a+tdUPR9YfP9WVOn4fx5YdHXfYbX0WtlPV8AAACOKuOcFj23z141v8+2muF77gFOt\/\/IJjb6vXgdvVjG8wUAAODIss1pvWb3yavn98kWM7w90Ldf73WUQLbzBQAA4OgyzWk9Z\/dJhvl98uwMbw909rVeR0lkOl8AAADIM6f1nt0nWeb3yTMzfOTn9Cz12gM9+jN5HeXaBWU5XwAAAPhbhjntFbP7JNP8Pnl0hp8\/s7mHnnugez8j2uvob5l2QRnOFwAAAH7JMKe9YnafZJvfJ8\/sgSKbnxE2DOfPC4u85j28jn6xBwIAAOA7Gea0eX7\/EdSFHcbPNfN77x3IvfP7R\/O9RjU212vfD9TjuvfsgryOHn8dRclwvgAAAPDLq+e0eXYfv+bprWvn81Pzz+PK+b33DmQcHtsFRb4v59rvIPK6j+yAvI4efx1FePX5AgAAwO9ePadFv4fjx4X5\/Z73cTRf\/4\/I\/cc983u7A4qwZg8Udd17dkFeRznfE\/Tq8wUAAIDfvXpO6\/mZLqfFddbM74uv72Lt\/L68JyzCmveyRF33nnvDvI7O2QMBAACw9Mo5rffn+laZ3ydrZnh7oL95HV326l2QPRAAAEAu9kC15\/ce94XN92dNnYbzzziOvu4tXkeX2QMBAADQsgeqP7\/3nPUz3tPkdXSZPRAAAAAte6D687s9kNfRJfZAAAAAtF41p\/We3SeV5vfJ2hn+yHsgr6PbXrkLsgcCAADIxR6o\/vwe+Tk9S71+B2t\/Jq+j2+yBAAAAmGXZA\/1cdI+1X7vX+X3+zOYeeu6BMn5G9GSvr6MI9kAAAAC5vGpO+5zzf\/bq46vpuvM\/T\/9+zfzePitrGM6fldWjW3p8P6\/4HazZA3kdbfc6imAPBAAAkMur5rTxa36Orp3P2\/dxjCvn97H5d6dv\/nt07fW\/89Hhe3nV72Acbu+CvI62eR1FsQcCAADI5QjvB5qv2c7v97yPo\/n69vtP8z6OHu8recXvINv7gZrfwc\/2+nt5HUWwBwIAAMjlFXPaxzezdQ\/Lz3WZv4ePxb9v9yqLr+9qzT7k0vcapffnRN\/42b2OVrhnr7Y1eyAAAIBces9pH1\/vnZjvt+l57e8+33d+L0fzuS+\/3auz+Pqubt0fde17jdLrd7DiZ\/c6Wume++y2Zg8EAACQiz1Q3fndHsjraA17IAAAAGbuC6t9P0+P+8I+mk6L\/x\/FfWHbcV8YAAAAsyPNacv5\/YGvPzy\/A6+jexzpfAEAAKjgSHOa+f15fgdeR\/c40vkCAABQwZHmNPP78\/wOvI7ucaTzBQAAoIIjzWnm9+f5HXgd3eNI5wsAAEAFR5jTPn5\/jtPZ5\/mu+Pp\/PmM3+vORs6rwO9j686KXf5\/X0f2OcL4AXPKnJEmSpn7+2TznKbqPFf\/+z1\/98322z1j68U2X\/n1Et36n0dd\/5e\/A66jf60iSJEmSpIB+9mq8MduP51\/z2\/f6+d+vztXj63+X4SX+HXgdSZJS95ckSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIk3ej\/YDv6bA==", + "data":"eJzt3cFx40qWhlF40YaMO7Kgl900oCyiAb3WTha0B9zMbHoMGCFKmMoHiiRA4U8mkOdEfNGv66kKRYmREfc+ghwGACDlvyVJTQYAALA1swZAe5zNAABAglkDoD3OZgAAIMGsAdAeZzMAAJBg1gBoj7MZAABIMGsAtMfZDAAAJJg1ANrjbAYAABLMGgDtcTYDAAAJZg2A9jibAQCABLMGQHuczQAAQIJZA6A9zmYAACDBrAHQHmczAACQYNYAaI+zGQAASDBrALTH2QwAACSYNQDa42wGAAASzBoA7XE2AwAACWYNgPY4mwEAgASzBkB7nM0AAECCWQOgPc5mAAAgwawB0B5nMwAAkGDWAGiPsxkAAEgwawC0x9kMAAAkmDUA2uNsBgAAEswaAO1xNgMAAAlmDYD2OJsBAIAEswZAe5zNAABAglkDoD3OZgAAIMGsAdAeZzMAAJBg1gBoj7MZAABIMGsAtMfZDAAAJJg1ANrjbAYAABLMGgDtcTYDAAAJZg2A9jibAQCABLMGQHuczQAAQIJZA6A9zmYAACDBrAHQHmczAACQYNYAaI+zGQAASDBrALTH2QwAACSYNQDa42wGAAASzBoA7XE2AwAACWYNgPY4mwEAgASzBkB7nM0AAECCWQOgPc5mAAAgwawB0B5nMwAAkGDWAGiPsxkAAEgwawC0x9kMAAAkmDUA2uNsBgAAEswaAO1xNgMAAAlmDYD2OJsBAIAEswZAe5zNAABAglkDoD3OZgAAIMGsAdAeZzMAAJBg1gBoj7MZAABIMGsAtMfZDAAAJJg1ANrjbAYAABLMGgDtcTYDAAAJZg2A9jibAQCABLMGQHuczQAAQIJZA6A9zmYAACDBrAHQHmczAACQYNYAaI+zGQAASDBrwPPeg9E3ZzMAAJBg1oDnjLuaS+jPvgx2Qb1zNgMAAAlmDViv3NFsvQsq\/zy7oH45mwEAgASzBqzz3W5mq13Qd3+OXVCfnM0AAECCWQOWu7eT+eku6N7vtwvqj7MZAABIMGvAMkt2Mfd2Of\/z5O9bc32Ow9kMAAAkmDXgsTU7mLWvC1rz9XZB\/XA2AwAACWYNuO+Z3cvS3c4z95LZBfXB2QwAACSYNeC2n+xcHu14fvJ+QnZBx+dsBgAAEswa8L0tdi23dj1bfL6YXdCxOZsBAIAEswZc23LHMt\/5bPUZ8yO7oONyNgMAAAlmDfirxG7lMvvfLdkFHZOzGQAASDBrwB\/JnUpiBzSxCzoeZzMAAJBg1oDfauyA7IJYytkMAAAkmDWg7uuA7IJYwtkMAAAkmDXo3bg7Se1mkp8XduvPtQs6BmczAACQYNagd9PeZOvdzKM\/L3U9e6BjcDYDAAAJZg16V+5NttrNLP1zEtezBzoGZzMAAJBg1qB3873JT3cza3\/\/1tezBzoGZzMAAJBg1qB33+1Nnt3NtPD77IGOwdkMAAAkmDXo3a29yatf1\/Ps19sDHYOzGQAASDBr0Lt7e5NXvs\/Ps19nD3QMzmYAACDBrEHvHu1NXvW5X8\/+e3ugY3A2AwAACWYNerdkb3Jr97L1DmiL69kDHYOzGQAASDBr0Lule5P5Dia1A\/rp9eyBjsHZDAAAJJg16N2avcll9r9pz1zPHugYnM0AAECCWYPerd2brN0BfXxT8nr2QMfgbAYAABLMGvRu6z3Qkp3Pmr2QPVCfnM0AAECCWYPepV8P9FP2QH1yNgMAAAlmDXpnD0SLnM0AAECCWYPe2QPRImczAACQYNagd\/ZAtMjZDAAAJJg16J09EC1yNgMAAAlmDXpnD0SLnM0AAECCWYPe2QPRImczAACQYNagd\/ZAtMjZDAAAJJg16J09EC1yNgMAAAlmDXpnD0SLnM0AAECCWYOefXx2+urvGzf9uR9fDcU\/17gm++ZsBgAAEswa9GrclZw\/ewt2Lq5Xvq6nxnXtgvbN2QwAACSYNehZ+dqcRPf2QMnr2gHtn7MZAABIMGvQq3IHlLBkD5S6rl3Q\/jmbAQCABLMGPZrfE5aw5L6w1HXdG7Z\/zmYAACDBrEGP7IFonbMZAABIMGvQqxr3hZWfF3YZrj8vLH1d9svZDAAAJJg16Nn7VzVcHn\/JJmo+JnKczQAAQIJZg57ZA9EqZzMAAJBg1qBn9kC0ytkMAAAkmDXo2fReOv960L83uNYWe6Dx7\/Ho75p87yHqcTYDAAAJZg16Nr1n838t6Ke7oJ\/ugf594+81z3tEH4OzGQAASDBr0LPys7tSTZ8RNgzXnxeWvCb75mwGAAASzBr0atyVnD97C3Yurle+HqjGde2C9s3ZDAAAJJg16Fn6tTn39kBeD8Q9zmYAACDBrEGvyh1QwpI9UOq6dkH752wGAAASzBr0aH5PWMKS+8JS13Vv2P45mwEAgASzBj2yB6J1zmYAACDBrEGvatwXVn5e2GW4\/ryw9HXZL2czAACQYNagZ+9f1XB5\/CWbqPmYyHE2AwAACWYNemYPRKuczQAAQIJZg57ZA9EqZzMAAJBg1qBnyffpmau1B6r5mMhxNgMAAAlmDXo2vWdzDTX3QN4jev+czQAAQIJZg56Vn92VavqMsGG4\/ryw5DXZN2czAACQYNagV+Ou5PzZW7Bzcb3y9UA1rmsXtG\/OZgAAIMGsQc\/Sr825twfyeiDucTYDAAAJZg16Ve6AEpbsgVLXtQvaP2czAACQYNagR\/N7whKW3BeWuq57w\/bP2QwAACSYNeiRPRCtczYDAAAJZg16VeO+sPLzwi7D9eeFpa\/LfjmbAQCABLMGPXv\/qobL4y\/ZRM3HRI6zGQAASDBr0DN7IFrlbAYAABLMGvTMHohWOZsBAIAEswY9S75Pz1ytPVDNx0SOsxkAAEgwa9Cz6T2ba6i5B\/Ie0fvnbAYAABLMGvSs\/OyuVNNnhA3D9eeFJa\/JvjmbAQCABLMGvRp3JefP3oKdi+uVrweqcV27oH1zNgMAAAlmDXqWfm3OvT2Q1wNxj7MZAABIMGvQq3IHlLBkD5S6rl3Q\/jmbAQCABLMGPZrfE5aw5L6w1HXdG7Z\/zmYAACDBrEGP7IFonbMZAABIMGvQqxr3hZWfF3YZrj8vLH1d9svZDAAAJJg16Nn7VzVcHn\/JJmo+JnKczQAAQIJZg57ZA9EqZzMAAJBg1qBn9kC0ytkMAAAkmDXoWfJ9euZq7YFqPiZynM0AAECCWYOeTe\/ZXEPNPZD3iN4\/ZzMAAJBg1qBn5Wd3pZo+I2wYrj8vLHlN9s3ZDAAAJJg16NW4Kzl\/9hbsXFyvfD1QjevaBe2bsxkAAEgwa9Cz9Gtz7u2BvB6Ie5zNAABAglmDXpU7oIQle6DUde2C9s\/ZDAAAJJg16NH8nrCEJfeFpa7r3rD9czYDAAAJZg16ZA9E65zNAABAglmDXo07kuQeaP55YZfh+vPCEqbHZAe0b85mAAAgwaxBz5J7oLnL4y\/ZRM3HRI6zGQAASDBr0DN7IFrlbAYAABLMGvTMHohWOZsBAIAEswY9S75Pz1ytPVDNx0SOsxkAAEgwa9Cz6T2ba6i5B\/Ie0fvnbAYAABLMGvSs\/OyuVNNnhA3D9eeFJa\/JvjmbAQCABLMGvRp3Jefhz\/vpJDoX1ytfD1TjunZB++ZsBgAAEswa9Cz92px7eyCvB+IeZzMAAJBg1qBX5Q4oYckeKHVdu6D9czYDAAAJZg16NL8nLGHJfWGp67o3bP+czQAAQIJZgx7ZA9E6ZzMAAJBg1qBXNe4LKz8v7DJcf15Y+rrsl7MZAABIMGvQs\/evarg8\/pJN1HxM5DibAQCABLMGPbMHolXOZgAAIMGsQc\/sgWiVsxkAAEgwa9Cz5Pv0zNXaA9V8TOQ4mwEAgASzBj2b3rO5hpp7IO8RvX\/OZgAAIMGsQc\/Kz+5KNX1G2DBcf15Y8prsm7MZAABIMGvQq3FXcv7sLdi5uF75eqAa17UL2jdnMwAAkGDWoGfp1+bc2wN5PRD3OJsBAIAEswa9KndACUv2QKnr2gXtn7MZAABIMGvQo\/k9YQlL7gtLXde9YfvnbAYAABLMGvTIHojWOZsBAIAEswa9qnFfWPl5YZfh+vPC0tdlv5zNAABAglmDnr1\/VcPl8ZdsouZjIsfZDAAAJJg16Jk9EK1yNgMAAAlmDXpmD0SrnM0AAECCWYOeJd+nZ67WHqjmYyLH2QwAACSYNejZ9J7NNdTcA3mP6P1zNgMAAAlmDXpWfnZXqukzwobh+vPCktdk35zNAABAglmDXo27kvNnb8HOxfXK1wPVuK5d0L45mwEAgASzRt\/eh+HXd50WdP7suz9z3EEsec3K+41qSr82594e6EivB+r9eZTgbAYAABLMGn25Na+3NL\/XmufLHVDCkj1Q6rrpXZDnUZ6zGQAASDBrHN+9Of3ZP\/Ptwfz+9uwfPNSZ5ef3hCUsuS8sdd3EvWGeR3U5mwEAgASzxjFtPa\/PJef3ucQsbw+0jOfR6zibAQCABLPG8aRm9lLN+b209S4ofV\/YdH\/W2GW4\/ryw9HV\/wvPotZzNAABAglnjWNJz++RV8\/tkqxm+5h7g8vhLNrHR98Xz6MWczQAAQIJZ4zhqze6jV8\/voy1meHugb3+\/51EDnM0AAECCWeMYas7uoxbm99FPZ3h7oKvf63nUCGczAACQYNbYv9qz+6iV+X30kxk++T49c7X2QM8+Js+jtnZBzmYAACDBrLFvr5jdRy3N76NnZ\/jpPZtrqLkHWvse0Z5Hv7W0C3I2AwAACWtnjVszW29a+T68YnYftTa\/j36yB0o2fUbYMFx\/Xljymmt4Hv1hDwQAAByZPdBzWvk+TPP7KdSNHcavJfN77R3I2vn9o\/i7pjoX1ytfD1Tjumt2QZ5Hzz+PUuyBAACAhGf2QKlZcU+1sAeaZvfz1zy9deVjvBT\/fP7m35em+b32DuQ8PLcLSu0TTg++B8nrPrMD8jx6\/nmUYA8EAAAkPDNrTPPb1n+XPWhlBzRKv4bjdGN+Py2c30\/Fr5Xze3L\/sWZ+L3dACUv2QKnrrtkFeR61+ZogeyAAACDBHmide3NrbTXf0+Uyu86S+X32+6tYOr\/P7wlLWPJaltR119wb5nl0zR4IAAA4KnugdVrZA9V+X9+9zO+jJTO8PdBvnke3vXoXZA8EAAAk2AOtYw\/02xHm9xr3hU33Z41dhuv3OE5f9xHPo9vsgQAAgCOyB1rHHui3o8zvNWf9Fu9p8jy6zR4IAAA4InugdeyBfjvK\/G4P5Hl0iz0QAABwRPZA67SwB6o9u4\/2NL+Pls7wPe+BPI8ee+UuyB4IAABIsAdap4XPjTe\/P7Z0fk++T89cre\/B0sfkefSYPRAAAHA09kDrtLgH+jVrjaW\/96jz+\/SezTXU3AO1+B7Ro6M+jxLsgQAAgIRn90Cnrz6+Gn99+ufTwXv1HqjmY731810yv5eflTUM15+VVaNHavx9XvE9WLIH8jza7nmUYA8EAAAk\/OT1QOX8Vv53\/unfH7VX74FqfX8f\/Xwfze\/n4tcu3\/z7dOX1v\/NR4e\/yqu\/BeXi8C\/I82uZ5lGIPBAAAJPz09UDTr5XzXc3XGbyiV++Baj7W6Zrzn++S+b18HUU5v7f0Oo4aryt5xfegtdcDFd+DX+X1j\/I8SrAHAgAAEtbOGh\/fzHaj+ft+HNX02D9e9Hhvff\/T5j\/fW9+Hcq8y+\/1VLdmH3Pq7ptR+n+gHj93zaIE1e7Wt2QMBAAAJa2aNj6\/\/dj\/d71H+u172QOW9LrV3Qfe+\/2nfvb\/v\/Pswv89q9vurenR\/1L2\/a0qt78GCx+55tNCa++y2Zg8EAAAk2AOtYw\/0297nd3sgz6Ml7IEAAICjcV\/YOu4L++0I9\/PUuC\/so+gy+\/8p7gvbjvvCAACAo9lq1uhlD9Srn\/58a8\/vLfI98Dxawx4IAABIsAdiCfP7z\/keeB6tYQ8EAAAk2AOxhPn953wPPI\/WsAcCAAAS7IFYwvz+c74Hnkdr2AMBAAAJ9kDc8\/HXz3Fa\/f7Y5Xsip98fuVV7+B5s\/X7R8z\/P82g9eyCgZ\/+RJElNdSo+a+i7+e7UQS\/63o\/XrfYYb\/0sy1\/\/z5\/K58f\/f8bS6Ztu\/XqiBc\/laK\/8Hnge1XseSZIkSdKRO\/1tGN4+Z7bz8Oe\/6ZevBxp\/\/e3AjY\/\/Rd\/7X7U6P5jtz9e\/5y9\/1\/Nwf64+N\/A8Ttfw98DzSJLUdP8rSZKaatyDnL7muOFLuQc6PZj9dt\/fXv8zkCRJkiRJqtG4B\/nnZ6Ve3h9ofNz2QJIkSZIkqZfGPcg\/Ot0D\/cMeSJIkSZIkdZQ90Ot\/BpIkSZIkSTWyB3r9z0CSJEmSJKlG9kCv\/xlIkiRJkiTVyB7o9T8DSZIkSZKkGtkDvf5nIEmSJEmSVKOe90A+N16SJEmSJPXUuAf559ce6GMYfn187YDKfz4qeyBJkiRJktRT4x7k9LXzOX3TrV8\/TPZAkiRJkiSpk06v3sM00Kt\/BpIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkbdH\/AdA6cco=", "encoding":"base64", "height":312, "id":2, @@ -369,8 +362,8 @@ "type":"", "visible":true, "width":8, - "x":5595.33333333333, - "y":1612.66666666667 + "x":5592, + "y":1616 }, { "height":8, @@ -390,8 +383,8 @@ "type":"", "visible":true, "width":8, - "x":5396.66666666667, - "y":1712.66666666667 + "x":5400, + "y":1712 }, { "height":8, @@ -411,8 +404,8 @@ "type":"", "visible":true, "width":8, - "x":5633.33333333333, - "y":1714.66666666667 + "x":5632, + "y":1712 }, { "height":8, @@ -432,8 +425,8 @@ "type":"", "visible":true, "width":8, - "x":6001.33333333333, - "y":1708 + "x":6000, + "y":1712 }, { "height":8, @@ -453,8 +446,8 @@ "type":"", "visible":true, "width":8, - "x":5162, - "y":1709.33333333333 + "x":5160, + "y":1712 }, { "height":8, @@ -688,76 +681,44 @@ "y":1616 }, { - "gid":2147485887, - "height":56, - "id":2352, - "name":"", - "rotation":0, - "type":"", - "visible":true, - "width":34, - "x":4608, - "y":1752 - }, - { - "gid":2147489030, - "height":16, - "id":2353, - "name":"", - "rotation":0, - "type":"", - "visible":true, - "width":40, - "x":4576, - "y":1752 - }, - { - "gid":2147485887, - "height":56, - "id":2354, - "name":"", - "rotation":0, - "type":"", - "visible":true, - "width":34, - "x":4480, - "y":1752 - }, - { - "gid":2239, - "height":56, - "id":2356, - "name":"", - "rotation":0, - "type":"", - "visible":true, - "width":34, - "x":6584, - "y":1752 - }, - { - "gid":5382, - "height":16, - "id":2357, + "height":8, + "id":2516, "name":"", + "properties": + { + "vehicle":"stationtram" + }, + "propertytypes": + { + "vehicle":"string" + }, "rotation":0, "type":"", "visible":true, - "width":40, - "x":6488, - "y":1752 + "width":8, + "x":3936, + "y":1736 }, { - "gid":2239, - "height":56, - "id":2358, + "height":8, + "id":2555, "name":"", + "properties": + { + "npc":"human", + "typeName":"slut2goarcadehint" + }, + "propertytypes": + { + "npc":"string", + "typeName":"string" + }, "rotation":0, "type":"", "visible":true, - "width":34, - "x":6456, - "y":1752 + "width":8, + "x":4424, + "y":1720 }], "opacity":1, "type":"objectgroup", @@ -771,6 +732,26 @@ "id":12, "name":"objects n wiring", "objects":[ + { + "height":0, + "id":2530, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":8, + "y":24 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, { "height":0, "id":1701, @@ -6218,6 +6199,1566 @@ "width":48, "x":5688, "y":1176 + }, + { + "gid":2130, + "height":24, + "id":2359, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":3928, + "y":1672 + }, + { + "gid":2130, + "height":24, + "id":2360, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":3928, + "y":1768 + }, + { + "gid":2130, + "height":24, + "id":2361, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":3928, + "y":1856 + }, + { + "gid":3093, + "height":40, + "id":2362, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4384, + "y":1752 + }, + { + "gid":2147486741, + "height":40, + "id":2363, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":3880, + "y":1752 + }, + { + "height":0, + "id":2364, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":0, + "y":-72 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3936, + "y":1832 + }, + { + "height":0, + "id":2365, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":0, + "y":-80 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3936, + "y":1744 + }, + { + "height":0, + "id":2366, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-32, + "y":8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3968, + "y":1832 + }, + { + "height":0, + "id":2367, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-32, + "y":16 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3968, + "y":1736 + }, + { + "height":0, + "id":2368, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-32, + "y":16 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3968, + "y":1640 + }, + { + "gid":2597, + "height":8, + "id":2369, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":3968, + "y":1744 + }, + { + "gid":2597, + "height":8, + "id":2370, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":3968, + "y":1648 + }, + { + "gid":2597, + "height":8, + "id":2371, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":3968, + "y":1840 + }, + { + "gid":5047, + "height":8, + "id":2372, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4360.00568181818, + "y":1592.08522727273 + }, + { + "gid":5047, + "height":8, + "id":2373, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4288, + "y":1688 + }, + { + "gid":5047, + "height":8, + "id":2374, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4216, + "y":1592 + }, + { + "gid":5047, + "height":8, + "id":2375, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4144, + "y":1688 + }, + { + "gid":5047, + "height":8, + "id":2376, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4072, + "y":1592 + }, + { + "gid":5047, + "height":8, + "id":2377, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4000, + "y":1688 + }, + { + "gid":4997, + "height":8, + "id":2378, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4072, + "y":1688 + }, + { + "gid":4997, + "height":8, + "id":2379, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4000, + "y":1592 + }, + { + "gid":4997, + "height":8, + "id":2380, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4144, + "y":1592 + }, + { + "gid":4997, + "height":8, + "id":2381, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4216, + "y":1688 + }, + { + "gid":4997, + "height":8, + "id":2382, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4288, + "y":1592 + }, + { + "gid":4997, + "height":8, + "id":2383, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4360, + "y":1688 + }, + { + "gid":4802, + "height":8, + "id":2384, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4360, + "y":1784 + }, + { + "gid":4802, + "height":8, + "id":2385, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4288, + "y":1784 + }, + { + "gid":4802, + "height":8, + "id":2386, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4216, + "y":1784 + }, + { + "gid":4802, + "height":8, + "id":2387, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4144, + "y":1784 + }, + { + "gid":4802, + "height":8, + "id":2388, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4072, + "y":1784 + }, + { + "gid":4802, + "height":8, + "id":2389, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4000, + "y":1784 + }, + { + "gid":2147489151, + "height":24, + "id":2390, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4384, + "y":1848 + }, + { + "gid":2147489279, + "height":16, + "id":2391, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4024, + "y":1656 + }, + { + "gid":2147488946, + "height":16, + "id":2392, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4056, + "y":1848 + }, + { + "gid":2147488946, + "height":16, + "id":2393, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4128, + "y":1848 + }, + { + "gid":5298, + "height":16, + "id":2394, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4200, + "y":1848 + }, + { + "gid":5298, + "height":16, + "id":2395, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4272, + "y":1848 + }, + { + "gid":2147489198, + "height":16, + "id":2396, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4368, + "y":1848 + }, + { + "gid":2147486890, + "height":40, + "id":2397, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4264, + "y":1656 + }, + { + "gid":3313, + "height":32, + "id":2398, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4272.00568181818, + "y":1728.08522727273 + }, + { + "gid":3319, + "height":40, + "id":2399, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4048, + "y":1640 + }, + { + "gid":3337, + "height":24, + "id":2400, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4368, + "y":1736 + }, + { + "gid":3423, + "height":40, + "id":2401, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":3992, + "y":1656 + }, + { + "gid":3428, + "height":40, + "id":2402, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4336, + "y":1752 + }, + { + "gid":2147487153, + "height":32, + "id":2403, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4120, + "y":1656 + }, + { + "gid":3565, + "height":40, + "id":2404, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4224, + "y":1656 + }, + { + "gid":3584, + "height":24, + "id":2405, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4104, + "y":1624 + }, + { + "gid":3798, + "height":32, + "id":2406, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4008, + "y":1848 + }, + { + "gid":3801, + "height":56, + "id":2407, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":4352, + "y":1656 + }, + { + "gid":3815, + "height":32, + "id":2408, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4120, + "y":1728 + }, + { + "gid":4566, + "height":32, + "id":2409, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4296, + "y":1752 + }, + { + "gid":3679, + "height":24, + "id":2410, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4304, + "y":1624 + }, + { + "gid":3297, + "height":40, + "id":2411, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4088, + "y":1752 + }, + { + "gid":3253, + "height":24, + "id":2412, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4064, + "y":1736 + }, + { + "gid":3178, + "height":24, + "id":2413, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4152, + "y":1824 + }, + { + "gid":6008, + "height":24, + "id":2414, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":64, + "x":4192, + "y":1712 + }, + { + "gid":3788, + "height":8, + "id":2415, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":3984, + "y":1808 + }, + { + "gid":5383, + "height":16, + "id":2416, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4072, + "y":1752 + }, + { + "gid":2147489031, + "height":16, + "id":2417, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4296, + "y":1656 + }, + { + "gid":5383, + "height":16, + "id":2418, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4280, + "y":1752 + }, + { + "gid":2147489031, + "height":16, + "id":2419, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4360, + "y":1752 + }, + { + "gid":5383, + "height":16, + "id":2420, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4208, + "y":1656 + }, + { + "gid":2147489031, + "height":16, + "id":2421, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4152, + "y":1656 + }, + { + "gid":2147489030, + "height":16, + "id":2422, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":4072, + "y":1656 + }, + { + "gid":2139, + "height":36, + "id":2423, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":3976, + "y":1848 + }, + { + "gid":3640, + "height":24, + "id":2424, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4376, + "y":1824 + }, + { + "gid":3642, + "height":24, + "id":2425, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4056, + "y":1824 + }, + { + "gid":3958, + "height":32, + "id":2426, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":3976, + "y":1656 + }, + { + "gid":2147485887, + "height":56, + "id":2427, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":3840, + "y":1752 + }, + { + "gid":2147489030, + "height":16, + "id":2428, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":3808, + "y":1752 + }, + { + "gid":6007, + "height":40, + "id":2429, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":56, + "x":3984, + "y":1752 + }, + { + "gid":3260, + "height":8, + "id":2430, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4008, + "y":1712 + }, + { + "gid":4964, + "height":32, + "id":2431, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4040, + "y":1752 + }, + { + "gid":3260, + "height":8, + "id":2433, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":3976, + "y":1712 + }, + { + "gid":3827, + "height":16, + "id":2437, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4208, + "y":1728 + }, + { + "gid":4539, + "height":16, + "id":2438, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4000, + "y":1616 + }, + { + "gid":4576, + "height":24, + "id":2439, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":72, + "x":4152, + "y":1632 + }, + { + "gid":2450, + "height":16, + "id":2440, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":4336, + "y":1832 + }, + { + "gid":2147488801, + "height":16, + "id":2441, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":4336, + "y":1848 + }, + { + "gid":4557, + "height":8, + "id":2442, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":4360, + "y":1832 + }, + { + "gid":4483, + "height":8, + "id":2443, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":4304, + "y":1832 + }, + { + "gid":4483, + "height":8, + "id":2444, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":4216, + "y":1832 + }, + { + "gid":4483, + "height":8, + "id":2445, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":8, + "x":4080, + "y":1832 + }, + { + "gid":4344, + "height":24, + "id":2446, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":12, + "x":4032, + "y":1848 + }, + { + "gid":3268, + "height":32, + "id":2447, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":4152, + "y":1752 + }, + { + "gid":3642, + "height":24, + "id":2448, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4360, + "y":1816 + }, + { + "gid":3640, + "height":24, + "id":2449, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4248, + "y":1824 + }, + { + "gid":2147485887, + "height":56, + "id":2352, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":4608, + "y":1752 + }, + { + "gid":2147489030, + "height":16, + "id":2353, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":4576, + "y":1752 + }, + { + "gid":2147485887, + "height":56, + "id":2354, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":4480, + "y":1752 + }, + { + "gid":2239, + "height":56, + "id":2356, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":6584, + "y":1752 + }, + { + "gid":5382, + "height":16, + "id":2357, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":6488, + "y":1752 + }, + { + "gid":2239, + "height":56, + "id":2358, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":6456, + "y":1752 + }, + { + "height":0, + "id":2534, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-24, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2535, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-24, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2536, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-96, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2537, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-96, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2539, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-24, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2540, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-96, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2541, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-168, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2542, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-168, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2543, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-168, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":4392, + "y":1688 + }, + { + "height":0, + "id":2545, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":48, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2546, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":48, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2547, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":48, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2548, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":120, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2549, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":120, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2550, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":120, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2551, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":192, + "y":88 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2552, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":192, + "y":-8 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "height":0, + "id":2553, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":192, + "y":-104 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 + }, + { + "gid":2717, + "height":16, + "id":2556, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":4384, + "y":1696 + }, + { + "gid":2717, + "height":16, + "id":2557, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":3952, + "y":1696 + }, + { + "height":0, + "id":2558, + "name":"", + "polyline":[ + { + "x":0, + "y":0 + }, + { + "x":-64, + "y":24 + }], + "rotation":0, + "type":"", + "visible":true, + "width":0, + "x":3960, + "y":1688 }], "opacity":1, "type":"objectgroup", @@ -6226,87 +7767,87 @@ "y":0 }], "nextlayerid":18, - "nextobjectid":2359, + "nextobjectid":2559, "orientation":"orthogonal", "renderorder":"right-down", - "tiledversion":"1.3.5", + "tiledversion":"1.8.0", "tileheight":8, "tilesets":[ { "firstgid":1, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/materials.json" + "source":"..\/..\/tilesets\/packed\/materials.json" }, { "firstgid":198, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/supports.json" + "source":"..\/..\/tilesets\/packed\/supports.json" }, { "firstgid":235, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/miscellaneous.json" + "source":"..\/..\/tilesets\/packed\/miscellaneous.json" }, { "firstgid":259, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/liquids.json" + "source":"..\/..\/tilesets\/packed\/liquids.json" }, { "firstgid":287, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-race\/generic.json" + "source":"..\/..\/tilesets\/packed\/objects-by-race\/generic.json" }, { "firstgid":2271, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-race\/ancient.json" + "source":"..\/..\/tilesets\/packed\/objects-by-race\/ancient.json" }, { "firstgid":2434, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/crafting.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/crafting.json" }, { "firstgid":2514, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/wire.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/wire.json" }, { "firstgid":2736, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-type\/teleporter.json" + "source":"..\/..\/tilesets\/packed\/objects-by-type\/teleporter.json" }, { "firstgid":2763, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/huge-objects.json" + "source":"..\/..\/tilesets\/packed\/huge-objects.json" }, { "firstgid":2864, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-colonytag\/outpost.json" + "source":"..\/..\/tilesets\/packed\/objects-by-colonytag\/outpost.json" }, { "firstgid":2968, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-colonytag\/apexresearchlab.json" + "source":"..\/..\/tilesets\/packed\/objects-by-colonytag\/apexresearchlab.json" }, { "firstgid":3019, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/door.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/door.json" }, { "firstgid":3151, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/decorative.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/decorative.json" }, { "firstgid":4592, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/light.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/light.json" }, { "firstgid":5050, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-race\/novakid.json" + "source":"..\/..\/tilesets\/packed\/objects-by-race\/novakid.json" }, { "firstgid":5114, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/furniture.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/furniture.json" }, { "firstgid":5468, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-category\/storage.json" + "source":"..\/..\/tilesets\/packed\/objects-by-category\/storage.json" }, { "firstgid":5702, - "source":"..\/..\/..\/..\/..\/Starbound\/assets\/packed\/tilesets\/packed\/objects-by-race\/human.json" + "source":"..\/..\/tilesets\/packed\/objects-by-race\/human.json" }, { "firstgid":5990, diff --git a/interface/sexbound/common/custombutton.lua b/interface/sexbound/common/custombutton.lua index f9fbb0e8..20af2f7e 100644 --- a/interface/sexbound/common/custombutton.lua +++ b/interface/sexbound/common/custombutton.lua @@ -255,4 +255,8 @@ function CustomButton:setNewImage(image, imageOffset) else self.config.image = nil end +end + +function CustomButton:setEnabled(enabled) + self.config.enabled = not not enabled end \ No newline at end of file diff --git a/interface/sexbound/customizer/customizer.config b/interface/sexbound/customizer/customizer.config index 3f4d34b3..056c2c4b 100644 --- a/interface/sexbound/customizer/customizer.config +++ b/interface/sexbound/customizer/customizer.config @@ -190,6 +190,80 @@ "hAnchor" : "left", "width" : 50, "value" : "^shadow;2000", + "color" : [255, 255, 255] + }, + "canBeDefeatedLabel" : { + "fontSize": 10, + "type": "label", + "position": [20, 132], + "hAnchor": "left", + "vAnchor": "top", + "width": 210, + "value": "^shadow;You currently ^orange;will not^reset;^shadow; be fuckable after being defeated.", + "wrapWidth": 210, + "color": [255, 255, 255] + }, + "canBeDefeatedConfirm": { + "type": "button", + "base": "/interface/sexbound/customizer/smallbutton.png", + "hover": "/interface/sexbound/customizer/smallbutton-hover.png", + "pressed": "/interface/sexbound/customizer/smallbutton-hover.png", + "disabledImage": "/interface/sexbound/customizer/smallbutton-disabled.png", + "pressedOffset": [1,-1], + "caption": "Change", + "fontColor": [255, 255, 255], + "textAlign": "center", + "position": [240, 121] + }, + "canBeDefeatedPriceIcon": { + "type" : "image", + "file" : "/interface/sexbound/customizer/icons/sexbux.png", + "position" : [300, 123] + }, + "canBeDefeatedPrice": { + "type" : "label", + "fontSize" : 8, + "position" : [310, 123], + "hAnchor" : "left", + "width" : 50, + "value" : "^shadow;0", + "color" : [255, 255, 255] + }, + "canDefeatOthersLabel" : { + "fontSize": 10, + "type": "label", + "position": [20, 104], + "hAnchor": "left", + "vAnchor": "top", + "width": 210, + "value": "^shadow;Supported enemies currently ^orange;will not^reset;^shadow; be fuckable after defeating them.", + "wrapWidth": 210, + "color": [255, 255, 255] + }, + "canDefeatOthersConfirm": { + "type": "button", + "base": "/interface/sexbound/customizer/smallbutton.png", + "hover": "/interface/sexbound/customizer/smallbutton-hover.png", + "pressed": "/interface/sexbound/customizer/smallbutton-hover.png", + "disabledImage": "/interface/sexbound/customizer/smallbutton-disabled.png", + "pressedOffset": [1,-1], + "caption": "Change", + "fontColor": [255, 255, 255], + "textAlign": "center", + "position": [240, 93] + }, + "canDefeatOthersPriceIcon": { + "type" : "image", + "file" : "/interface/sexbound/customizer/icons/sexbux.png", + "position" : [300, 95] + }, + "canDefeatOthersPrice": { + "type" : "label", + "fontSize" : 8, + "position" : [310, 95], + "hAnchor" : "left", + "width" : 50, + "value" : "^shadow;0", "color" : [255, 255, 255] } } @@ -395,7 +469,9 @@ "subGenderSelector.down", "subGenderConfirm", "sterilizeConfirm", - "infertileConfirm" + "infertileConfirm", + "canBeDefeatedConfirm", + "canDefeatOthersConfirm" ], "scripts" : [ diff --git a/interface/sexbound/customizer/customizergeneral.lua b/interface/sexbound/customizer/customizergeneral.lua index e3e62b41..472c9647 100644 --- a/interface/sexbound/customizer/customizergeneral.lua +++ b/interface/sexbound/customizer/customizergeneral.lua @@ -12,7 +12,9 @@ function Customizer.General:new(parent) currentSubGenderIndex = 1, subGenderList = {}, sterilized = false, - infertile = false + infertile = false, + canBeDefeated = false, + canDefeatOthers = false }, Customizer.General_mt) end @@ -38,6 +40,16 @@ function Customizer.General:init() if self.infertile == nil then self.infertile = false end if self.infertile then widget.setText("generalTab.infertileLabel", "^shadow;You currently ^orange;are^reset;^shadow; infertile.") else widget.setButtonEnabled("generalTab.infertileConfirm", false) end + + self.canBeDefeated = self._parent.config.canBeDefeated + if self.canBeDefeated == nil then self.canBeDefeated = false end + if self.canBeDefeated then widget.setText("generalTab.canBeDefeatedLabel", "^shadow;You currently ^orange;will^reset;^shadow; be fuckable after being defeated.") + else widget.setButtonEnabled("generalTab.canBeDefeatedLabel", false) end + + self.canDefeatOthers = self._parent.config.canDefeatOthers + if self.canDefeatOthers == nil then self.canDefeatOthers = false end + if self.canDefeatOthers then widget.setText("generalTab.canDefeatOthersLabel", "^shadow;Supported enemies currently ^orange;will^reset;^shadow; be fuckable after defeating them.") + else widget.setButtonEnabled("generalTab.canDefeatOthersLabel", false) end end function Customizer.General:handleMessage(message) @@ -162,4 +174,26 @@ function Customizer.General:makeFertile() world.sendEntityMessage(player.id(), "Sexbound:Status:RemoveStatus", "infertile") self.infertile = false +end + +function Customizer.General:toggleCanBeDefeated() + if self.canBeDefeated then + widget.setText("generalTab.canBeDefeatedLabel", "^shadow;You currently ^orange;will not^reset;^shadow; be fuckable after being defeated.") + world.sendEntityMessage(player.id(), "Sexbound:Status:RemoveStatus", "canBeDefeated") + else + widget.setText("generalTab.canBeDefeatedLabel", "^shadow;You currently ^orange;will^reset;^shadow; be fuckable after being defeated.") + world.sendEntityMessage(player.id(), "Sexbound:Status:AddStatus", "canBeDefeated") + end + self.canBeDefeated = not self.canBeDefeated +end + +function Customizer.General:toggleCanDefeatOthers() + if self.canDefeatOthers then + widget.setText("generalTab.canDefeatOthersLabel", "^shadow;Supported enemies currently ^orange;will not^reset;^shadow; be fuckable after defeating them.") + world.sendEntityMessage(player.id(), "Sexbound:Status:RemoveStatus", "canDefeatOthers") + else + widget.setText("generalTab.canDefeatOthersLabel", "^shadow;Supported enemies currently ^orange;will^reset;^shadow; be fuckable after defeating them.") + world.sendEntityMessage(player.id(), "Sexbound:Status:AddStatus", "canDefeatOthers") + end + self.canDefeatOthers = not self.canDefeatOthers end \ No newline at end of file diff --git a/interface/sexbound/customizer/customizerui.lua b/interface/sexbound/customizer/customizerui.lua index faa26d52..6a914f64 100644 --- a/interface/sexbound/customizer/customizerui.lua +++ b/interface/sexbound/customizer/customizerui.lua @@ -43,4 +43,19 @@ end function sterilizeConfirm() if not self.customizer._inited then return end self.customizer.tabs["General"]:sterilize() +end + +function infertileConfirm() + if not self.customizer._inited then return end + self.customizer.tabs["General"]:makeFertile() +end + +function canBeDefeatedConfirm() + if not self.customizer._inited then return end + self.customizer.tabs["General"]:toggleCanBeDefeated() +end + +function canDefeatOthersConfirm() + if not self.customizer._inited then return end + self.customizer.tabs["General"]:toggleCanDefeatOthers() end \ No newline at end of file diff --git a/interface/sexbound/customizer/icons/addon_mod_ahego.png b/interface/sexbound/customizer/icons/addon_mod_ahego.png index 308a32c7..de4e5d42 100644 Binary files a/interface/sexbound/customizer/icons/addon_mod_ahego.png and b/interface/sexbound/customizer/icons/addon_mod_ahego.png differ diff --git a/interface/sexbound/defeat.config b/interface/sexbound/defeat.config new file mode 100644 index 00000000..07ef4cb2 --- /dev/null +++ b/interface/sexbound/defeat.config @@ -0,0 +1,38 @@ +{ + "scripts" : ["/interface/sexbound/defeat.lua"], + + "scriptDelta" : 2, + + "scriptWidgetCallbacks" : [], + + "canvasClickCallbacks" : { + "interface" : "canvasClickEvent" + }, + + "canvasKeyCallbacks" : { + "interface" : "canvasKeyEvent" + }, + + "gui" : { + "panefeature" : { + "type" : "panefeature", + "anchor" : "center", + "positionLocked" : true + }, + "background" : { + "type" : "background", + "fileHeader" : "", + "fileBody" : "/interface/sexbound/defeatbody.png", + "fileFooter": "" + }, + "interface" : { + "type" : "canvas", + "rect" : [0, 0, 10, 10], + "captureKeyboardEvents" : true, + "captureMouseEvents" : true, + "zlevel" : 1 + } + }, + + "config" : {} +} \ No newline at end of file diff --git a/interface/sexbound/defeat.lua b/interface/sexbound/defeat.lua new file mode 100644 index 00000000..ea58504b --- /dev/null +++ b/interface/sexbound/defeat.lua @@ -0,0 +1,27 @@ +require "/scripts/messageutil.lua" + +function init() + self.config = config.getParameter("config") + self.canvas = widget.bindCanvas("interface") + widget.focus("interface") +end + +function update(dt) + if not status.statusProperty("sexbound_defeated") then + pane.dismiss() + end + + self.canvas:clear() +end + +function canvasClickEvent(position, button, isButtonDown) + +end + +function canvasKeyEvent(key, isKeyDown) + +end + +function dismissed() + world.sendEntityMessage(player.id(), "SexboundDefeat:Breakout") +end \ No newline at end of file diff --git a/interface/sexbound/defeatbody.png b/interface/sexbound/defeatbody.png new file mode 100644 index 00000000..5d051145 Binary files /dev/null and b/interface/sexbound/defeatbody.png differ diff --git a/interface/statuses/lustia.png b/interface/statuses/lustia.png new file mode 100644 index 00000000..e280bc8b Binary files /dev/null and b/interface/statuses/lustia.png differ diff --git a/items/generic/other/debug_birthingpill.consumable b/items/generic/other/debug_birthingpill.consumable new file mode 100644 index 00000000..5027388f --- /dev/null +++ b/items/generic/other/debug_birthingpill.consumable @@ -0,0 +1,18 @@ +{ + "itemName" : "debug_birthingpill", + "price" : 1, + "rarity" : "Common", + "category" : "medicine", + "inventoryIcon" : "debug_birthingpill.png", + "description" : "Debug version of the Birthing Pill without downsides.", + "shortdescription" : "Birthing Pill (Debug)", + "maxStack" : 1000, + "effects" : [ [ + { + "effect" : "debug_birthingpill", + "duration" : 5 + } + ] ], + "emote" : "", + "emitters" : [ "drinking" ] +} diff --git a/items/generic/other/debug_birthingpill.png b/items/generic/other/debug_birthingpill.png new file mode 100644 index 00000000..e94c30dd Binary files /dev/null and b/items/generic/other/debug_birthingpill.png differ diff --git a/items/generic/other/debug_hyperfertilitypil.consumable b/items/generic/other/debug_hyperfertilitypil.consumable new file mode 100644 index 00000000..4116c903 --- /dev/null +++ b/items/generic/other/debug_hyperfertilitypil.consumable @@ -0,0 +1,14 @@ +{ + "itemName" : "debug_hyperfertilitypill", + "price" : 1, + "rarity" : "Legendary", + "category" : "medicine", + "inventoryIcon" : "debug_hyperfertilitypill.png", + "description" : "Debug version of the Hyper Fertility Pill without downsides!", + "shortdescription" : "Fertility Pill (Debug)", + "effects" : [ + [ "sexbound_debug_hyper_fertility" ] + ], + "emote" : "", + "emitters" : [ "drinking" ] +} diff --git a/items/generic/other/debug_hyperfertilitypill.png b/items/generic/other/debug_hyperfertilitypill.png new file mode 100644 index 00000000..d7538b63 Binary files /dev/null and b/items/generic/other/debug_hyperfertilitypill.png differ diff --git a/items/generic/other/sexbound_birthspeedpill.consumable b/items/generic/other/sexbound_birthspeedpill.consumable new file mode 100644 index 00000000..666cf3ec --- /dev/null +++ b/items/generic/other/sexbound_birthspeedpill.consumable @@ -0,0 +1,18 @@ +{ + "itemName" : "sexbound_birthspeedpill", + "price" : 100, + "rarity" : "Common", + "category" : "medicine", + "inventoryIcon" : "sexbound_birthspeedpill.png", + "description" : "Swallow this to speed up the birthing process.", + "shortdescription" : "Speed Birth Pill", + "maxStack" : 1000, + "effects" : [ [ + { + "effect" : "sexbound_birthspeedpill", + "duration" : 840 + } + ] ], + "emote" : "", + "emitters" : [ "drinking" ] +} diff --git a/items/generic/other/sexbound_birthspeedpill.png b/items/generic/other/sexbound_birthspeedpill.png new file mode 100644 index 00000000..e1cef360 Binary files /dev/null and b/items/generic/other/sexbound_birthspeedpill.png differ diff --git a/npcs/base.npctype.patch b/npcs/base.npctype.patch index b2960dcb..52db7bcc 100644 --- a/npcs/base.npctype.patch +++ b/npcs/base.npctype.patch @@ -77,6 +77,12 @@ } }, + { + "op": "add", + "path": "/statusControllerSettings/stats/arousalMult", + "value": { "baseValue": 1.0 } + }, + { "op" : "add", "path" : "/statusControllerSettings/resources/arousal", diff --git a/npcs/slut2goarcadehint.npctype b/npcs/slut2goarcadehint.npctype new file mode 100644 index 00000000..e33110ff --- /dev/null +++ b/npcs/slut2goarcadehint.npctype @@ -0,0 +1,21 @@ +{ + "type" : "slut2goarcadehint", + "baseType" : "slut2gohooker", + + "npcname" : "Arcade Hooker", + + "persistent" : true, + + "scriptConfig" : { + "behavior" : "tutorial", + + "dialog" : { + "greeting" : "/dialog/lustiaarcadehintconverse.config:greeting", + "converse" : "/dialog/lustiaarcadehintconverse.config:converse" + }, + + "questGenerator" : { + "enableParticipation" : false + } + } +} \ No newline at end of file diff --git a/objects/miscellaneous/sexscapeshops/arcadesign_off.object b/objects/miscellaneous/sexscapeshops/arcadesign_off.object new file mode 100644 index 00000000..3b7244ea --- /dev/null +++ b/objects/miscellaneous/sexscapeshops/arcadesign_off.object @@ -0,0 +1,34 @@ +{ + "objectName" : "arcadesign_off", + "colonyTags" : ["hylotl","hylotloceancity","electronic","light"], + "rarity" : "Common", + "category" : "decorative", + "price" : 150, + "lightColor" : [235, 180, 65], + + "description" : "An arcade sign. Sadly, it seems to be off.", + "shortdescription" : "Arcade Sign (off)", + "race" : "hylotl", + + "apexDescription" : "An arcade! Sadly, it seems to be closed.", + "avianDescription" : "An arcade. Too bad it seems to be closed!", + "floranDescription" : "Arcade! It not glowing though!", + "glitchDescription" : "Wanting. An amusement arcade! To bad it's closed.", + "humanDescription" : "I love arcades! Too bad it seems to be closed.", + "hylotlDescription" : "Hmm, it's been a while since my last arcade trip. Sadly it's closed.", + "novakidDescription" : "An arcade? Would be mighta fun if it wasn't closed.", + + "inventoryIcon" : "arcadesignicon_off.png", + "orientations" : [ + { + "image" : "arcadesign_off.png", + "imagePosition" : [-32, -8], + "frames" : 1, + "animationCycle" : 1, + + "spaceScan" : 0.1, + "anchors" : [ "background" ] + + } + ] +} diff --git a/objects/miscellaneous/sexscapeshops/arcadesign_off.png b/objects/miscellaneous/sexscapeshops/arcadesign_off.png new file mode 100644 index 00000000..bcb3dd6f Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/arcadesign_off.png differ diff --git a/objects/miscellaneous/sexscapeshops/arcadesignicon_off.png b/objects/miscellaneous/sexscapeshops/arcadesignicon_off.png new file mode 100644 index 00000000..41422c8f Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/arcadesignicon_off.png differ diff --git a/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.object b/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.object new file mode 100644 index 00000000..51955c62 --- /dev/null +++ b/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.object @@ -0,0 +1,55 @@ +{ + "objectName" : "sexbound_cardshop_empty", + "shortdescription" : "Card Sex Shop", + "description" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "colonyTags" : ["sexbound", "sex", "commerce", "mechanical", "odd"], + "rarity" : "Uncommon", + "category" : "other", + "race" : "generic", + "price" : 500, + "printable" : false, + + "apexDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "avianDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "floranDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "glitchDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "humanDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "hylotlDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + "novakidDescription" : "A stall that, one day, will sell Monster Girl Cards and related items.", + + "inventoryIcon" : "sexbound_sexshopicon_empty.png", + + "offeredQuests" : [ + ], + "turnInQuests" : [ + ], + + "uniqueId" : "cardshop_empty", + + "orientations" : [ + { + "imageLayers" : [ { "image" : "sexbound_cardshopflip_empty.png" } ], + + "imagePosition" : [-28, 0], + "frames" : 1, + "animationCycle" : 1.0, + + "direction" : "left", + + "spaceScan" : 0.1, + "anchors" : [ "bottom" ] + }, + { + "imageLayers" : [ { "image" : "sexbound_cardshop_empty.png" } ], + + "imagePosition" : [-28, 0], + "frames" : 1, + "animationCycle" : 1.0, + + "direction" : "right", + + "spaceScan" : 0.1, + "anchors" : [ "bottom" ] + } + ] +} diff --git a/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.png b/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.png new file mode 100644 index 00000000..34e3a4c9 Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/sexbound_cardshop_empty.png differ diff --git a/objects/miscellaneous/sexscapeshops/sexbound_cardshopflip_empty.png b/objects/miscellaneous/sexscapeshops/sexbound_cardshopflip_empty.png new file mode 100644 index 00000000..ca2e2489 Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/sexbound_cardshopflip_empty.png differ diff --git a/objects/miscellaneous/sexscapeshops/sexbound_cardshopportrait_empty.png b/objects/miscellaneous/sexscapeshops/sexbound_cardshopportrait_empty.png new file mode 100644 index 00000000..7687da2b Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/sexbound_cardshopportrait_empty.png differ diff --git a/objects/miscellaneous/sexscapeshops/sexbound_cardshoptiled_empty.png b/objects/miscellaneous/sexscapeshops/sexbound_cardshoptiled_empty.png new file mode 100644 index 00000000..34e3a4c9 Binary files /dev/null and b/objects/miscellaneous/sexscapeshops/sexbound_cardshoptiled_empty.png differ diff --git a/objects/sexbound_node/sexbound_main_node.object.patch b/objects/sexbound_node/sexbound_main_node.object.patch new file mode 100644 index 00000000..d776f47e --- /dev/null +++ b/objects/sexbound_node/sexbound_main_node.object.patch @@ -0,0 +1,7 @@ +[ + { + "op" : "add", + "path" : "/health", + "value" : 100 + } +] \ No newline at end of file diff --git a/objects/sexbound_node/sexbound_main_node_centered.object.patch b/objects/sexbound_node/sexbound_main_node_centered.object.patch new file mode 100644 index 00000000..d776f47e --- /dev/null +++ b/objects/sexbound_node/sexbound_main_node_centered.object.patch @@ -0,0 +1,7 @@ +[ + { + "op" : "add", + "path" : "/health", + "value" : 100 + } +] \ No newline at end of file diff --git a/player.config.patch b/player.config.patch index 1169a979..8a68f03b 100644 --- a/player.config.patch +++ b/player.config.patch @@ -58,6 +58,12 @@ "path": "/statusControllerSettings/stats/climaxThreshold", "value": { "baseValue": 0.5 } }, + + { + "op": "add", + "path": "/statusControllerSettings/stats/arousalMult", + "value": { "baseValue": 1.0 } + }, { "op": "add", diff --git a/scripts/sexbound/lib/sexbound.lua b/scripts/sexbound/lib/sexbound.lua index b7a5990a..599e1e3c 100644 --- a/scripts/sexbound/lib/sexbound.lua +++ b/scripts/sexbound/lib/sexbound.lua @@ -44,7 +44,9 @@ function Sexbound.new(maxActors) _globalActorId = 0, _uiSyncTokens = {positions=0}, _containsPlayer = false, - _sexMusicListeners = {} + _sexMusicListeners = {}, + _containsDefeated = false, + _playerControl = false }, Sexbound_mt) -- Store UUID of the entity running this instance of Sexbound. @@ -336,23 +338,44 @@ function Sexbound:addActor(actorConfig, store) --actor:getApparel():sync() --actor:initPlugins() - - if actor:getEntityType() == "player" then self._containsPlayer = true end - + self._positions:filterPositions(self._actors) self._UI:refresh() - actor:openUI() + + if actor:getEntityType() == "player" then + self._containsPlayer = true + -- Open UI if not defeated or is allowed to while defeated. + if not actor:getStatus():hasStatus("sexbound_defeated") or actor:getStatus():hasStatus("can_use_sex_ui_defeated") then + actor:openUI() + self._playerControl = true + end + end + if self._containsDefeated then + -- Disable node interaction if an actor joins a defeat node + object.setInteractive(false) + end -- Resort actors based on changed environment self:helper_reassignAllRoles() if self._config.position.forceJoin then self._positions:switchPosition(self._config.position.forceJoin) - -- If we only have NPCs, try to initiate sex (switch from idle to a random available position) - elseif not self._containsPlayer and self._config.sex.npcStartSex then - self._positions:switchRandomSexPosition(true) + -- If we have no controlling player, try to initiate sex (switch from idle to a random available position) + elseif not self._playerControl and self._config.sex.npcStartSex then + local success = self._positions:switchRandomSexPosition(true) + -- Smash the defeat node if there's no valid position to avoid boring standing around + if not success and self._containsDefeated then + self:forEachActor(function(index,actor) + if actor:getStatus():hasStatus("sexbound_defeated") then + world.sendEntityMessage(actor:getEntityId(), "SexboundDefeat:Untransform") + end + end) + end end + -- Mark node as a defeat node. + if actor:getStatus():hasStatus("sexbound_defeated") then self._containsDefeated = true end + -- Reset all actors to refresh their appearances self:resetAllActors() @@ -376,10 +399,14 @@ function Sexbound:removeActor(entityId) self:getLog():debug("Officially removed actor for entity "..tostring(entityId).." - new count: "..#self._actors) local containsPlayer = false + local containsDefeated = false for _,a in ipairs(self._actors) do - if a:getEntityType() == "player" then containsPlayer = true break end + if a:getEntityType() == "player" then containsPlayer = true end + if a:getStatus():hasStatus("sexbound_defeated") then containsDefeated = true end end + if not containsDefeated then object.setInteractive(true) end self._containsPlayer = containsPlayer + self._containsDefeated = containsDefeated self._positions:filterPositions(self._actors) self:helper_reassignAllRoles() @@ -1480,6 +1507,11 @@ function Sexbound:getContainsPlayer() return self._containsPlayer end +--- Returns if the node currently contains a defeated actor +function Sexbound:getContainsDefeated() + return self._containsDefeated +end + --- Returns a reference to this instance's sextalk manager function Sexbound:getSextalk() return self._sextalk diff --git a/scripts/sexbound/lib/sexbound/actor.lua b/scripts/sexbound/lib/sexbound/actor.lua index f4734e03..5d552572 100644 --- a/scripts/sexbound/lib/sexbound/actor.lua +++ b/scripts/sexbound/lib/sexbound/actor.lua @@ -642,6 +642,8 @@ function Sexbound.Actor:setup(actorConfig) if self._config.arousedStrong then actorStatus:addStatus("sexbound_aroused_strong") end if self._config.inHeat then actorStatus:addStatus("sexbound_aroused_heat") end if self._config.isDefeated then actorStatus:addStatus("sexbound_defeated") end + if self._config.birthcontrol then actorStatus:addStatus("birthcontrol") end + if self._config.canUseSexUIDefeated then actorStatus:addStatus("can_use_sex_ui_defeated") end if self._config.identity.sxbNaturalStatus then for _,s in ipairs(self._config.identity.sxbNaturalStatus) do @@ -649,7 +651,7 @@ function Sexbound.Actor:setup(actorConfig) end end - self:getLog():debug("Actor "..self:getName().." setup fertility: fertile "..tostring(self._config.isFertile).." - hyperFertile "..tostring(self._config.isHyperFertile).." - ovulating "..tostring(self._config.isOvulating).." - defeated "..tostring(self._config.isDefeated)) + self:getLog():debug("Actor "..self:getName().." setup fertility: fertile "..tostring(self._config.isFertile).." - hyperFertile "..tostring(self._config.isHyperFertile).." - ovulating "..tostring(self._config.isOvulating).." - defeated "..tostring(self._config.isDefeated).." - birthcontrol "..tostring(self._config.birthcontrol)) self:initPlugins() self:getApparel():sync() -- initial fetching of apparel to determine initial gender diff --git a/scripts/sexbound/lib/sexbound/positions.lua b/scripts/sexbound/lib/sexbound/positions.lua index 9797a535..988f7d37 100644 --- a/scripts/sexbound/lib/sexbound/positions.lua +++ b/scripts/sexbound/lib/sexbound/positions.lua @@ -292,11 +292,12 @@ end function Sexbound.Positions:switchRandomSexPosition(fromIdle) fromIdle = fromIdle or false - if self._positionCount < 1 then return end - if fromIdle and self._index ~= -1 then return end + if self._positionCount < 1 then return false end + if fromIdle and self._index ~= -1 then return false end local randomIndex = util.randomIntInRange({1, self._positionCount}) self:switchPosition(randomIndex) + return true end --- Returns a reference to the Positions Configuration. diff --git a/scripts/sexbound/lib/sexbound/sextalk.lua b/scripts/sexbound/lib/sexbound/sextalk.lua index 78fc94f2..964d9c54 100644 --- a/scripts/sexbound/lib/sexbound/sextalk.lua +++ b/scripts/sexbound/lib/sexbound/sextalk.lua @@ -95,6 +95,10 @@ end --- Function to choose a random available function Sexbound.Sextalk:triggerTalk() + + -- disable dialog if its a defeat node (will have separate dialog in the future) + if self._parent._containsDefeated then return end + local viableActors = {} for _,a in ipairs(self._parent:getActors()) do local sxt = a:getPlugins("sextalk") diff --git a/scripts/sexbound/override/common/arousal.lua b/scripts/sexbound/override/common/arousal.lua index 514d07a4..c241e83e 100644 --- a/scripts/sexbound/override/common/arousal.lua +++ b/scripts/sexbound/override/common/arousal.lua @@ -4,7 +4,8 @@ Sexbound.Common.Arousal_mt = { __index = Sexbound.Common.Arousal } --- Instantiates this class function Sexbound.Common.Arousal:new() return setmetatable({ - _resourceName = "arousal" + _resourceName = "arousal", + _multiplierName = "arousalMult" }, Sexbound.Common.Arousal_mt) end @@ -92,6 +93,9 @@ end function Sexbound.Common.Arousal:addAmount(amount) if self._parent._isKid then return end + -- Account for environmental multiplier + local mult = status.stat(self._multiplierName) + if mult > 0 then amount = amount * mult end status.modifyResource(self._resourceName, amount) end diff --git a/scripts/sexbound/override/common/status.lua b/scripts/sexbound/override/common/status.lua index 914f2622..0a316cfb 100644 --- a/scripts/sexbound/override/common/status.lua +++ b/scripts/sexbound/override/common/status.lua @@ -75,6 +75,10 @@ function Sexbound.Common.Status:addStatus(statusName, persistent) local l = self._listeners.add[n] xpcall(function() l({query="add", name=statusName, isPersistent=persistent}) end, function(err) sb.logWarn("Error in #"..entity.id().."'s status listener") sb.logWarn(err) end) end + + if statusName == "canBeDefeated" or statusName == "canDefeatOthers" then + status.setStatusProperty(statusName, true) + end return true end @@ -133,6 +137,10 @@ end -- @param statusName function Sexbound.Common.Status:removeStatus(statusName, persistent) if persistent == nil then persistent = true end + + if statusName == "canBeDefeated" or statusName == "canDefeatOthers" then + status.setStatusProperty(statusName, false) + end for index, status in ipairs(self:getStatusList()) do if (status == statusName) then diff --git a/scripts/sexbound/override/common/transform.lua b/scripts/sexbound/override/common/transform.lua index 446ca5ac..86e9af0a 100644 --- a/scripts/sexbound/override/common/transform.lua +++ b/scripts/sexbound/override/common/transform.lua @@ -12,7 +12,8 @@ function Sexbound.Common.Transform:new() return setmetatable({ _canTransform = false, _nodeName = "sexbound_main_node", - _timeout = 300 + _timeout = 300, + _promises = PromiseKeeper.new() }, Sexbound.Common.Transform_mt) end @@ -23,41 +24,48 @@ function Sexbound.Common.Transform:init(parent) self._feetOffset = self:calculateFeetPositionOffset() end ---- Returns a nearby position within the specified rectangle. --- @param rectSize -function Sexbound.Common.Transform:findNearbyOpenSpace(rectSize) +--- Returns 5 nearby positions within 10 blocks underneath the entity. +function Sexbound.Common.Transform:findNearbyOpenSpace(startPosition) local yOffset = 0.5 - - local startPosition = entity.position() + local distance = 6 + local positive = true + local positions = {} + local counter = 0 + local position = nil + startPosition = startPosition or entity.position() startPosition[2] = (startPosition[2] - self._feetOffset) + yOffset - local endPosition = vec2.add(startPosition, {0, -10}) + for i=0,distance * 2 do + position = world.lineCollision(startPosition, endPosition, {"Block", "Platform"}) + table.insert(positions, position) + counter = counter + 1 + if positive then + startPosition[1] = startPosition[1] + counter + endPosition[1] = endPosition[1] + counter + positive = false + else + startPosition[1] = startPosition[1] - counter + endPosition[1] = endPosition[1] - counter + positive = true + end - local position = world.lineCollision(startPosition, endPosition, {"Block", "Platform"}) - - if position == nil then - return false end - position = vec2.floor(position) - - if not world.tileIsOccupied(position, true) then - return position + if positions == {} then + return false end - return false + return positions end ---- Attempts to place a sex node at a specified position. +--- Attempts to place a sex node beneath an entity. -- @param position -- @param spawnOptions -function Sexbound.Common.Transform:placeSexNode(position, spawnOptions) - local dungeonId = Sexbound.Util.tileProtectionDisable(position) - local result = self:helper_SpawnSexNode(position, spawnOptions) - +function Sexbound.Common.Transform:placeSexNode(spawnOptions, position, actorData) + local dungeonId = Sexbound.Util.tileProtectionDisable(position or entity.position()) + local uniqueId = self:helper_SpawnSexNode(spawnOptions, position or nil, actorData or nil) Sexbound.Util.tileProtectionEnable(dungeonId) - - return result + return uniqueId end --- This function may never actually work while the NPC is stunned @@ -79,24 +87,26 @@ function Sexbound.Common.Transform:calculateFeetPositionOffset() return 2.5 -- Else take a wild guess that it's 2.5 end --- [Helper] Handles the process of spawning a sex node at a specified position. +-- [Helper] Handles the process of spawning a sex node in a tile beneath the entity. -- @param position -- @param spawnOptions -function Sexbound.Common.Transform:helper_SpawnSexNode(position, spawnOptions) - spawnOptions = spawnOptions or {} - +function Sexbound.Common.Transform:helper_SpawnSexNode(spawnOptions, position, actorData) + local positions = self:findNearbyOpenSpace(position) local params = { mindControl = { timeout = self._timeout -- 5 minutes by default unless overrided }, respawner = storage.respawner, sexboundConfig = self:getSexboundConfig(), - storedActor = self:getParent():getActorData(), + storedActor = actorData or self:getParent():getActorData(), uniqueId = sb.makeUuid() } + + spawnOptions = spawnOptions or {} + -- Randomize the start position when true - params.sexboundConfig.randomStartPosition = spawnOptions.randomStartPosition + --params.sexboundConfig.randomStartPosition = spawnOptions.randomStartPosition local facingDirection = 1 @@ -105,16 +115,25 @@ function Sexbound.Common.Transform:helper_SpawnSexNode(position, spawnOptions) facingDirection = mcontroller.facingDirection() end - if world.placeObject(self._nodeName, position, facingDirection, params) then - self:setPosition(position[1], position[2] + self._feetOffset) - - if not spawnOptions.noEffect then - world.sendEntityMessage(entity.id(), "applyStatusEffect", "sexbound_transform") + -- Iterate through list of scanned tile positions until node is placed. + local uniqueId = params.uniqueId + for _, targetTile in ipairs(positions) do + -- In the future, we'll need to handle tile protection on a different entity in case of a player being transformed + local placed = world.placeObject(self._nodeName, targetTile, facingDirection, params) + if placed then + if params.storedActor.entityType == "player" then + world.sendEntityMessage(params.storedActor.entityId, "Sexbound:Defeat:SetPosition", {targetTile[1], targetTile[2] + 2.5}) + elseif mcontroller then + mcontroller.setPosition({targetTile[1], targetTile[2] + self._feetOffset}) + end + if not spawnOptions.noEffect then + world.sendEntityMessage(params.storedActor.entityId, "applyStatusEffect", "sexbound_transform") + end + return params.uniqueId end - - return params.uniqueId end + return nil end diff --git a/scripts/sexbound/override/monster.lua b/scripts/sexbound/override/monster.lua index 155332c5..5c2f06d3 100644 --- a/scripts/sexbound/override/monster.lua +++ b/scripts/sexbound/override/monster.lua @@ -114,6 +114,9 @@ function Sexbound.Monster:initMessageHandlers() message.setHandler("Sexbound:Actor:Say", function(_, _, args) return self:handleSay(args) end) + message.setHandler("Sexbound:Actor:GetActorData", function(_, _, args) + return self:getActorData(), args + end) message.setHandler("Sexbound:Config:Retrieve", function(_, _, args) return self:handleRetrieveConfig(args) end) @@ -172,11 +175,12 @@ function Sexbound.Monster:restore() if entityId then world.sendEntityMessage(entityId, "Sexbound:removeStatusEffect", "sexbound_invisible") world.sendEntityMessage(entityId, "Sexbound:removeStatusEffect", "sexbound_stun") + world.sendEntityMessage(entityId, "Sexbound:removeStatusEffect", "sexbound_defeat_stun") end end function Sexbound.Monster:handleRetrieveConfig(args) - return config.getParameter("sexboundConfig") + return config.getParameter("sexboundConfig"), args end function Sexbound.Monster:handleSay(args) diff --git a/scripts/sexbound/override/monster/transform.lua b/scripts/sexbound/override/monster/transform.lua index 5e7beb6d..2e8087f1 100644 --- a/scripts/sexbound/override/monster/transform.lua +++ b/scripts/sexbound/override/monster/transform.lua @@ -14,15 +14,15 @@ function Sexbound.Monster.Transform:new(parent) _self:setCanTransform(true); - message.setHandler("Sexbound:Transform", function(_, _, args) - return _self:handleTransform(args) + message.setHandler("Sexbound:Transform", function(_, _, args, actorData) + return _self:handleTransform(args, actorData) end) return _self end -function Sexbound.Monster.Transform:handleTransform(args) - if self:getCanTransform() then +function Sexbound.Monster.Transform:handleTransform(args, actorData) + if self:getCanTransform() or actorData ~= nil then self:setSexboundConfig(args.sexboundConfig) self:setTimeout(args.timeout) @@ -30,7 +30,7 @@ function Sexbound.Monster.Transform:handleTransform(args) if not args.responseRequired then self:notifyTransform() else - local result = self:tryCreateNode() + local result = self:tryCreateNode(args.spawnOptions or {}, args.position or nil, actorData or nil) if result ~= nil and args.applyStatusEffects ~= nil then for _, statusName in ipairs(args.applyStatusEffects) do @@ -60,17 +60,11 @@ function Sexbound.Monster.Transform:handleTransform(args) return false end -function Sexbound.Monster.Transform:tryCreateNode() - local position = self:findNearbyOpenSpace() - - if position == false then - return nil - end - - -- Place Sexnode and store Unique ID - local uniqueId = self:placeSexNode(position, { - randomStartPosition = true - }) +function Sexbound.Monster.Transform:tryCreateNode(spawnOptions, position, actorData) + local uniqueId = self:placeSexNode({ + randomStartPosition = true, + noEffect = spawnOptions.noEffect or false + }, position or nil, actorData or nil) if uniqueId ~= nil then world.sendEntityMessage(entity.id(), "Sexbound:Transform:Success", { diff --git a/scripts/sexbound/override/npc.lua b/scripts/sexbound/override/npc.lua index 71d67565..d005017a 100644 --- a/scripts/sexbound/override/npc.lua +++ b/scripts/sexbound/override/npc.lua @@ -185,6 +185,9 @@ function Sexbound.NPC:initMessageHandlers() message.setHandler("Sexbound:Actor:Say", function(_, _, args) return self:handleSay(args) end) + message.setHandler("Sexbound:Actor:GetActorData", function(_, _, args) + return self:getActorData(), args + end) message.setHandler("Sexbound:Config:Retrieve", function(_, _, args) return self:handleRetrieveConfig(args) end) @@ -266,7 +269,7 @@ function Sexbound.NPC:handleRestore(args) end function Sexbound.NPC:handleRetrieveConfig(args) - return config.getParameter("sexboundConfig") + return config.getParameter("sexboundConfig"), args end function Sexbound.NPC:handleSay(args) @@ -342,6 +345,7 @@ function Sexbound.NPC:removeAllStunningStatusEffects() status.removeEphemeralEffect("sexbound_stun") status.setResource("stunned", 0) status.setStatusProperty("sexbound_stun", false) + status.removeEphemeralEffect("sexbound_defeat_stun") end function Sexbound.NPC:removeWeaponsWhenShouldHaveEmptyHands() diff --git a/scripts/sexbound/override/npc/transform.lua b/scripts/sexbound/override/npc/transform.lua index a0e3bdae..9da3b729 100644 --- a/scripts/sexbound/override/npc/transform.lua +++ b/scripts/sexbound/override/npc/transform.lua @@ -15,17 +15,17 @@ function Sexbound.NPC.Transform:new(parent) _self:setCanTransform(true); - message.setHandler("Sexbound:Transform", function(_, _, args) - return _self:handleTransform(args) + message.setHandler("Sexbound:Transform", function(_, _, args, actorData) + return _self:handleTransform(args, actorData) end) return _self end -function Sexbound.NPC.Transform:handleTransform(args) +function Sexbound.NPC.Transform:handleTransform(args, actorData) if self._parent._isKid then return false end - - if self:getCanTransform() then + + if self:getCanTransform() or actorData ~= nil then -- Override sexbound config that is supplied to the spawned sexnode self:setSexboundConfig(args.sexboundConfig) @@ -34,7 +34,7 @@ function Sexbound.NPC.Transform:handleTransform(args) if not args.responseRequired then self:notifyTransform() else - local result = self:tryCreateNode() + local result = self:tryCreateNode(args.spawnOptions or {}, args.position or nil, actorData or nil) if result ~= nil and args.applyStatusEffects ~= nil then for _, statusName in ipairs(args.applyStatusEffects) do @@ -73,19 +73,13 @@ function Sexbound.NPC.Transform:notifyTransform() end end -function Sexbound.NPC.Transform:tryCreateNode() +function Sexbound.NPC.Transform:tryCreateNode(spawnOptions, position, actorData) if self._parent._isKid then return nil end - local position = self:findNearbyOpenSpace() - - if position == false then - return nil - end - - -- Place Sexnode and store Unique ID - local uniqueId = self:placeSexNode(position, { - randomStartPosition = true - }) + local uniqueId = self:placeSexNode({ + randomStartPosition = true, + noEffect = spawnOptions.noEffect or false + }, position or nil, actorData or nil) if uniqueId ~= nil then world.sendEntityMessage(entity.id(), "Sexbound:Transform:Success", { diff --git a/scripts/sexbound/override/player.lua b/scripts/sexbound/override/player.lua index 155851fe..d7bd7e86 100644 --- a/scripts/sexbound/override/player.lua +++ b/scripts/sexbound/override/player.lua @@ -73,7 +73,9 @@ function Sexbound.Player.new() _loungeId = nil, _states = {"defaultState", "havingSexState"}, _isSterilized = false, - _isInfertile = false + _isInfertile = false, + _canBeDefeated = false, + _canDefeatOthers = false }, Sexbound.Player_mt) self:init(self, "player") @@ -125,6 +127,8 @@ function Sexbound.Player.new() self._isSterilized = self._status:hasStatus("sterilized") self._isInfertile = self._status:hasStatus("infertile") + self._canBeDefeated = self._status:hasStatus("canBeDefeated") + self._canDefeatOthers = self._status:hasStatus("canDefeatOthers") self._hasInited = true self:updateTraitEffects() @@ -231,6 +235,8 @@ function Sexbound.Player:handleGetCutomizerData(args) _loadedConfig.subGenders = self._subGender:getAllSubGenders() _loadedConfig.sterilized = self._status:hasStatus("sterilized") _loadedConfig.infertile = self._status:hasStatus("infertile") + _loadedConfig.canBeDefeated = self._status:hasStatus("canBeDefeated") + _loadedConfig.canDefeatOthers = self._status:hasStatus("canDefeatOthers") return _loadedConfig end @@ -275,7 +281,7 @@ function Sexbound.Player:restore() end function Sexbound.Player:handleRetrieveConfig(args) - return nil + return nil, args end function Sexbound.Player:handleRetrieveStorage(args) @@ -364,6 +370,9 @@ function Sexbound.Player:initMessageHandlers() message.setHandler("Sexbound:Actor:Respawn", function(_, _, args) return self:handleRespawn(args) end) + message.setHandler("Sexbound:Actor:GetActorData", function(_, _, args) + return self:getActorData(), args + end) message.setHandler("Sexbound:Config:Retrieve", function(_, _, args) return self:handleRetrieveConfig(args) end) @@ -514,10 +523,12 @@ function Sexbound.Player:getActorData() isFertile = status.statusProperty("sexbound_custom_fertility", false), isHyperFertile = status.statusProperty("sexbound_custom_hyper_fertility", false), isOvulating = status.statusProperty("sexbound_custom_ovulating", false), + birthcontrol = status.statusProperty("sexbound_birthcontrol"), aroused = status.statusProperty("sexbound_aroused", false), arousedStrong = status.statusProperty("sexbound_aroused_strong", false), inHeat = status.statusProperty("sexbound_aroused_heat", false), - isDefeated = self.sexboundDefeat and self.sexboundDefeat:isDefeated(), + isDefeated = status.statusProperty("sexbound_defeated", false), + canUseSexUIDefeated = status.statusProperty("can_use_sex_ui_defeated", false), generationFertility = status.statusProperty("generationFertility", 1.0), fertilityPenalty = status.statusProperty("fertilityPenalty", 1.0) } diff --git a/scripts/sexbound/override/player/transform.lua b/scripts/sexbound/override/player/transform.lua index 2e01baf9..45a5d1f0 100644 --- a/scripts/sexbound/override/player/transform.lua +++ b/scripts/sexbound/override/player/transform.lua @@ -7,7 +7,7 @@ Sexbound.Player.Transform_mt = { function Sexbound.Player.Transform:new(parent) local _self = setmetatable({ - _canTransform = false, + _canTransform = true, _mindControl = {}, _nodeName = "sexbound_main_node", _parent = parent @@ -31,7 +31,7 @@ function Sexbound.Player.Transform:handleTransform(args) self:setTimeout(args.timeout) - local result = self:tryCreateNode(args.spawnOptions or {}) + local result = self:tryCreateNode(args.spawnOptions or {}, args.position or nil) if result ~= nil and args.applyStatusEffects ~= nil then for _, statusName in ipairs(args.applyStatusEffects) do @@ -45,18 +45,12 @@ function Sexbound.Player.Transform:handleTransform(args) return false end -function Sexbound.Player.Transform:tryCreateNode(spawnOptions) - local position = self:findNearbyOpenSpace() - if self._parent:canLog("debug") then sb.logInfo("Looking for valid spawn position") end - if position == false then - return nil - end - if self._parent:canLog("debug") then sb.logInfo("Found valid position, attempting to place actual node") end +function Sexbound.Player.Transform:tryCreateNode(spawnOptions, position, data) -- Place Sexnode and store Unique ID - local uniqueId = self:placeSexNode(position, { + local uniqueId = self:placeSexNode({ randomStartPosition = true, noEffect = spawnOptions.noEffect or false - }) + }, position or nil, data or nil) if self._parent:canLog("debug") then sb.logInfo("Placed node with UUID "..tostring(uniqueId)) end if uniqueId ~= nil then world.sendEntityMessage(entity.id(), "Sexbound:Transform:Success", { diff --git a/scripts/sexbound/override/stats/monster_primary.lua b/scripts/sexbound/override/stats/monster_primary.lua index 3199758b..f85ba244 100644 --- a/scripts/sexbound/override/stats/monster_primary.lua +++ b/scripts/sexbound/override/stats/monster_primary.lua @@ -1,3 +1,5 @@ +require "/stats/sexbound/sexbounddefeat.lua" + local sexbound_monster_primary_init = init function init() sexbound_monster_primary_init() @@ -5,4 +7,21 @@ function init() message.setHandler("Sexbound:removeStatusEffect", function(_, _, effectName) status.removeEphemeralEffect(effectName) end) + + --Defeat Init + self.sexboundDefeat = SexboundDefeat:new("monster") + status.removeEphemeralEffect("sexbound_sex") + status.removeEphemeralEffect("sexbound_defeat_stun") end + +-- Override Update Hook (Defeat) +local sexbound_defeat_update = update +function update(dt) + self.sexboundDefeat:update(dt, sexbound_defeat_update) +end + +-- Override Apply Damage Request Hook (Defeat) +local sexbound_defeat_applyDamageRequest = applyDamageRequest +function applyDamageRequest(damageRequest) + return self.sexboundDefeat:handleApplyDamageRequest(sexbound_defeat_applyDamageRequest, damageRequest) +end \ No newline at end of file diff --git a/scripts/sexbound/override/stats/npc_primary.lua b/scripts/sexbound/override/stats/npc_primary.lua index 125b0e3e..66b25163 100644 --- a/scripts/sexbound/override/stats/npc_primary.lua +++ b/scripts/sexbound/override/stats/npc_primary.lua @@ -1,3 +1,5 @@ +require "/stats/sexbound/sexbounddefeat.lua" + local sexbound_NPC_Primary_init = init function init() sexbound_NPC_Primary_init() @@ -5,4 +7,22 @@ function init() message.setHandler("Sexbound:removeStatusEffect", function(_, _, effectName) status.removeEphemeralEffect(effectName) end) + + -- Defeat init + self.sexboundDefeat = SexboundDefeat:new("npc") + status.removeEphemeralEffect("sexbound_sex") + status.removeEphemeralEffect("sexbound_defeat_stun") + end + +-- Override Update Hook (defeat) +local sexbound_defeat_update = update +function update(dt) + self.sexboundDefeat:update(dt, sexbound_defeat_update) +end + +-- Override Apply Damage Request Hook (defeat) +local sexbound_defeat_applyDamageRequest = applyDamageRequest +function applyDamageRequest(damageRequest) + return self.sexboundDefeat:handleApplyDamageRequest(sexbound_defeat_applyDamageRequest, damageRequest) +end \ No newline at end of file diff --git a/scripts/sexbound/override/stats/player_primary.lua b/scripts/sexbound/override/stats/player_primary.lua index 60e32f32..3681985c 100644 --- a/scripts/sexbound/override/stats/player_primary.lua +++ b/scripts/sexbound/override/stats/player_primary.lua @@ -1,4 +1,5 @@ require "/scripts/sexbound/util.lua" +require "/stats/sexbound/sexbounddefeat.lua" local Sexbound_Override_Player_Primary_init = init function init() @@ -7,9 +8,26 @@ function init() message.setHandler("Sexbound:removeStatusEffect", function(_, _, effectName) status.removeEphemeralEffect(effectName) end) + + -- Defeat init + self.sexboundDefeat = SexboundDefeat:new("player") + status.removeEphemeralEffect("sexbound_sex") + status.removeEphemeralEffect("sexbound_defeat_stun") + status.removeEphemeralEffect("regeneration4") + + message.setHandler("Sexbound:Defeat:SetPosition", function(_, _, position) + mcontroller.setPosition(position) + end) + end local Sexbound_Override_Player_Primary_update = update function update(dt) - Sexbound_Override_Player_Primary_update(dt) + self.sexboundDefeat:update(dt, Sexbound_Override_Player_Primary_update) +end + +-- Override Apply Damage Request Hook (Defeat) +local sexbound_defeat_applyDamageRequest = applyDamageRequest +function applyDamageRequest(damageRequest) + return self.sexboundDefeat:handleApplyDamageRequest(sexbound_defeat_applyDamageRequest, damageRequest) end diff --git a/scripts/sexbound/plugins/climax/climax.lua b/scripts/sexbound/plugins/climax/climax.lua index bd01fb70..ec69249f 100644 --- a/scripts/sexbound/plugins/climax/climax.lua +++ b/scripts/sexbound/plugins/climax/climax.lua @@ -130,6 +130,10 @@ function Sexbound.Actor.Climax:onUpdateSexState(dt) local multiplier = actor:getPosition():getAnimationState("sexState"):getClimaxMultiplier(actorNumber) or 1 local increase = util.randomInRange(self:getDefaultIncrease()) * multiplier * dt + -- increase point gain if this is a defeat node to allow for climaxing during the limited sexnode duration + if self:getParent():getParent():getContainsDefeated() then + increase = increase * 2.1 + end self._config.currentPoints = util.clamp(self._config.currentPoints + increase, self:getMinPoints(), self:getMaxPoints()) @@ -527,21 +531,12 @@ end --- Attempts to cause this actor to begin climaxing. function Sexbound.Actor.Climax:tryAutoClimax() local entityType = self:getParent():getEntityType() - local containsPlayer = false - local playerControl = false if entityType == "player" then return - else - for _, actor in ipairs(self:getParent():getParent():getActors()) do - if actor:getActorNumber() ~= self:getParent():getActorNumber() then - if actor:getEntityType() == "player" then containsPlayer = true end - if not actor:getStatus():hasStatus("sexbound_defeated") then playerControl = true end - end - end end - if self._config.prioritizePlayer and containsPlayer and playerControl then + if self._config.prioritizePlayer and self:getParent():getParent()._playerControl then -- Prevent auto climax if we have a player and that player is in control (not raped as part of sexbound defeat) return end diff --git a/scripts/sexbound/plugins/pregnant/baby.lua b/scripts/sexbound/plugins/pregnant/baby.lua index f66ee6f2..3d761fd9 100644 --- a/scripts/sexbound/plugins/pregnant/baby.lua +++ b/scripts/sexbound/plugins/pregnant/baby.lua @@ -369,8 +369,8 @@ function Baby:_convertBabyConfigToSpawnableNPC(babyConfig, babyName) generationFertility = babyConfig.generationFertility, fertilityPenalty = babyConfig.generationFertility } - if self._parent._parent._config.enableKidStage then - params.statusControllerSettings.statusProperties.kid = world.time() + 840*(self._parent._parent._config.kidDayCount or 5) --Config based days of being a kid + if self._config.enableKidStage then + params.statusControllerSettings.statusProperties.kid = world.time() + 840*(self._config.kidDayCount or 5) --Config based days of being a kid end params.identity = {} params.identity.gender = babyConfig.birthGender diff --git a/sexbound-ES-changelog.txt b/sexbound-ES-changelog.txt index 88275954..85581c3b 100644 --- a/sexbound-ES-changelog.txt +++ b/sexbound-ES-changelog.txt @@ -263,6 +263,8 @@ => [GENERAL] Support for non-humanoid species [B] => [GENERAL] Add commands [C] => [GENERAL] Add humping variety to sex animation [Probably impossible] [I] + => [GENERAL] Add balancing debuffs for debug consumables (hyper fertility pill, birthing pill) <- + => [GENERAL] Add birth speedup pill (progression speed multiplier) as non-cheaty, non-debuff alternative to birthing pill (like normal fertility pill) <- => [CLIMAX] Make condoms degrading (climax with condom -> used condom -> broken condom) [S] => [CLIMAX] Upgrade status prevention/condoms to be gender specific [S] => [CLIMAX] Fix scripted climax cancel conditions [BUGFIX] @@ -273,7 +275,6 @@ => [PREGNANCY] Add maximum complexity logic (lingering cum, washing) [L] => [PREGNANCY] NPC realistic pregnancy logic [L]/[F]? => [MODDING] Assimilate "Sexbound Defeat" if allowed [C] - => [MODDING] Update default animation depth to the level of Red's "Relayer" project? [I] => [IDEA] Rework of climax system ==> Climax available at 100 diff --git a/sexbound-defeat.config b/sexbound-defeat.config new file mode 100644 index 00000000..d0a84b42 --- /dev/null +++ b/sexbound-defeat.config @@ -0,0 +1,89 @@ +{ + /* + Defeated Monster Timeout. + This can be a positive integer or a range like so [30, 60]. Default = 60 + */ + "defeatTimeoutMonster" : 60, + + /* + Defeated NPC Timeout. + This can be a positive integer or a range like so [30, 60]. Default = 60 + */ + "defeatTimeoutNPC" : 60, + + /* + Defeated Player Timeout. + This can be a positive integer or a range like so [30, 60]. Default = 30 + */ + "defeatTimeoutPlayer" : 30, + + /* + Enable pregnant NPCs to be immortal. + Valid options are true & false. Default: false + */ + "enableImmortalPregnantNPCs" : false, + + /* + Enable impregnated enemies to switch damage teams to friendly. + Valid options are true & false. Default: false + */ + "convertPregnantEnemiesToFriends" : false, + + /* + Enable starting dialog for NPCs? + Valid options are true & false. Default: true + */ + "enableStartDialogForNPCs" : true, + + /* + Enable starting dialog for Monsters? + Valid options are true & false. Default: false + */ + "enableStartDialogForMonsters" : false, + + /* + Setting this to true enables a defeated player to have access to use the Sex UI. + Valid options are true & false. Default: false + */ + "defeatedPlayersCanUseSexUI" : false, + + /* + Setting this to true enables a defeated player to escape the defeat scene. + Valid options are true & false. Default: false + */ + "enableDefeatedPlayerEscape" : false, + + /* Define 'victory' and 'defeated' start dialog for NPCs. the 'default' species is a fallback. */ + "startDialog" : { + "victory" : { + "default" : [ + "Stay down and wait for me to give you a real punishment!", + "I'm not finished with this little bitch yet!", + "You're going to make such a fine cum dumpster for me." + ], + + "floran" : [ + "Floran is going to have fun playing with prey!", + "Time to Sssexxxsss with the prey!" + ] + }, + + "defeated" : { + "default" : [ + "W-what are you going to do with me now?", + "P-please don't hurt me any more! Let me go!", + "W-What do you plan to do with me?" + ], + + "floran" : [ + "Floran doesn't like where thisss is going next.." + ] + } + }, + + "pregnantDialog" : { + "default" : [ + "Sorry, but I refuse to die while I'm pregnant!" + ] + } +} \ No newline at end of file diff --git a/stats/effects/lustia_hornybuff/lustia_hornybuff.lua b/stats/effects/lustia_hornybuff/lustia_hornybuff.lua new file mode 100644 index 00000000..4d63679f --- /dev/null +++ b/stats/effects/lustia_hornybuff/lustia_hornybuff.lua @@ -0,0 +1,9 @@ +function init() + effect.addStatModifierGroup({ + { stat = "arousalMult", effectiveMultiplier = 5 } + }) +end + +function uninit() + +end diff --git a/stats/effects/lustia_hornybuff/lustia_hornybuff.statuseffect b/stats/effects/lustia_hornybuff/lustia_hornybuff.statuseffect new file mode 100644 index 00000000..c0f5ccdc --- /dev/null +++ b/stats/effects/lustia_hornybuff/lustia_hornybuff.statuseffect @@ -0,0 +1,9 @@ +{ + "name" : "lustia_hornybuff", + "blockingStat" : "sexboundImmunity", + "defaultDuration" : 999, + "effectConfig" : {}, + "icon" : "/interface/statuses/lustia.png", + "label" : "Lustia makes you horny", + "scripts" : [ "lustia_hornybuff.lua" ] +} diff --git a/stats/effects/sexbound_birthcontrol/sexbound_birthcontrol.lua b/stats/effects/sexbound_birthcontrol/sexbound_birthcontrol.lua index 1dd15b77..6bea8efc 100644 --- a/stats/effects/sexbound_birthcontrol/sexbound_birthcontrol.lua +++ b/stats/effects/sexbound_birthcontrol/sexbound_birthcontrol.lua @@ -1,7 +1,11 @@ function init() + local entityId = entity.id() status.setStatusProperty("sexbound_birthcontrol", true) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "birthcontrol") end function uninit() + local entityId = entity.id() status.setStatusProperty("sexbound_birthcontrol", false) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "birthcontrol") end diff --git a/stats/effects/sexbound_birthing/sexbound_birthing.lua b/stats/effects/sexbound_birthing/sexbound_birthing.lua index f23a35f3..3ea77da0 100644 --- a/stats/effects/sexbound_birthing/sexbound_birthing.lua +++ b/stats/effects/sexbound_birthing/sexbound_birthing.lua @@ -1,5 +1,6 @@ function init() - if status.stat('specialStatusImmunity') > 0 then effect.expire() return end + self._aborted = status.stat('specialStatusImmunity') > 0 + if self._aborted then effect.expire() return end effect.addStatModifierGroup({ { stat = "invulnerable", amount = 1 }, @@ -22,6 +23,7 @@ function update() end function uninit() + if self._aborted then return end if status.isResource("stunned") then status.setResource("stunned", 0) end status.setStatusProperty("sexbound_stun", false) end \ No newline at end of file diff --git a/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.lua b/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.lua new file mode 100644 index 00000000..c9869ecb --- /dev/null +++ b/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.lua @@ -0,0 +1,11 @@ +function init() + +end + +function update() + +end + +function uninit() + +end \ No newline at end of file diff --git a/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.statuseffect b/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.statuseffect new file mode 100644 index 00000000..cc7640d9 --- /dev/null +++ b/stats/effects/sexbound_birthspeedpill/sexbound_birthspeedpill.statuseffect @@ -0,0 +1,8 @@ +{ + "name" : "sexbound_birthspeedpill", + "blockingStat" : "sexboundImmunity", + "defaultDuration" : 840, + "effectConfig" : {}, + "label" : "Speed Birthing", + "scripts" : [ "sexbound_birthspeedpill.lua" ] +} diff --git a/stats/effects/sexbound_custom_hyper_fertility/sexbound_custom_hyper_fertility.lua b/stats/effects/sexbound_custom_hyper_fertility/sexbound_custom_hyper_fertility.lua index ada4a4bf..3f5e95e2 100644 --- a/stats/effects/sexbound_custom_hyper_fertility/sexbound_custom_hyper_fertility.lua +++ b/stats/effects/sexbound_custom_hyper_fertility/sexbound_custom_hyper_fertility.lua @@ -1,4 +1,6 @@ function init() + self._aborted = status.getStatusProperty("sexbound_penalty_hyper_fertility", false) + if self._aborted then effect.expire() end status.setStatusProperty("sexbound_custom_hyper_fertility", true) world.sendEntityMessage(entity.id(), "Sexbound:Pregnant:AddStatus", "sexbound_custom_hyper_fertility") end @@ -7,3 +9,6 @@ function uninit() status.setStatusProperty("sexbound_custom_hyper_fertility", false) world.sendEntityMessage(entity.id(), "Sexbound:Pregnant:RemoveStatus", "sexbound_custom_hyper_fertility") end + +function onExpire() +end diff --git a/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.lua b/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.lua new file mode 100644 index 00000000..ada4a4bf --- /dev/null +++ b/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.lua @@ -0,0 +1,9 @@ +function init() + status.setStatusProperty("sexbound_custom_hyper_fertility", true) + world.sendEntityMessage(entity.id(), "Sexbound:Pregnant:AddStatus", "sexbound_custom_hyper_fertility") +end + +function uninit() + status.setStatusProperty("sexbound_custom_hyper_fertility", false) + world.sendEntityMessage(entity.id(), "Sexbound:Pregnant:RemoveStatus", "sexbound_custom_hyper_fertility") +end diff --git a/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.statuseffect b/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.statuseffect new file mode 100644 index 00000000..12f48d83 --- /dev/null +++ b/stats/effects/sexbound_debug_hyper_fertility/sexbound_debug_hyper_fertility.statuseffect @@ -0,0 +1,9 @@ +{ + "name" : "sexbound_debug_hyper_fertility", + "blockingStat" : "sexboundImmunity", + "defaultDuration" : 300, + "effectConfig" : {}, + "icon" : "/interface/statuses/hyperfertile.png", + "label" : "Extremely Fertile!", + "scripts" : [ "sexbound_debug_hyper_fertility.lua" ] +} diff --git a/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.lua b/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.lua new file mode 100644 index 00000000..b7ed139c --- /dev/null +++ b/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.lua @@ -0,0 +1,9 @@ +function init() + effect.addStatModifierGroup({ + { stat = "invulnerable", amount = 1 }, + { stat = "fireStatusImmunity", amount = 1 }, + { stat = "iceStatusImmunity", amount = 1 }, + { stat = "electricStatusImmunity", amount = 1 }, + { stat = "poisonStatusImmunity", amount = 1 } + }) +end \ No newline at end of file diff --git a/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.statuseffect b/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.statuseffect new file mode 100644 index 00000000..881fb046 --- /dev/null +++ b/stats/effects/sexbound_defeat_invuln/sexbound_defeat_invuln.statuseffect @@ -0,0 +1,9 @@ +{ + "name" : "sexbound_defeat_invuln", + "blockingStat" : "specialStatusImmunity", + "defaultDuration" : 1.5, + "effectConfig" : {}, + "icon" : "/interface/statuses/timefreeze.png", + "label" : "Recovering", + "scripts" : [ "sexbound_defeat_invuln.lua" ] +} diff --git a/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.lua b/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.lua new file mode 100644 index 00000000..cca84516 --- /dev/null +++ b/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.lua @@ -0,0 +1,29 @@ +function init() + if status.isResource("energy") then + status.setResourcePercentage("energy", 0) + end + effect.addStatModifierGroup({ + { stat = "invulnerable", amount = 1 }, + { stat = "fireStatusImmunity", amount = 1 }, + { stat = "iceStatusImmunity", amount = 1 }, + { stat = "electricStatusImmunity", amount = 1 }, + { stat = "poisonStatusImmunity", amount = 1 }, + { stat = "powerMultiplier", effectiveMultiplier = 0 } + }) + if status.isResource("stunned") then + status.setResource("stunned", math.max(status.resource("stunned"), effect.duration())) + end + mcontroller.setVelocity({ 0, 0 }) + status.setStatusProperty("sexbound_defeat_stun", true) +end + +function update() + mcontroller.setVelocity({ 0, 0 }) + mcontroller.controlModifiers({ facingSuppressed = true, movementSuppressed = true }) +end + +function uninit() + if status.isResource("stunned") then status.setResource("stunned", 0) end + status.setStatusProperty("sexbound_defeat_stun", false) + status.addEphemeralEffect("sexbound_defeat_invuln") +end \ No newline at end of file diff --git a/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.statuseffect b/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.statuseffect new file mode 100644 index 00000000..fd6145c5 --- /dev/null +++ b/stats/effects/sexbound_defeat_stun/sexbound_defeat_stun.statuseffect @@ -0,0 +1,9 @@ +{ + "name" : "sexbound_defeat_stun", + "blockingStat" : "specialStatusImmunity", + "defaultDuration" : 300, + "effectConfig" : {}, + "icon" : "/interface/statuses/timefreeze.png", + "label" : "Defeated", + "scripts" : [ "sexbound_defeat_stun.lua" ] +} diff --git a/stats/effects/sexbound_regen/sexbound_regen.lua b/stats/effects/sexbound_regen/sexbound_regen.lua new file mode 100644 index 00000000..c5f6d05b --- /dev/null +++ b/stats/effects/sexbound_regen/sexbound_regen.lua @@ -0,0 +1,14 @@ +function init() + + script.setUpdateDelta(5) + + self.healingRate = 1.0 / config.getParameter("healTime", 60) +end + +function update(dt) + status.modifyResourcePercentage("health", self.healingRate * dt) +end + +function uninit() + +end diff --git a/stats/effects/sexbound_regen/sexbound_regen1.statuseffect b/stats/effects/sexbound_regen/sexbound_regen1.statuseffect new file mode 100644 index 00000000..f8a15784 --- /dev/null +++ b/stats/effects/sexbound_regen/sexbound_regen1.statuseffect @@ -0,0 +1,16 @@ +{ + "name" : "sexbound_regen1", + "blockingStat" : "healingStatusImmunity", + + "effectConfig" : { + "healTime" : 60 + }, + "defaultDuration" : 5, + + "scripts" : [ + "sexbound_regen.lua" + ], + + "label" : "Defeat Regeneration", + "icon" : "/interface/statuses/heal.png" +} diff --git a/stats/effects/sexbound_regen/sexbound_regen2.statuseffect b/stats/effects/sexbound_regen/sexbound_regen2.statuseffect new file mode 100644 index 00000000..8f71d531 --- /dev/null +++ b/stats/effects/sexbound_regen/sexbound_regen2.statuseffect @@ -0,0 +1,16 @@ +{ + "name" : "sexbound_regen2", + "blockingStat" : "healingStatusImmunity", + + "effectConfig" : { + "healTime" : 50 + }, + "defaultDuration" : 5, + + "scripts" : [ + "sexbound_regen.lua" + ], + + "label" : "Defeat Regeneration", + "icon" : "/interface/statuses/heal.png" +} diff --git a/stats/effects/sexbound_regen/sexbound_regen3.statuseffect b/stats/effects/sexbound_regen/sexbound_regen3.statuseffect new file mode 100644 index 00000000..323534db --- /dev/null +++ b/stats/effects/sexbound_regen/sexbound_regen3.statuseffect @@ -0,0 +1,16 @@ +{ + "name" : "sexbound_regen3", + "blockingStat" : "healingStatusImmunity", + + "effectConfig" : { + "healTime" : 40 + }, + "defaultDuration" : 5, + + "scripts" : [ + "sexbound_regen.lua" + ], + + "label" : "Defeat Regeneration", + "icon" : "/interface/statuses/heal.png" +} diff --git a/stats/effects/sexbound_regen/sexbound_regen4.statuseffect b/stats/effects/sexbound_regen/sexbound_regen4.statuseffect new file mode 100644 index 00000000..83b4b4e5 --- /dev/null +++ b/stats/effects/sexbound_regen/sexbound_regen4.statuseffect @@ -0,0 +1,16 @@ +{ + "name" : "sexbound_regen4", + "blockingStat" : "healingStatusImmunity", + + "effectConfig" : { + "healTime" : 30 + }, + "defaultDuration" : 5, + + "scripts" : [ + "sexbound_regen.lua" + ], + + "label" : "Defeat Regeneration", + "icon" : "/interface/statuses/heal.png" +} diff --git a/stats/sexbound/sexbounddefeat.lua b/stats/sexbound/sexbounddefeat.lua new file mode 100644 index 00000000..f2a51c47 --- /dev/null +++ b/stats/sexbound/sexbounddefeat.lua @@ -0,0 +1,564 @@ +--- SexboundDefeat Class Module. +-- @classmod SexboundDefeat +-- @author Locuturus +-- @license GNU General Public License v3.0 +SexboundDefeat = {} +SexboundDefeat_mt = { __index = SexboundDefeat } + +require "/scripts/util.lua" +require "/scripts/messageutil.lua" + +--- Creates and returns new instance of SexboundDefeat. +-- @param entityType +-- @param species +function SexboundDefeat:new(entityType) + local _self = setmetatable({ + _configFilePath = "/sexbound-defeat.config", + _uiConfigFilePath = "/interface/sexbound/defeat.config", + _entityId = entity.id(), + _entityType = entityType, + _hostileEntityId = nil, + _hostileEntityType = nil, + _promises = PromiseKeeper.new(), + _timer = 0, + _timeout = 60, + _isDefeated = false, + _isTransformed = false, + _sexNodeId = nil, + _hostileEntities = {}, + _actorData = nil, + _sexboundConfig = nil + }, SexboundDefeat_mt) + + _self:setIsDefeated(false) + + -- Load the Sexbound Defeat config settings + _self._config = _self:loadConfig() + _self:validateConfig(_self._config) + + -- Initialize message handlers + _self:initMessageHandlers() + + -- Set the default timeout as configured in the settings + _self:_initTimeout() + + -- Set "Can use sexbound UI while defeated." state as a status for use with other scripts + status.setStatusProperty("can_use_sex_ui_defeated", _self._config.defeatedPlayersCanUseSexUI) + + -- Enable canBeDefeated and canDefeatOthers on non-players. Additional conditions could be added. + if _self.entityType ~= "player" then + status.setStatusProperty("canBeDefeated", true) + status.setStatusProperty("canDefeatOthers", true) + end + return _self +end + +function SexboundDefeat:initMessageHandlers() + message.setHandler("SexboundDefeat:Breakout", function(_,_,args) + self._timer = self._timeout + end) + message.setHandler("SexboundDefeat:TargetedBy", function(_,_,entityId) + -- Send hostile entity a message to add self to their hostile entity table + if status.statusProperty("canDefeatOthers") then + world.sendEntityMessage(entityId, "SexboundDefeat:InCombatWith", self._entityId) + end + local found = false + for i, v in ipairs(self._hostileEntities) do + if v[1] == entityId then found = true end + end + if not found then + self:retrieveSexboundConfig(function(result) + -- Run function that adds entity with their sexbound config into the hostile entity table + return self:handleRetrieveSexboundConfigSuccess(result,entityId) + end, function() + return + end, + entityId) + end + end) + -- Ends the hostile entity "handshake". Does same as "TargetedBy" but will not an additional message. + message.setHandler("SexboundDefeat:InCombatWith", function(_,_,entityId) + local found = false + for i, v in ipairs(self._hostileEntities) do + if v[1] == entityId then found = true end + end + if not found then + self:retrieveSexboundConfig(function(result) + return self:handleRetrieveSexboundConfigSuccess(result,entityId) + end, function() + return + end, + entityId) + end + end) + -- Sets the entity's status to untransform at the earliers opportunity + message.setHandler("SexboundDefeat:Untransform", function(_,_) + self:setTimer(self._timeout - 3) + end) +end + +-- Update Loop +function SexboundDefeat:update(dt, oldUpdate) + self._promises:update() + + if self:isTransformed() then + self._timer = self._timer + dt + -- Untransform the NPC when the timer runs out + if self._timer >= self._timeout or not self:isStunned() then + self:setIsDefeated(false) + self:setIsTransformed(false) + self:setTimer(0) + self:untransform() + status.removeEphemeralEffect("sexbound_defeat_stun") + end + end + + oldUpdate(dt) +end + +--- Returns back species name retrieved with the default world API. +--- MonsterType is considered as a species by Sexbound +function SexboundDefeat:findSpecies() + if self:isMonster() then + return world.monsterType(self._entityId) + end + if self:isPlayer() or self:isNPC() then + return world.entitySpecies(self._entityId) + end + return "default" +end + +function SexboundDefeat:handleApplyDamageRequest(originalFunction, damageRequest) + -- Do not return damage while the entity isDefeated is true + if self:isDefeated() then return {} end + + -- Otherwise use the original applyDamageRequest function to process the incoming damage + local damage = originalFunction(damageRequest) + + -- When the this entity's health is greater than 0, generate damage + if status.resource("health") > 0 then return damage end + + -- Handle the case where the entity doesn't have the status allowing being fucked after defeat. + if not status.statusProperty("canBeDefeated") then + self:tryToDie("entity does not have \"canBeDefeated\" status") + return {} + end + + -- Store a reference to the hostile entity id that delivered the killing blow to this entity + local hostileEntityId = damageRequest.sourceEntityId + local hostileEntityType = nil + if hostileEntityId ~= nil then + hostileEntityType = world.entityType(hostileEntityId) + end + + -- Handle the case that the entity has given itself a killing blow + if self:isSuicide() then + self:tryToDie("suicide") + return {} + end + + if self._entityId == "player" and hostileEntityType == "player" then + world.sendEntityMessage(self._entityId, "SexboundDefeat:TargetedBy", hostileEntityId) + end + + -- Prevent the entity from dying by ticking its health up by a percentage point + status.setResourcePercentage("health", 0.01) + + -- Set this entity as isDefeated + self:setIsDefeated(true) + + -- Reset the defeat timer to 0 + self:setTimer(0) + + -- Attempt to transform this entity into a sexnode + self:retrieveActorData(hostileEntityId, hostileEntityType) + + return {} +end + +function SexboundDefeat:retrieveActorData(damageSourceEntity, damageSourceEntityType) + local entityId = self._entityId + self._promises:add( + world.sendEntityMessage( + entityId, + "Sexbound:Actor:GetActorData" + ), + function(actorData) + --find closest entity that's in the table + local found = false + local hostileEntityId = nil + local sexboundConfig = nil + local entities = world.entityQuery(entity.position(), 25, {includedTypes = {"monster","npc","player"}, order = "nearest"}) + for i,v in ipairs(entities) do + for i2,v2 in ipairs(self._hostileEntities) do + if v == v2[1] then + found = true + hostileEntityId = v2[1] + sexboundConfig = v2[2] + self._hostileEntityId = hostileEntityId + self._hostileEntityType = world.entityType(self._hostileEntityId) + break + end + end + if found then break end + end + if hostileEntityId then + --victory dialog, transform attempt + self:outputVictoryDialog() + self:transform(sexboundConfig, + function(result) + result = result or {} + if result.uniqueId == nil then + return self:handleTransformFailed() + end + return self:handleTransformSuccess(result.uniqueId) + end, function() + return self:handleTransformFailed() + end, + actorData + ) + else + self:tryToDie("Hostile entity not found in table") + end + end, + function() + self:tryToDie("Actor data retrieval failed") + end) + +end + +function SexboundDefeat:loadConfig() + local _,loadedConfig = xpcall(function() + return root.assetJson(self._configFilePath) + end, function(err) + sb.logError("Unable to load config file for Sexbound Defeat!") + end) + return loadedConfig +end + +function SexboundDefeat:outputDefeatedDialog() + if self:isNPC() and not self._config.enableStartDialogForNPCs then return end + if self:isMonster() and not self._config.enableStartDialogForMonsters then return end + local species = self:findSpecies() + local defeatedDialog = self._config.startDialog.defeated[species] or + self._config.startDialog.defeated.default + world.sendEntityMessage( + self._entityId, "Sexbound:Actor:Say", + { + message = util.randomChoice(defeatedDialog) + } + ) +end + +function SexboundDefeat:outputVictoryDialog() + if self._hostileEntityType == "npc" and not self._config.enableStartDialogForNPCs then return end + if self._hostileEntityType == "monster" and not self._config.enableStartDialogForMonsters then return end + local controllerSpecies = world.entitySpecies(self._hostileEntityId) + local victoryDialog = self._config.startDialog.victory[controllerSpecies] or + self._config.startDialog.victory.default + world.sendEntityMessage( + self._hostileEntityId, "Sexbound:Actor:Say", + { + message = util.randomChoice(victoryDialog) + } + ) +end + +function SexboundDefeat:retrieveSexboundConfig(successCallback, failureCallback, entityId) + self._promises:add( + world.sendEntityMessage( + entityId, + "Sexbound:Config:Retrieve" + ), + successCallback, + failureCallback + ) +end + +function SexboundDefeat:handleRetrieveSexboundConfigSuccess(sexboundConfig, hostileEntityId) + table.insert(self._hostileEntities, 1, {hostileEntityId, sexboundConfig}) + + if #self._hostileEntities > 8 then + table.remove(self._hostileEntities) + end + --[[ Output the victory dialog + self:outputVictoryDialog() + self:transform(sexboundConfig, function(result) + result = result or {} + if result.uniqueId == nil then + return self:handleTransformFailed() + end + return self:handleTransformSuccess(result.uniqueId) + end, function() + return self:handleTransformFailed() + end, + self._actorData + ) + ]] +end + + +function SexboundDefeat:transform(sexboundConfig, successCallback, failureCallback, actorData) + local position = nil + local entityId = self._entityId + if self:isPlayer() then + position = entity.position() + entityId = self._hostileEntityId + end + self._promises:add( + world.sendEntityMessage( + entityId, + "Sexbound:Transform", + { + responseRequired = true, + sexboundConfig = sexboundConfig, + timeout = 500, + position = position + }, + actorData or nil + ), + successCallback, + failureCallback + ) +end + +function SexboundDefeat:handleTransformFailed() + self:tryToDie("Transform failed") + return false +end + +function SexboundDefeat:handleTransformSuccess(nodeUniqueId) + self._sexNodeId = nodeUniqueId + self:setIsTransformed(true) + self:setTimer(0) + self:outputDefeatedDialog() + self:_initTimeout() + if self:isPlayer() then + -- Check config for using invisible "UI" that allows escape with ESC key + if self._config.enableDefeatedPlayerEscape then world.sendEntityMessage(self._entityId, "Sexbound:UI:Show", {config = self:loadUIConfig()}) end + status.addEphemeralEffect("sexbound_regen4", self._timeout) + end + + status.addEphemeralEffect("sexbound_sex", self._timeout) + status.addEphemeralEffect("sexbound_defeat_stun", self._timeout) + + -- Try to notify the controlling entity to mount the defeated player. + if (self._sexNodeId and self._hostileEntityId) then + self._promises:add(world.sendEntityMessage(self._sexNodeId, "Sexbound:Retrieve:ControllerId"), function(controllerId) + world.sendEntityMessage(self._hostileEntityId, "notify", {type = "sexbound.setup", targetId = controllerId}) + end) + end + + return true +end + +function SexboundDefeat:loadUIConfig() + local _,_config = xpcall(function() + return root.assetJson(self._uiConfigFilePath) + end, function(error) + sb.logError("Unable to load config file for the Sexbound Defeat!") + end) + _config.config.nodeUniqueId = self._sexNodeId + return _config or {} +end + +function SexboundDefeat:tryToDie(reason) + if reason then sb.logInfo("Sexbound Defeat Death: Name="..world.entityName(self._entityId).." reason: "..reason) end + self:setIsDefeated(false) + self:setIsTransformed(false) + if not self:isPlayer() and self:isPregnant() and self._config.enableImmortalPregnantNPCs then + local species = self:findSpecies() + local pregnantDialog = self._config.pregnantDialog[species] or self._config.pregnantDialog.default + world.sendEntityMessage(self._entityId, "Sexbound:Actor:Say", {message = util.randomChoice(pregnantDialog)}) + status.setResourcePercentage("health", 1.0) + else + status.setResourcePercentage("health", 0) + end +end + +function SexboundDefeat:smashSexNode(storage) + if not self._sexNodeId then return end + world.sendEntityMessage(self._sexNodeId, "Sexbound:Smash", { storage = storage }) +end + +-- [Helper] Untransform the Entity +function SexboundDefeat:untransform() + if not self:isPlayer() then self:tryToDie("non-player untransform") end + local storage = {} -- temp local storage + if not self:isPlayer() and self:isPregnant() and self._config.convertPregnantEnemiesToFriends then + storage = { previousDamageTeam = { type = "friendly", team = 1 } } + end + self:smashSexNode(storage) + if not self._hostileEntityId then return end + if self._hostileEntityType == "player" then return end + world.sendEntityMessage(self._hostileEntityId, "Sexbound:Actor:Respawn") + self._hostileEntityId = nil + self._hostileEntityType = nil + self._sexNodeId = nil + status.removeEphemeralEffect("sexbound_regen4") +end + +-- Validate Configuration +function SexboundDefeat:validateConfig() + self:_validateConvertPregnantEnemiesToFriends(self._config.convertPregnantEnemiesToFriends, false) + self:_validateDefeatedPlayersCanUseSexUI(self._config.defeatedPlayersCanUseSexUI, false) + self:_validateDefeatTimeoutMonster(self._config.defeatTimeoutMonster, 60) + self:_validateDefeatTimeoutNPC(self._config.defeatTimeoutNPC, 60) + self:_validateDefeatTimeoutPlayer(self._config.defeatTimeoutPlayer, 30) + self:_validateEnableImmortalPregnantNPCs(self._config.enableImmortalPregnantNPCs, false) + self:_validateEnableStartDialogForNPCs(self._config.enableStartDialogForNPCs, true) + self:_validateEnableStartDialogForMonsters(self._config.enableStartDialogForMonsters, false) + self:_validateEnableDefeatedPlayerEscape(self._config.enableDefeatedPlayerEscape, false) +end + +-- Getters / Setters +function SexboundDefeat:getConfig() + return self._config +end + +function SexboundDefeat:getTimer() + return self._timer +end + +function SexboundDefeat:getTimeout() + return self._timeout +end + +function SexboundDefeat:isDefeated() + return self._isDefeated or status.statusProperty("sexbound_defeated") +end + +function SexboundDefeat:isMonster() + return self._entityType == "monster" +end + +function SexboundDefeat:isNPC() + return self._entityType == "npc" +end + +function SexboundDefeat:isPlayer() + return self._entityType == "player" +end + +function SexboundDefeat:isPregnant() + return status.statusProperty("sexbound_pregnant") +end + +function SexboundDefeat:isStunned() + return status.statusProperty("sexbound_defeat_stun") +end + +function SexboundDefeat:isSuicide() + return self._hostileEntityId == self._entityId +end + +function SexboundDefeat:isTransformed() + return self._isTransformed or false +end + +function SexboundDefeat:setIsDefeated(isDefeated) + self._isDefeated = isDefeated + status.setStatusProperty("sexbound_defeated", isDefeated) +end + +function SexboundDefeat:setIsTransformed(isTransformed) + self._isTransformed = isTransformed +end + +function SexboundDefeat:setTimer(value) + self._timer = value +end + +function SexboundDefeat:setTimeout(value) + self._timeout = value +end + +-- Misc. helper functions +function SexboundDefeat:_initTimeout() + if self:isMonster() then + self:setTimeout(util.randomInRange(self._config.defeatTimeoutMonster)) + return + end + if self:isNPC() then + self:setTimeout(util.randomInRange(self._config.defeatTimeoutNPC)) + return + end + if self:isPlayer() then + self:setTimeout(util.randomInRange(self._config.defeatTimeoutPlayer)) + return + end +end + +function SexboundDefeat:_isBoolean(value) + return type(value) == "boolean" +end + +function SexboundDefeat:_isPositiveNumberOrNumberRange(value) + if type(value) == "number" and value > 0 then return true end + if type(value) == "table" and #value == 2 then + if type(value[1]) ~= "number" or value[1] <= 0 then return false end + if type(value[2]) ~= "number" or value[2] <= 0 then return false end + return true + end + return false +end + +function SexboundDefeat:_logWarnInvalidValueProvided(optionName, value) + local msg = "Invalid value was set for '" .. optionName .. "' option in " .. self._configFilePath .. " - " + msg = msg .. "Falling back to use the default value: " .. sb.printJson(value) + sb.logWarn(msg) +end + +function SexboundDefeat:_validateConvertPregnantEnemiesToFriends(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("convertPregnantEnemiesToFriends", defaultValue) + self._config.convertPregnantEnemiesToFriends = defaultValue +end + +function SexboundDefeat:_validateDefeatedPlayersCanUseSexUI(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("defeatedPlayersCanUseSexUI", defaultValue) + self._config.defeatedPlayersCanUseSexUI = defaultValue +end + +function SexboundDefeat:_validateDefeatTimeoutMonster(value, defaultValue) + if self:_isPositiveNumberOrNumberRange(value) then return end + self:_logWarnInvalidValueProvided("defeatTimeoutMonster", defaultValue) + self._config.defeatTimeoutMonster = defaultValue +end + +function SexboundDefeat:_validateDefeatTimeoutNPC(value, defaultValue) + if self:_isPositiveNumberOrNumberRange(value) then return end + self:_logWarnInvalidValueProvided("defeatTimeoutNPC", defaultValue) + self._config.defeatTimeoutNPC = defaultValue +end + +function SexboundDefeat:_validateDefeatTimeoutPlayer(value, defaultValue) + if self:_isPositiveNumberOrNumberRange(value) then return end + self:_logWarnInvalidValueProvided("defeatTimeoutPlayer", defaultValue) + self._config.defeatTimeoutPlayer = defaultValue +end + +function SexboundDefeat:_validateEnableImmortalPregnantNPCs(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("enableImmortalPregnantNPCs", defaultValue) + self._config.enableImmortalPregnantNPCs = defaultValue +end + +function SexboundDefeat:_validateEnableStartDialogForNPCs(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("enableStartDialogForNPCs", defaultValue) + self._config.enableStartDialogForNPCs = defaultValue +end + +function SexboundDefeat:_validateEnableStartDialogForMonsters(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("enableStartDialogForMonsters", defaultValue) + self._config.enableStartDialogForMonsters = defaultValue +end + +function SexboundDefeat:_validateEnableDefeatedPlayerEscape(value, defaultValue) + if self:_isBoolean(value) then return end + self:_logWarnInvalidValueProvided("enableDefeatedPlayerEscape", defaultValue) + self._config.enableDefeatedPlayerEscape = defaultValue +end \ No newline at end of file diff --git a/tilesets/packed/objects-special/sexscape_tileset.json b/tilesets/packed/objects-special/sexscape_tileset.json index 38ad45ef..00ccd888 100644 --- a/tilesets/packed/objects-special/sexscape_tileset.json +++ b/tilesets/packed/objects-special/sexscape_tileset.json @@ -1,12 +1,4 @@ { "columns":0, - "editorsettings": - { - "export": - { - "format":"", - "target":"." - } - }, "grid": { "height":1, @@ -16,8 +8,8 @@ "margin":0, "name":"lustbound_tileset", "spacing":0, - "tilecount":17, - "tiledversion":"1.3.5", + "tilecount":19, + "tiledversion":"1.8.0", "tileheight":88, "tileproperties": { @@ -105,6 +97,25 @@ "object":"sexbound_cardshop", "tilesetDirection":"right" }, + "17": + { + "\/\/description":"A stall that, one day, will sell Monster Girl Cards and related items.", + "\/\/name":"sexbound_cardshop_empty", + "\/\/shortdescription":"Card Sex Shop", + "imagePositionX":"-28", + "imagePositionY":"0", + "object":"sexbound_cardshop_empty", + "tilesetDirection":"right" + }, + "18": + { + "\/\/description":"An arcade sign. Sadly, it seems to be closed.", + "\/\/name":"arcadesign_off", + "\/\/shortdescription":"Arcade Sign (off)", + "imagePositionX":"-32", + "imagePositionY":"-8", + "object":"arcadesign_off" + }, "2": { "\/\/description":"These small bricks are masterfully crafted.", @@ -272,6 +283,25 @@ "object":"string", "tilesetDirection":"string" }, + "17": + { + "\/\/description":"string", + "\/\/name":"string", + "\/\/shortdescription":"string", + "imagePositionX":"string", + "imagePositionY":"string", + "object":"string", + "tilesetDirection":"string" + }, + "18": + { + "\/\/description":"string", + "\/\/name":"string", + "\/\/shortdescription":"string", + "imagePositionX":"string", + "imagePositionY":"string", + "object":"string" + }, "2": { "\/\/description":"string", @@ -409,6 +439,18 @@ "imageheight":40, "imagewidth":56 }, + "17": + { + "image":"..\/..\/..\/objects\/miscellaneous\/sexscapeshops\/sexbound_cardshoptiled_empty.png", + "imageheight":40, + "imagewidth":56 + }, + "18": + { + "image":"..\/..\/..\/objects\/miscellaneous\/sexscapeshops\/arcadesign_off.png", + "imageheight":24, + "imagewidth":64 + }, "2": { "image":"tombbrick3.png", @@ -458,7 +500,7 @@ "imagewidth":34 } }, - "tilewidth":56, + "tilewidth":64, "type":"tileset", "version":1.1 } \ No newline at end of file diff --git a/weather.config.patch b/weather.config.patch index 37698d95..429bc2bc 100644 --- a/weather.config.patch +++ b/weather.config.patch @@ -5,11 +5,11 @@ "value": [ [ 0.6, - "clear" + "lustiaclear" ], [ 0.4, - "glowingrain" + "lustiaglowingrain" ] ] } diff --git a/weather/lustia/lustiaclear.weather b/weather/lustia/lustiaclear.weather new file mode 100644 index 00000000..3a46dd71 --- /dev/null +++ b/weather/lustia/lustiaclear.weather @@ -0,0 +1,13 @@ +{ + "name" : "lustiaclear", + + "particleDensity" : 0, + "particles" : [ ], + "projectiles" : [ ], + + "statusEffects" : ["lustia_hornybuff"], + + "duration" : [40, 100], + "lightningFrequency" : 0.0, + "weatherNoises" : [ ] +} diff --git a/weather/lustia/lustiaglowingrain.weather b/weather/lustia/lustiaglowingrain.weather new file mode 100644 index 00000000..7b6d18fe --- /dev/null +++ b/weather/lustia/lustiaglowingrain.weather @@ -0,0 +1,21 @@ +{ + "name" : "lustiaglowingrain", + + "projectiles" : [ + { + "projectile" : "glowingrain", + "parameters" : { + "power" : 0 + }, + "velocity" : [0, -30], + "ratePerX" : 0.05, + "spawnAboveRegion" : 30, + "spawnHorizontalPad" : 30, + "windAffectAmount" : 1.0 + } + ], + "duration" : [50, 400], + "maximumWind" : 10.0, + + "statusEffects" : ["lustia_hornybuff"] +}