Merge remote-tracking branch 'upstream/master'

This commit is contained in:
skelsoft
2021-07-14 10:51:20 +10:00
28 changed files with 179673 additions and 9174 deletions
+1 -1
View File
@@ -222,7 +222,7 @@ First follow the [Github-Setup](#github-setup). After you have forked over your
1. Navigate to the right hand side of Intellij where it says "Gradle" 1. Navigate to the right hand side of Intellij where it says "Gradle"
* Gradle is very useful when it comes to running and compiling the project * Gradle is very useful when it comes to running and compiling the project
* The only tabs we are concerned about are "Client", "Management-Server", and "Server" * The only tabs we are concerned about are "Client", "Management-Server", and "Server"
* Each of these have a "Tasks" folder and an "application" folder * Each of these have a "Tasks" folder and an "application" folder inside of "Tasks"
<br> <br>
2. Click on the "application" folder for the Management-Server and double-click "run" 2. Click on the "application" folder for the Management-Server and double-click "run"
* The management server is used for things such as player data(not saves), highscores, and world information * The management server is used for things such as player data(not saves), highscores, and world information
+2 -2
View File
@@ -17,12 +17,12 @@ compileKotlin {
} }
repositories { repositories {
maven { url "https://dl.bintray.com/jetbrains/markdown" } mavenCentral()
} }
dependencies { dependencies {
implementation("com.github.ajalt.mordant:mordant:2.0.0-alpha2") implementation("com.github.ajalt.mordant:mordant:2.0.0-alpha2")
implementation "org.jetbrains:markdown-jvm:0.2.0.pre-55" implementation "org.jetbrains:markdown-jvm:0.2.0"
implementation 'com.google.guava:guava:29.0-jre' implementation 'com.google.guava:guava:29.0-jre'
implementation 'mysql:mysql-connector-java:8.0.21' implementation 'mysql:mysql-connector-java:8.0.21'
implementation 'io.github.classgraph:classgraph:4.8.98' implementation 'io.github.classgraph:classgraph:4.8.98'
+18 -15
View File
@@ -1,25 +1,28 @@
<RDT> <RDT>
<item id="995" minAmt="3000" maxAmt="3000" weight="12"/> <item id="995" minAmt="3000" maxAmt="3000" weight="12"/>
<item id="2363" minAmt="1" maxAmt="1" weight="7"/> <item id="1452" minAmt="1" maxAmt="1" weight="7"/>
<item id="1615" minAmt="1" maxAmt="1" weight="7"/> <item id="1462" minAmt="1" maxAmt="1" weight="7"/>
<item id="886" minAmt="150" maxAmt="150" weight="10"/>
<item id="443" minAmt="100" maxAmt="100" weight="7"/> <item id="443" minAmt="100" maxAmt="100" weight="7"/>
<item id="561" minAmt="1" maxAmt="67" weight="7"/> <item id="2363" minAmt="1" maxAmt="1" weight="7"/>
<item id="892" minAmt="1" maxAmt="20" weight="7"/> <item id="1623" minAmt="1" maxAmt="1" weight="12"/>
<item id="886" minAmt="150" maxAmt="150" weight="7"/> <item id="1621" minAmt="1" maxAmt="1" weight="10"/>
<item id="1619" minAmt="1" maxAmt="1" weight="8"/>
<item id="1617" minAmt="1" maxAmt="1" weight="7"/>
<item id="1615" minAmt="1" maxAmt="1" weight="5"/>
<item id="560" minAmt="45" maxAmt="45" weight="6"/>
<item id="563" minAmt="45" maxAmt="45" weight="6"/>
<item id="561" minAmt="67" maxAmt="67" weight="6"/>
<item id="892" minAmt="42" maxAmt="42" weight="6"/>
<item id="1319" minAmt="1" maxAmt="1" weight="7"/> <item id="1319" minAmt="1" maxAmt="1" weight="7"/>
<item id="1373" minAmt="1" maxAmt="1" weight="7"/> <item id="1373" minAmt="1" maxAmt="1" weight="7"/>
<item id="1185" minAmt="1" maxAmt="1" weight="7"/> <item id="1185" minAmt="1" maxAmt="1" weight="7"/>
<item id="1623" minAmt="1" maxAmt="1" weight="12"/> <item id="829" minAmt="20" maxAmt="20" weight="6"/>
<item id="1621" minAmt="1" maxAmt="1" weight="12"/> <item id="830" minAmt="5" maxAmt="5" weight="4"/>
<item id="1619" minAmt="1" maxAmt="1" weight="12"/> <item id="987" minAmt="1" maxAmt="1" weight="7"/>
<item id="1452" minAmt="1" maxAmt="1" weight="7"/> <item id="985" minAmt="1" maxAmt="1" weight="7"/>
<item id="1462" minAmt="1" maxAmt="1" weight="7"/>
<item id="1601" minAmt="1" maxAmt="1" weight="7"/>
<item id="830" minAmt="5" maxAmt="5" weight="3"/>
<item id="987" minAmt="1" maxAmt="1" weight="3"/>
<item id="985" minAmt="1" maxAmt="1" weight="3"/>
<item id="1149" minAmt="1" maxAmt="1" weight="3"/> <item id="1149" minAmt="1" maxAmt="1" weight="3"/>
<item id="1201" minAmt="1" maxAmt="1" weight="3"/> <item id="1201" minAmt="1" maxAmt="1" weight="4"/>
<item id="1247" minAmt="1" maxAmt="1" weight="1"/> <item id="1247" minAmt="1" maxAmt="1" weight="1"/>
<item id="2366" minAmt="1" maxAmt="1" weight="1"/> <item id="2366" minAmt="1" maxAmt="1" weight="1"/>
<item id="1249" minAmt="1" maxAmt="1" weight="1"/> <item id="1249" minAmt="1" maxAmt="1" weight="1"/>
File diff suppressed because it is too large Load Diff
+56 -56
View File
@@ -5715,7 +5715,7 @@
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "50.0", "weight": "25.0",
"id": "1181", "id": "1181",
"maxAmount": "1" "maxAmount": "1"
}, },
@@ -5729,38 +5729,20 @@
"minAmount": "12", "minAmount": "12",
"weight": "25.0", "weight": "25.0",
"id": "892", "id": "892",
"maxAmount": "42" "maxAmount": "12"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "5.0", "weight": "8.0",
"id": "1333", "id": "1333",
"maxAmount": "1" "maxAmount": "1"
}, },
{
"minAmount": "1",
"weight": "5.0",
"id": "1373",
"maxAmount": "1"
},
{ {
"minAmount": "37", "minAmount": "37",
"weight": "50.0", "weight": "25.0",
"id": "554", "id": "554",
"maxAmount": "37" "maxAmount": "37"
}, },
{
"minAmount": "50",
"weight": "50.0",
"id": "554",
"maxAmount": "50"
},
{
"minAmount": "150",
"weight": "50.0",
"id": "554",
"maxAmount": "150"
},
{ {
"minAmount": "5", "minAmount": "5",
"weight": "25.0", "weight": "25.0",
@@ -5769,15 +5751,15 @@
}, },
{ {
"minAmount": "5", "minAmount": "5",
"weight": "25.0", "weight": "8.0",
"id": "565", "id": "565",
"maxAmount": "5" "maxAmount": "5"
}, },
{ {
"minAmount": "24", "minAmount": "2",
"weight": "25.0", "weight": "8.0",
"id": "563", "id": "563",
"maxAmount": "24" "maxAmount": "2"
}, },
{ {
"minAmount": "1", "minAmount": "1",
@@ -5799,7 +5781,7 @@
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "50.0", "weight": "8.0",
"id": "211", "id": "211",
"maxAmount": "1" "maxAmount": "1"
}, },
@@ -5811,46 +5793,40 @@
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "25.0", "weight": "8.0",
"id": "207", "id": "207",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "25.0", "weight": "8.0",
"id": "209", "id": "209",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "25.0", "weight": "8.0",
"id": "215", "id": "215",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "5.0", "weight": "8.0",
"id": "2485", "id": "2485",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "5.0", "weight": "8.0",
"id": "213", "id": "213",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "5.0", "weight": "8.0",
"id": "217", "id": "217",
"maxAmount": "1" "maxAmount": "1"
}, },
{
"minAmount": "15",
"weight": "50.0",
"id": "995",
"maxAmount": "15"
},
{ {
"minAmount": "25", "minAmount": "25",
"weight": "50.0", "weight": "50.0",
@@ -5858,8 +5834,14 @@
"maxAmount": "25" "maxAmount": "25"
}, },
{ {
"minAmount": "1", "minAmount": "60",
"weight": "50.0", "weight": "50.0",
"id": "995",
"maxAmount": "60"
},
{
"minAmount": "1",
"weight": "25.0",
"id": "7872", "id": "7872",
"maxAmount": "1" "maxAmount": "1"
}, },
@@ -5895,13 +5877,7 @@
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "5.0", "weight": "8.0",
"id": "987",
"maxAmount": "1"
},
{
"minAmount": "1",
"weight": "5.0",
"id": "31", "id": "31",
"maxAmount": "1" "maxAmount": "1"
}, },
@@ -5910,6 +5886,30 @@
"weight": "100.0", "weight": "100.0",
"id": "0", "id": "0",
"maxAmount": "1" "maxAmount": "1"
},
{
"minAmount": "1",
"weight": "25.0",
"id": "1145",
"maxAmount": "1"
},
{
"minAmount": "1",
"weight": "5.0",
"id": "5733",
"maxAmount": "1"
},
{
"minAmount": "100",
"weight": "25.0",
"id": "554",
"maxAmount": "100"
},
{
"minAmount": "150",
"weight": "25.0",
"id": "554",
"maxAmount": "150"
} }
] ]
}, },
@@ -26486,19 +26486,19 @@
}, },
{ {
"minAmount": "50", "minAmount": "50",
"weight": "50.0", "weight": "25.0",
"id": "556", "id": "556",
"maxAmount": "50" "maxAmount": "50"
}, },
{ {
"minAmount": "7", "minAmount": "7",
"weight": "50.0", "weight": "25.0",
"id": "565", "id": "565",
"maxAmount": "7" "maxAmount": "7"
}, },
{ {
"minAmount": "10", "minAmount": "10",
"weight": "50.0", "weight": "25.0",
"id": "562", "id": "562",
"maxAmount": "10" "maxAmount": "10"
}, },
@@ -26512,7 +26512,7 @@
"minAmount": "30", "minAmount": "30",
"weight": "100.0", "weight": "100.0",
"id": "995", "id": "995",
"maxAmount": "3000" "maxAmount": "690"
}, },
{ {
"minAmount": "1", "minAmount": "1",
@@ -26546,25 +26546,25 @@
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "25.0", "weight": "5.0",
"id": "2727", "id": "12070",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "25.0", "weight": "22.0",
"id": "31", "id": "31",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "2.5", "weight": "2.2",
"id": "4151", "id": "4151",
"maxAmount": "1" "maxAmount": "1"
}, },
{ {
"minAmount": "1", "minAmount": "1",
"weight": "150.0", "weight": "100.0",
"id": "0", "id": "0",
"maxAmount": "1" "maxAmount": "1"
} }
+43 -43
View File
@@ -2095,7 +2095,7 @@
"requirements": "{3,15}", "requirements": "{3,15}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "155", "grand_exchange_price": "150",
"durability": null, "durability": null,
"name": "Grimy guam", "name": "Grimy guam",
"tradeable": "true", "tradeable": "true",
@@ -2115,7 +2115,7 @@
"requirements": "{5,15}", "requirements": "{5,15}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "26", "grand_exchange_price": "150",
"durability": null, "durability": null,
"name": "Grimy marrentill", "name": "Grimy marrentill",
"tradeable": "true", "tradeable": "true",
@@ -2135,7 +2135,7 @@
"requirements": "{11,15}", "requirements": "{11,15}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "151", "grand_exchange_price": "150",
"durability": null, "durability": null,
"name": "Grimy tarromin", "name": "Grimy tarromin",
"tradeable": "true", "tradeable": "true",
@@ -2155,7 +2155,7 @@
"requirements": "{20,15}", "requirements": "{20,15}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "275", "grand_exchange_price": "300",
"durability": null, "durability": null,
"name": "Grimy harralander", "name": "Grimy harralander",
"tradeable": "true", "tradeable": "true",
@@ -2175,7 +2175,7 @@
"requirements": "{15,25}", "requirements": "{15,25}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "4909", "grand_exchange_price": "1300",
"durability": null, "durability": null,
"name": "Grimy ranarr", "name": "Grimy ranarr",
"tradeable": "true", "tradeable": "true",
@@ -2195,7 +2195,7 @@
"requirements": "{15,40}", "requirements": "{15,40}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "2034", "grand_exchange_price": "900",
"durability": null, "durability": null,
"name": "Grimy irit", "name": "Grimy irit",
"tradeable": "true", "tradeable": "true",
@@ -2215,7 +2215,7 @@
"requirements": "{15,48}", "requirements": "{15,48}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "3789", "grand_exchange_price": "500",
"durability": null, "durability": null,
"name": "Grimy avantoe", "name": "Grimy avantoe",
"tradeable": "true", "tradeable": "true",
@@ -2235,7 +2235,7 @@
"requirements": "{15,54}", "requirements": "{15,54}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "1665", "grand_exchange_price": "900",
"durability": null, "durability": null,
"name": "Grimy kwuarm", "name": "Grimy kwuarm",
"tradeable": "true", "tradeable": "true",
@@ -2255,7 +2255,7 @@
"requirements": "{15,65}", "requirements": "{15,65}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "1582", "grand_exchange_price": "900",
"durability": null, "durability": null,
"name": "Grimy cadantine", "name": "Grimy cadantine",
"tradeable": "true", "tradeable": "true",
@@ -2275,7 +2275,7 @@
"requirements": "{15,70}", "requirements": "{15,70}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "6934", "grand_exchange_price": "1300",
"durability": null, "durability": null,
"name": "Grimy dwarf weed", "name": "Grimy dwarf weed",
"tradeable": "true", "tradeable": "true",
@@ -2295,7 +2295,7 @@
"requirements": "{15,75}", "requirements": "{15,75}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "8200", "grand_exchange_price": "3200",
"durability": null, "durability": null,
"name": "Grimy torstol", "name": "Grimy torstol",
"tradeable": "true", "tradeable": "true",
@@ -4371,7 +4371,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Some hard dry clay.", "examine": "Some hard dry clay.",
"grand_exchange_price": "406", "grand_exchange_price": "150",
"durability": null, "durability": null,
"name": "Clay", "name": "Clay",
"tradeable": "true", "tradeable": "true",
@@ -4391,7 +4391,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "This needs refining.", "examine": "This needs refining.",
"grand_exchange_price": "58", "grand_exchange_price": "80",
"tokkul_price": "4", "tokkul_price": "4",
"durability": null, "durability": null,
"name": "Copper ore", "name": "Copper ore",
@@ -4420,7 +4420,7 @@
"low_alchemy": "8", "low_alchemy": "8",
"high_alchemy": "12", "high_alchemy": "12",
"weight": "2.25", "weight": "2.25",
"grand_exchange_price": "46", "grand_exchange_price": "80",
"name": "Tin ore", "name": "Tin ore",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@@ -4438,7 +4438,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "This needs refining.", "examine": "This needs refining.",
"grand_exchange_price": "396", "grand_exchange_price": "230",
"tokkul_price": "25", "tokkul_price": "25",
"durability": null, "durability": null,
"name": "Iron ore", "name": "Iron ore",
@@ -4523,7 +4523,7 @@
"low_alchemy": "64", "low_alchemy": "64",
"high_alchemy": "97", "high_alchemy": "97",
"weight": "1.75", "weight": "1.75",
"grand_exchange_price": "369", "grand_exchange_price": "460",
"name": "Mithril ore", "name": "Mithril ore",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@@ -4547,7 +4547,7 @@
"low_alchemy": "160", "low_alchemy": "160",
"high_alchemy": "240", "high_alchemy": "240",
"weight": "2.7", "weight": "2.7",
"grand_exchange_price": "1622", "grand_exchange_price": "1330",
"name": "Adamantite ore", "name": "Adamantite ore",
"tradeable": "true", "tradeable": "true",
"archery_ticket_price": "0", "archery_ticket_price": "0",
@@ -4588,7 +4588,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Hmm a non-renewable energy source!", "examine": "Hmm a non-renewable energy source!",
"grand_exchange_price": "315", "grand_exchange_price": "350",
"tokkul_price": "67", "tokkul_price": "67",
"durability": null, "durability": null,
"name": "Coal", "name": "Coal",
@@ -5363,7 +5363,7 @@
{ {
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "These would feed a dog for months.", "examine": "These would feed a dog for months.",
"grand_exchange_price": "4065", "grand_exchange_price": "1300",
"durability": null, "durability": null,
"name": "Dragon bones", "name": "Dragon bones",
"tradeable": "true", "tradeable": "true",
@@ -5539,7 +5539,7 @@
"shop_price": "17", "shop_price": "17",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "One of the 4 basic elemental Runes.", "examine": "One of the 4 basic elemental Runes.",
"grand_exchange_price": "39", "grand_exchange_price": "17",
"tokkul_price": "6", "tokkul_price": "6",
"durability": null, "durability": null,
"name": "Fire rune", "name": "Fire rune",
@@ -5553,7 +5553,7 @@
"shop_price": "17", "shop_price": "17",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "One of the 4 basic elemental Runes.", "examine": "One of the 4 basic elemental Runes.",
"grand_exchange_price": "15", "grand_exchange_price": "17",
"tokkul_price": "6", "tokkul_price": "6",
"durability": null, "durability": null,
"name": "Water rune", "name": "Water rune",
@@ -5567,7 +5567,7 @@
"shop_price": "17", "shop_price": "17",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "One of the 4 basic elemental Runes.", "examine": "One of the 4 basic elemental Runes.",
"grand_exchange_price": "37", "grand_exchange_price": "17",
"tokkul_price": "6", "tokkul_price": "6",
"durability": null, "durability": null,
"name": "Air rune", "name": "Air rune",
@@ -5581,7 +5581,7 @@
"shop_price": "17", "shop_price": "17",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "One of the 4 basic elemental Runes.", "examine": "One of the 4 basic elemental Runes.",
"grand_exchange_price": "25", "grand_exchange_price": "17",
"tokkul_price": "6", "tokkul_price": "6",
"durability": null, "durability": null,
"name": "Earth rune", "name": "Earth rune",
@@ -5595,7 +5595,7 @@
"shop_price": "17", "shop_price": "17",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for basic missile spells.", "examine": "Used for basic missile spells.",
"grand_exchange_price": "6", "grand_exchange_price": "17",
"tokkul_price": "4", "tokkul_price": "4",
"durability": null, "durability": null,
"name": "Mind rune", "name": "Mind rune",
@@ -5609,7 +5609,7 @@
"shop_price": "16", "shop_price": "16",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for Curse spells", "examine": "Used for Curse spells",
"grand_exchange_price": "6", "grand_exchange_price": "16",
"tokkul_price": "4", "tokkul_price": "4",
"durability": null, "durability": null,
"name": "Body rune", "name": "Body rune",
@@ -5623,7 +5623,7 @@
"shop_price": "310", "shop_price": "310",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for medium missile spells.", "examine": "Used for medium missile spells.",
"grand_exchange_price": "433", "grand_exchange_price": "235",
"durability": null, "durability": null,
"name": "Death rune", "name": "Death rune",
"tradeable": "true", "tradeable": "true",
@@ -5636,7 +5636,7 @@
"shop_price": "372", "shop_price": "372",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for alchemy spells.", "examine": "Used for alchemy spells.",
"grand_exchange_price": "228", "grand_exchange_price": "325",
"durability": null, "durability": null,
"name": "Nature rune", "name": "Nature rune",
"tradeable": "true", "tradeable": "true",
@@ -5649,7 +5649,7 @@
"shop_price": "140", "shop_price": "140",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for small missile spells.", "examine": "Used for small missile spells.",
"grand_exchange_price": "54", "grand_exchange_price": "145",
"durability": null, "durability": null,
"name": "Chaos rune", "name": "Chaos rune",
"tradeable": "true", "tradeable": "true",
@@ -5662,7 +5662,7 @@
"shop_price": "378", "shop_price": "378",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for teleport spells.", "examine": "Used for teleport spells.",
"grand_exchange_price": "349", "grand_exchange_price": "350",
"durability": null, "durability": null,
"name": "Law rune", "name": "Law rune",
"tradeable": "true", "tradeable": "true",
@@ -5675,7 +5675,7 @@
"shop_price": "232", "shop_price": "232",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for enchant spells.", "examine": "Used for enchant spells.",
"grand_exchange_price": "158", "grand_exchange_price": "180",
"durability": null, "durability": null,
"name": "Cosmic rune", "name": "Cosmic rune",
"tradeable": "true", "tradeable": "true",
@@ -5688,7 +5688,7 @@
"shop_price": "550", "shop_price": "550",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for large missile spells.", "examine": "Used for large missile spells.",
"grand_exchange_price": "408", "grand_exchange_price": "435",
"durability": null, "durability": null,
"name": "Blood rune", "name": "Blood rune",
"tradeable": "true", "tradeable": "true",
@@ -5701,7 +5701,7 @@
"shop_price": "400", "shop_price": "400",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Used for high level curse spells.", "examine": "Used for high level curse spells.",
"grand_exchange_price": "187", "grand_exchange_price": "230",
"durability": null, "durability": null,
"name": "Soul rune", "name": "Soul rune",
"tradeable": "true", "tradeable": "true",
@@ -17229,7 +17229,7 @@
"shop_price": "4", "shop_price": "4",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "A number of wooden logs.", "examine": "A number of wooden logs.",
"grand_exchange_price": "279", "grand_exchange_price": "120",
"durability": null, "durability": null,
"name": "Logs", "name": "Logs",
"tradeable": "true", "tradeable": "true",
@@ -17251,7 +17251,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Logs cut from a magic tree.", "examine": "Logs cut from a magic tree.",
"grand_exchange_price": "1581", "grand_exchange_price": "750",
"durability": null, "durability": null,
"name": "Magic logs", "name": "Magic logs",
"tradeable": "true", "tradeable": "true",
@@ -17273,7 +17273,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Logs cut from a yew tree.", "examine": "Logs cut from a yew tree.",
"grand_exchange_price": "532", "grand_exchange_price": "360",
"durability": null, "durability": null,
"name": "Yew logs", "name": "Yew logs",
"tradeable": "true", "tradeable": "true",
@@ -17295,7 +17295,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Logs cut from a maple tree.", "examine": "Logs cut from a maple tree.",
"grand_exchange_price": "20", "grand_exchange_price": "180",
"durability": null, "durability": null,
"name": "Maple logs", "name": "Maple logs",
"tradeable": "true", "tradeable": "true",
@@ -17317,7 +17317,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Logs cut from a willow tree.", "examine": "Logs cut from a willow tree.",
"grand_exchange_price": "11", "grand_exchange_price": "80",
"durability": null, "durability": null,
"name": "Willow logs", "name": "Willow logs",
"tradeable": "true", "tradeable": "true",
@@ -17339,7 +17339,7 @@
{ {
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "Logs cut from an Oak Tree.", "examine": "Logs cut from an Oak Tree.",
"grand_exchange_price": "153", "grand_exchange_price": "160",
"durability": null, "durability": null,
"name": "Oak logs", "name": "Oak logs",
"tradeable": "true", "tradeable": "true",
@@ -19419,7 +19419,7 @@
{ {
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I should take this to the tannery.", "examine": "I should take this to the tannery.",
"grand_exchange_price": "516", "grand_exchange_price": "150",
"durability": null, "durability": null,
"name": "Cowhide", "name": "Cowhide",
"tradeable": "true", "tradeable": "true",
@@ -19567,7 +19567,7 @@
{ {
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "The scaly rough hide from a green dragon.", "examine": "The scaly rough hide from a green dragon.",
"grand_exchange_price": "1933", "grand_exchange_price": "1000",
"durability": null, "durability": null,
"name": "Green dragonhide", "name": "Green dragonhide",
"tradeable": "true", "tradeable": "true",
@@ -19833,7 +19833,7 @@
{ {
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need a bow stave to attach this to.", "examine": "I need a bow stave to attach this to.",
"grand_exchange_price": "223", "grand_exchange_price": "250",
"durability": null, "durability": null,
"name": "Bow string", "name": "Bow string",
"tradeable": "true", "tradeable": "true",
@@ -26832,7 +26832,7 @@
"requirements": "{15,67}", "requirements": "{15,67}",
"ge_buy_limit": "10000", "ge_buy_limit": "10000",
"examine": "I need to clean this herb before I can use it.", "examine": "I need to clean this herb before I can use it.",
"grand_exchange_price": "7210", "grand_exchange_price": "900",
"durability": null, "durability": null,
"name": "Grimy lantadyme", "name": "Grimy lantadyme",
"tradeable": "true", "tradeable": "true",
@@ -76029,7 +76029,7 @@
"shop_price": "1", "shop_price": "1",
"ge_buy_limit": "25000", "ge_buy_limit": "25000",
"examine": "An uncharged Rune Stone of extra capability.", "examine": "An uncharged Rune Stone of extra capability.",
"grand_exchange_price": "109", "grand_exchange_price": "180",
"durability": null, "durability": null,
"name": "Pure essence", "name": "Pure essence",
"tradeable": "true", "tradeable": "true",
File diff suppressed because it is too large Load Diff
+32
View File
@@ -10686,5 +10686,37 @@
{ {
"npc_id": "5463", "npc_id": "5463",
"loc_data": "{2324,3809,0,1,0}-{2317,3802,0,1,0}" "loc_data": "{2324,3809,0,1,0}-{2317,3802,0,1,0}"
},
{
"npc_id": "5521",
"loc_data": "{2324,3832,0,1,0}-{2350,3859,0,1,0}-{2375,3892,0,1,0}-{2388,3867,0,1,0}-{2384,3863,0,1,0}-{2387,3859,0,1,0}-{2350,3862,0,1,0}-{2352,3857,0,1,0}"
},
{
"npc_id": "5523",
"loc_data": "{2367,3832,0,1,0}-{2319,3854,0,1,0}-{2324,3891,0,1,0}-{2406,3854,0,1,0}-{2405,3863,0,1,0}-{2400,3856,0,1,0}"
},
{
"npc_id": "5522",
"loc_data": "{2362,3893,0,1,0}-{2390,3861,0,1,0}-{2395,3859,0,1,0}-{2323,3857,0,1,0}-{2331,3860,0,1,0}"
},
{
"npc_id": "5524",
"loc_data": "{2340,3830,0,1,0}-{2338,3860,0,1,0}-{2339,3895,0,1,0}-{2411,3886,0,1,0}-{2396,3854,0,1,0}"
},
{
"npc_id": "5514",
"loc_data": "{2337,3831,0,1,0}-{2399,3852,0,1,0}-{2321,3833,0,1,0}"
},
{
"npc_id": "5515",
"loc_data": "{2327,3858,0,1,0}-{2321,3860,0,1,0}-{2343,3862,0,1,0}"
},
{
"npc_id": "5516",
"loc_data": "{2393,3861,0,1,0}-{2347,3890,0,1,0}-{2347,3890,0,1,0}"
},
{
"npc_id": "5517",
"loc_data": "{2403,3853,0,1,0}-{2328,3830,0,1,0}-{2405,3860,0,1,0}-{2335,3894,0,1,0}"
} }
] ]
@@ -3,6 +3,7 @@ package core.game.ge;
import core.game.component.Component; import core.game.component.Component;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.tools.StringUtils; import core.tools.StringUtils;
import rs09.game.ge.OfferManager;
/** /**
* Represents the glass used to open the guide prices for the different type of * Represents the glass used to open the guide prices for the different type of
@@ -139,7 +140,7 @@ public final class GEGuidePrice {
player.getPacketDispatch().sendInterfaceConfig(642, i, false); player.getPacketDispatch().sendInterfaceConfig(642, i, false);
} }
for (GuideItem item : getItems()) { for (GuideItem item : getItems()) {
player.getPacketDispatch().sendString("" + GrandExchangeDatabase.getDatabase().get(item.getItem()).getValue() + " gp", COMPONENT.getId(), item.getChildData()[0]); player.getPacketDispatch().sendString("" + OfferManager.getRecommendedPrice(item.item, false) + " gp", COMPONENT.getId(), item.getChildData()[0]);
} }
} }
} }
@@ -22,6 +22,7 @@ import core.plugin.Initializable;
import core.plugin.Plugin; import core.plugin.Plugin;
import kotlin.Unit; import kotlin.Unit;
import rs09.game.ge.GrandExchangeOffer; import rs09.game.ge.GrandExchangeOffer;
import rs09.game.ge.OfferManager;
import rs09.game.ge.PlayerGrandExchange; import rs09.game.ge.PlayerGrandExchange;
import rs09.game.interaction.npc.BogrogPouchSwapper; import rs09.game.interaction.npc.BogrogPouchSwapper;
import rs09.game.world.GameWorld; import rs09.game.world.GameWorld;
@@ -69,7 +70,7 @@ public class GrandExchangeInterface extends ComponentPlugin {
if (offer == null || value < 1 || offer.getOfferState() != OfferState.PENDING) { if (offer == null || value < 1 || offer.getOfferState() != OfferState.PENDING) {
return; return;
} }
if (value == GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue()) { if (value == OfferManager.getRecommendedPrice(offer.getItemID(), false)) {
player.getAudioManager().send(new Audio(4043, 1, 1)); player.getAudioManager().send(new Audio(4043, 1, 1));
} else if (value > offer.getOfferedValue()) { } else if (value > offer.getOfferedValue()) {
player.getAudioManager().send(new Audio(4041, 1, 1)); player.getAudioManager().send(new Audio(4041, 1, 1));
@@ -77,7 +78,7 @@ public class GrandExchangeInterface extends ComponentPlugin {
player.getAudioManager().send(new Audio(4045, 1, 1)); player.getAudioManager().send(new Audio(4045, 1, 1));
} }
offer.setOfferedValue(value); offer.setOfferedValue(value);
player.getConfigManager().send(1111, offer.getOfferedValue()); player.varpManager.get(1111).setVarbit(0,offer.getOfferedValue()).send(player);
} }
@Override @Override
@@ -348,14 +349,14 @@ public class GrandExchangeInterface extends ComponentPlugin {
return false; return false;
case 180: case 180:
if (offer != null) { if (offer != null) {
setOfferValue(player, offer, GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue()); setOfferValue(player, offer, OfferManager.getRecommendedPrice(offer.getItemID(), false));
return true; return true;
} }
return false; return false;
case 177: // mid - 5% value case 177: // mid - 5% value
case 183: // mid + 5% value case 183: // mid + 5% value
if (offer != null) { if (offer != null) {
setOfferValue(player, offer, (int) (GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue() * (button == 177 ? 0.95 : 1.05))); setOfferValue(player, offer, (int) (OfferManager.getRecommendedPrice(offer.getItemID(), false) * (button == 177 ? 0.95 : 1.05)));
return true; return true;
} }
return false; return false;
@@ -19,6 +19,7 @@ import rs09.game.ai.AIPlayer;
import rs09.game.ai.AIRepository; import rs09.game.ai.AIRepository;
import rs09.game.ai.general.GeneralBotCreator; import rs09.game.ai.general.GeneralBotCreator;
import rs09.game.content.global.NPCDropTable; import rs09.game.content.global.NPCDropTable;
import rs09.game.ge.OfferManager;
import rs09.game.system.config.ItemConfigParser; import rs09.game.system.config.ItemConfigParser;
import rs09.game.world.repository.Repository; import rs09.game.world.repository.Repository;
@@ -177,7 +178,7 @@ public final class NPCDropTables {
} }
} }
player.sendMessage(player.getInterfaceManager().isResizable()+""); player.sendMessage(player.getInterfaceManager().isResizable()+"");
int price = item.getName().endsWith("charm") ? 100 : GrandExchangeDatabase.getDatabase().get(itemId).getValue(); int price = item.getName().endsWith("charm") ? 100 : OfferManager.getRecommendedPrice(itemId, false);
looter.getGlobalData().setLootSharePoints(looter.getGlobalData().getLootSharePoints() - (price) + ((price / looters.size()))); looter.getGlobalData().setLootSharePoints(looter.getGlobalData().getLootSharePoints() - (price) + ((price / looters.size())));
looter.sendMessage((player.getInterfaceManager().isResizable() ? "<col=32CD32>" : "<col=009900>") + "You received: " + item.getAmount() + " " + item.getName()); looter.sendMessage((player.getInterfaceManager().isResizable() ? "<col=32CD32>" : "<col=009900>") + "You received: " + item.getAmount() + " " + item.getName());
for (Player p : looters) { for (Player p : looters) {
@@ -81,8 +81,8 @@ public final class BansheeNPC extends AbstractNPC {
} }
@Override @Override
public void checkImpact(BattleState state) { public void onImpact(Entity entity, BattleState state) {
super.checkImpact(state); super.onImpact(entity, state);
if (state.getAttacker() instanceof Player) { if (state.getAttacker() instanceof Player) {
final Player player = (Player) state.getAttacker(); final Player player = (Player) state.getAttacker();
if (!hasEarMuffs(player)) { if (!hasEarMuffs(player)) {
@@ -8,6 +8,7 @@ import core.game.interaction.Interaction;
import core.game.interaction.OptionHandler; import core.game.interaction.OptionHandler;
import core.game.node.Node; import core.game.node.Node;
import core.game.node.entity.combat.equipment.DegradableEquipment; import core.game.node.entity.combat.equipment.DegradableEquipment;
import rs09.game.ge.OfferManager;
/** /**
* Represents an item. * Represents an item.
@@ -99,10 +100,7 @@ public class Item extends Node{
*/ */
public long getValue() { public long getValue() {
long value = 1; long value = 1;
GrandExchangeEntry entry = GrandExchangeDatabase.getDatabase().get(getId()); value = OfferManager.getRecommendedPrice(getId(), false);
if (entry != null) {
value = entry.getValue();
}
if (definition.getValue() > value) { if (definition.getValue() > value) {
value = definition.getValue(); value = definition.getValue();
} }
@@ -89,6 +89,7 @@ public final class MultiwayCombatZone extends MapZone {
registerRegion(13370);//Venenatis registerRegion(13370);//Venenatis
registerRegion(12603);//Callisto registerRegion(12603);//Callisto
registerRegion(14939);//Kalphite Stronghold Cave registerRegion(14939);//Kalphite Stronghold Cave
registerRegion(9532); //Isle north of Jatizso
} }
@Override @Override
@@ -161,7 +161,7 @@ public class GrandExchangeTab extends ConsoleTab {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
} }
for (GrandExchangeOffer o : OfferManager.Companion.getOffersForItem(itemId)) { for (GrandExchangeOffer o : OfferManager.getOffersForItem(itemId)) {
if (o == null) { if (o == null) {
continue; continue;
} }
@@ -184,7 +184,7 @@ public class GrandExchangeTab extends ConsoleTab {
JOptionPane.showMessageDialog(null, "Error! No data in DB yet. Press load."); JOptionPane.showMessageDialog(null, "Error! No data in DB yet. Press load.");
return; return;
} }
for (GrandExchangeOffer offer : OfferManager.Companion.getOFFER_MAPPING().values()) { for (GrandExchangeOffer offer : OfferManager.getOFFER_MAPPING().values()) {
model.addElement(offer); model.addElement(offer);
} }
} }
+10 -1
View File
@@ -600,7 +600,7 @@ object ContentAPI {
*/ */
@JvmStatic @JvmStatic
fun findLocalNPCs(entity: Entity, ids: IntArray): List<NPC>{ fun findLocalNPCs(entity: Entity, ids: IntArray): List<NPC>{
return RegionManager.getSurroundingNPCs(entity).filter { it.id in ids }.toList() return RegionManager.getLocalNpcs(entity).filter { it.id in ids }.toList()
} }
/** /**
@@ -1146,4 +1146,13 @@ object ContentAPI {
fun addClimbDest(ladderLoc: Location, dest: Location){ fun addClimbDest(ladderLoc: Location, dest: Location){
SpecialLadders.add(ladderLoc,dest) SpecialLadders.add(ladderLoc,dest)
} }
/**
* Sends a news announcement in game chat.
* @param message the message to announce
*/
@JvmStatic
fun sendNews(message: String){
Repository.sendNews(message, 12, "CC6600")
}
} }
@@ -1,5 +1,6 @@
package rs09.game.ai.general package rs09.game.ai.general
import api.ContentAPI
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.component.Component import core.game.component.Component
import core.game.content.consumable.Consumable import core.game.content.consumable.Consumable
@@ -31,6 +32,7 @@ import rs09.game.ai.AIRepository
import rs09.game.ge.GrandExchangeOffer import rs09.game.ge.GrandExchangeOffer
import rs09.game.ge.OfferManager import rs09.game.ge.OfferManager
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import rs09.game.system.config.ItemConfigParser
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository import rs09.game.world.repository.Repository
import rs09.tools.stringtools.colorize import rs09.tools.stringtools.colorize
@@ -675,33 +677,7 @@ class ScriptAPI(private val bot: Player) {
*/ */
fun checkPriceOverrides(id: Int): Int?{ fun checkPriceOverrides(id: Int): Int?{
return when(id){ return when(id){
Items.PURE_ESSENCE_7936 -> 50 else -> ContentAPI.itemDefinition(id).getConfiguration(ItemConfigParser.GE_PRICE)
Items.BOW_STRING_1777 -> 250
Items.MAGIC_LOGS_1513 -> 750
Items.COWHIDE_1739 -> 250
Items.DRAGON_BONES_536 -> 1250
Items.GREEN_DRAGONHIDE_1753 -> 550
Items.GRIMY_RANARR_207 -> 1214
Items.GRIMY_AVANTOE_211 -> 453
Items.GRIMY_CADANTINE_215 -> 232
Items.GRIMY_DWARF_WEED_217 -> 86
Items.GRIMY_GUAM_199 -> 50
Items.GRIMY_HARRALANDER_205 -> 115
Items.GRIMY_IRIT_209 -> 860
Items.GRIMY_KWUARM_213 -> 334
Items.GRIMY_LANTADYME_2485 -> 115
Items.GRIMY_MARRENTILL_201 -> 250
Items.LOBSTER_379 -> 268
Items.RAW_LOBSTER_377 -> 265
Items.LOOP_HALF_OF_A_KEY_987 -> 5250
Items.TOOTH_HALF_OF_A_KEY_985-> 4263
Items.SWORDFISH_373 -> 400
Items.RAW_SWORDFISH_371 -> 390
Items.SHARK_385 -> 720
Items.RAW_SHARK_383 -> 710
Items.TEAK_LOGS_6333 -> 350
Items.MAHOGANY_LOGS_6332 -> 847
else -> null
} }
} }
@@ -0,0 +1,46 @@
package rs09.game.ge
import core.game.world.callback.CallBack
import rs09.game.system.SystemLogger
import rs09.tools.secondsToTicks
object GrandExchange : CallBack {
/**
* Fallback safety check to make sure we don't start the GE twice under any circumstance
*/
var isRunning = false
/**
* Initializes the offer manager and spawns an update thread.
* @param local whether or not the GE should be the local in-code server rather than some hypothetical remote implementation.
*/
fun boot(local: Boolean){
if(isRunning) return
if(!local){
TODO("Remote GE server stuff")
}
SystemLogger.logGE("Initializing GE...")
OfferManager.init()
SystemLogger.logGE("GE Initialized.")
SystemLogger.logGE("Initializing GE Update Worker")
val t = Thread {
Thread.currentThread().name = "GE Update Worker"
while(true) {
SystemLogger.logGE("Updating offers...")
OfferManager.update()
Thread.sleep(60_000) //sleep for 60 seconds
}
}.start()
isRunning = true
}
override fun call(): Boolean {
boot(true)
return true
}
}
@@ -1,5 +1,6 @@
package rs09.game.ge package rs09.game.ge
import api.ContentAPI
import rs09.ServerConstants import rs09.ServerConstants
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.content.eco.EcoStatus import core.game.content.eco.EcoStatus
@@ -23,524 +24,507 @@ import org.json.simple.JSONArray
import org.json.simple.JSONObject import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser import org.json.simple.parser.JSONParser
import rs09.game.ai.AIPlayer import rs09.game.ai.AIPlayer
import rs09.game.system.config.ItemConfigParser
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
import java.io.FileWriter import java.io.FileWriter
import java.io.IOException import java.io.IOException
import java.lang.Integer.max
import java.lang.Integer.min import java.lang.Integer.min
import java.util.* import java.util.*
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import javax.script.ScriptEngineManager import javax.script.ScriptEngineManager
import kotlin.collections.ArrayList
class OfferManager : Pulse(), CallBack { object OfferManager {
/** /**
* How often in ticks should ge offers that hit the buying limit be reprocessed? * The update notification.
*/ */
private val RESET_BUYING_LIMIT_INTERVAL = 24000 private const val UPDATE_NOTIFICATION = "One or more of your grand exchange offers have been updated."
/** /**
* How often should the database be saved to disk? * The database path.
*/ */
private val SAVE_EVERY = ServerConstants.GE_AUTOSAVE_FREQUENCY private val DB_PATH = ServerConstants.GRAND_EXCHANGE_DATA_PATH + "offer_dispatch.json"
override fun call(): Boolean { /**
init() * Bot DB path
delay = 1 */
GameWorld.Pulser.submit(this) private val BOT_DB_PATH = ServerConstants.GRAND_EXCHANGE_DATA_PATH + "bot_offers.json"
/**
* The offset of the offer UIDs.
*/
private var offsetUID: Long = 1
/**
* The mapping of all current offers. Stored in multiple maps.
*
* First map is offsetID, Offer
* Second is itemID, offsetID, Offer
* Final is playerID, offsetID, Offer
*/
@JvmStatic
val OFFER_MAPPING: MutableMap<Long, GrandExchangeOffer> = HashMap()
val OFFERS_BY_ITEMID: MutableMap<Int, MutableList<GrandExchangeOffer>> = HashMap()
private val GE_OFFER_LOCK = ReentrantLock()
/**
* Bot offers are sorted by itemID.
* the second int shows the offer amount. Negative is buying positive selling.
*/
public val BOT_OFFERS: HashMap<Int, Int> = HashMap()
/**
* If the database should be dumped.
*/
public var dumpDatabase = false
/**
* Initializes the Grand Exchange.
*/
fun init() {
GE_OFFER_LOCK.lock()
val file = File(DB_PATH)
if(file.exists() && file.length() != 0L) {
val parser = JSONParser()
val reader: FileReader? = FileReader(DB_PATH)
val saveFile = parser.parse(reader) as JSONObject
offsetUID = saveFile["offsetUID"].toString().toLong()
if (saveFile.containsKey("offers")) {
val offers = saveFile["offers"] as JSONArray
for (offer in offers) {
val o = offer as JSONObject
// Copy all the bot offers from the file
if (o["playerUID"].toString().toInt() == 0) {
addBotOffer(o["itemId"].toString().toInt(), o["amount"].toString().toInt() - o["completedAmount"].toString().toInt())
}
val no = GrandExchangeOffer()
no.itemID = o["itemId"].toString().toInt()
no.sell = o["sale"] as Boolean
no.offeredValue = o["offeredValue"].toString().toInt()
no.amount = o["amount"].toString().toInt()
no.timeStamp = o["timeStamp"].toString().toLong()
no.uid = o["uid"].toString().toLong()
no.completedAmount = o["completedAmount"].toString().toInt()
no.playerUID = o["playerUID"].toString().toInt()
no.offerState = OfferState.values()[o["offerState"].toString().toInt()]
no.totalCoinExchange = o["totalCoinExchange"].toString().toInt()
val withdrawData = o["withdrawItems"] as JSONArray
for ((index, data) in withdrawData.withIndex()) {
val item = data as JSONObject
val it = Item(item["id"].toString().toInt(), item["amount"].toString().toInt())
no.withdraw[index] = it
}
addEntry(no)
}
}
}
if(File(BOT_DB_PATH).exists()) {
try {
val botReader: FileReader? = FileReader(BOT_DB_PATH)
val botSave = JSONParser().parse(botReader) as JSONObject
if (botSave.containsKey("offers")) {
val offers = botSave["offers"] as JSONArray
for (offer in offers) {
val o = offer as JSONObject
addBotOffer(o["item"].toString().toInt(), o["qty"].toString().toInt())
}
}
} catch (e: IOException) {
SystemLogger.logWarn("Unable to load bot offers. Perhaps it doesn't exist?")
}
}
GE_OFFER_LOCK.unlock()
}
fun update(){
for (offer in OFFER_MAPPING.values) {
if (offer.isActive) {
updateOffer(offer)
}
}
}
fun buyFromBots(offer: GrandExchangeOffer) {
if (BOT_OFFERS[offer.itemID] == null) {
return
}
val botPrice = getRecommendedPrice(offer.itemID, true)
if (offer.offeredValue < botPrice) {
return
}
val amount = min(BOT_OFFERS[offer.itemID]!!, getBuylimitAmount(offer))
val botOffer = GrandExchangeOffer()
botOffer.sell = true
botOffer.amount = amount
botOffer.offerState = OfferState.REGISTERED
botOffer.offeredValue = botPrice
exchange(offer, botOffer)
BOT_OFFERS[offer.itemID] = BOT_OFFERS[offer.itemID]!! - amount
}
private fun buyFromBotsWithItem(itemID: Int) {
if (OFFERS_BY_ITEMID[itemID] == null || BOT_OFFERS[itemID] == null) {
return
}
for (trade in OFFERS_BY_ITEMID[itemID]!!) {
if (!trade.sell) {
buyFromBots(trade)
}
}
}
fun addBotOffer(itemID: Int, qty: Int): Boolean {
if (GrandExchangeDatabase.getDatabase()[itemID] == null) {
SystemLogger.logWarn("Bot attempted to sell invalid item $itemID")
return false
}
if (BOT_OFFERS[itemID] == null) {
BOT_OFFERS[itemID] = qty
} else {
BOT_OFFERS[itemID] = (qty + BOT_OFFERS[itemID]!!)
}
buyFromBotsWithItem(itemID)
return true return true
} }
override fun pulse(): Boolean { fun amtBotsSelling(itemID: Int): Int {
// TODO: Update offers code if (BOT_OFFERS[itemID] == null) {
if (GameWorld.ticks % RESET_BUYING_LIMIT_INTERVAL == 0) { return 0
BuyingLimitation.clear()
for (offer in OFFER_MAPPING.values) {
if (offer.isActive && offer.isLimitation) {
updateOffer(offer)
}
}
} }
if (BOT_OFFERS[itemID]!! <= 0) {
if (dumpDatabase && (GameWorld.ticks % SAVE_EVERY == 0)) { return 0
//save()
dumpDatabase = false
} }
return BOT_OFFERS[itemID]!!
return false
} }
fun setIndex(offerID: Long, idx: Int) {
if (!OFFER_MAPPING.containsKey(offerID)) {
println("ERROR. GE Entry $offerID not found in database. Playerdata may be corrupted.")
return
}
OFFER_MAPPING[offerID]!!.index = idx
}
companion object { fun removeEntry(offer: GrandExchangeOffer): Boolean{
/** println("REMOVING ENTRY of ID " + offer.itemID)
* The update notification. GE_OFFER_LOCK.lock()
*/ if (!OFFER_MAPPING.containsKey(offer.uid)){
private const val UPDATE_NOTIFICATION = "One or more of your grand exchange offers have been updated."
/**
* The database path.
*/
private val DB_PATH = ServerConstants.GRAND_EXCHANGE_DATA_PATH + "offer_dispatch.json"
/**
* Bot DB path
*/
private val BOT_DB_PATH = ServerConstants.GRAND_EXCHANGE_DATA_PATH + "bot_offers.json"
/**
* The offset of the offer UIDs.
*/
private var offsetUID: Long = 1
/**
* The mapping of all current offers. Stored in multiple maps.
*
* First map is offsetID, Offer
* Second is itemID, offsetID, Offer
* Final is playerID, offsetID, Offer
*/
val OFFER_MAPPING: MutableMap<Long, GrandExchangeOffer> = HashMap()
val OFFERS_BY_ITEMID: MutableMap<Int, MutableList<GrandExchangeOffer>> = HashMap()
private val GE_OFFER_LOCK = ReentrantLock()
/**
* Bot offers are sorted by itemID.
* the second int shows the offer amount. Negative is buying positive selling.
*/
public val BOT_OFFERS: HashMap<Int, Int> = HashMap()
/**
* If the database should be dumped.
*/
public var dumpDatabase = false
/**
* Initializes the Grand Exchange.
*/
fun init() {
GE_OFFER_LOCK.lock()
val file = File(DB_PATH)
if(file.exists() && file.length() != 0L) {
val parser = JSONParser()
val reader: FileReader? = FileReader(DB_PATH)
val saveFile = parser.parse(reader) as JSONObject
offsetUID = saveFile["offsetUID"].toString().toLong()
if (saveFile.containsKey("offers")) {
val offers = saveFile["offers"] as JSONArray
for (offer in offers) {
val o = offer as JSONObject
// Copy all the bot offers from the file
if (o["playerUID"].toString().toInt() == 0) {
addBotOffer(o["itemId"].toString().toInt(), o["amount"].toString().toInt() - o["completedAmount"].toString().toInt())
}
val no = GrandExchangeOffer()
no.itemID = o["itemId"].toString().toInt()
no.sell = o["sale"] as Boolean
no.offeredValue = o["offeredValue"].toString().toInt()
no.amount = o["amount"].toString().toInt()
no.timeStamp = o["timeStamp"].toString().toLong()
no.uid = o["uid"].toString().toLong()
no.completedAmount = o["completedAmount"].toString().toInt()
no.playerUID = o["playerUID"].toString().toInt()
no.offerState = OfferState.values()[o["offerState"].toString().toInt()]
no.totalCoinExchange = o["totalCoinExchange"].toString().toInt()
val withdrawData = o["withdrawItems"] as JSONArray
for ((index, data) in withdrawData.withIndex()) {
val item = data as JSONObject
val it = Item(item["id"].toString().toInt(), item["amount"].toString().toInt())
no.withdraw[index] = it
}
addEntry(no)
}
}
}
if(File(BOT_DB_PATH).exists()) {
try {
val botReader: FileReader? = FileReader(BOT_DB_PATH)
val botSave = JSONParser().parse(botReader) as JSONObject
if (botSave.containsKey("offers")) {
val offers = botSave["offers"] as JSONArray
for (offer in offers) {
val o = offer as JSONObject
addBotOffer(o["item"].toString().toInt(), o["qty"].toString().toInt())
}
}
} catch (e: IOException) {
SystemLogger.logWarn("Unable to load bot offers. Perhaps it doesn't exist?")
}
}
GE_OFFER_LOCK.unlock() GE_OFFER_LOCK.unlock()
return false
} }
OFFER_MAPPING.remove(offer.uid)
OFFERS_BY_ITEMID[offer.itemID]!!.remove(offer)
GE_OFFER_LOCK.unlock()
return true
}
fun buyFromBots(offer: GrandExchangeOffer) { fun addEntry(offer: GrandExchangeOffer){
if (BOT_OFFERS[offer.itemID] == null) { GE_OFFER_LOCK.lock()
return OFFER_MAPPING[offer.uid] = offer
} if (!OFFERS_BY_ITEMID.containsKey(offer.itemID)) {
val botPrice = BotPrices.getPrice(offer.itemID) OFFERS_BY_ITEMID[offer.itemID] = mutableListOf()
if (offer.offeredValue < botPrice) {
return
}
val amount = min(BOT_OFFERS[offer.itemID]!!, getBuylimitAmount(offer))
val botOffer = GrandExchangeOffer()
botOffer.sell = true
botOffer.amount = amount
botOffer.offerState = OfferState.REGISTERED
botOffer.offeredValue = botPrice
exchange(offer, botOffer)
BOT_OFFERS[offer.itemID] = BOT_OFFERS[offer.itemID]!! - amount
} }
OFFERS_BY_ITEMID[offer.itemID]!!.add(offer)
GE_OFFER_LOCK.unlock()
}
private fun buyFromBotsWithItem(itemID: Int) { fun getQuantitySoldForItem(item: Int): Int {
if (OFFERS_BY_ITEMID[itemID] == null || BOT_OFFERS[itemID] == null) { var qty = 0
return val offs = getOffersForItem(item)
} for (o in offs) {
for (trade in OFFERS_BY_ITEMID[itemID]!!) { if (o.sell) {
if (!trade.sell) { qty += o.amountLeft
buyFromBots(trade)
}
} }
} }
qty += amtBotsSelling(item)
return qty
}
fun addBotOffer(itemID: Int, qty: Int): Boolean { @JvmStatic
if (GrandExchangeDatabase.getDatabase()[itemID] == null) { fun getOffersForItem(item: Int): MutableList<GrandExchangeOffer> {
SystemLogger.logWarn("Bot attempted to sell invalid item $itemID") if (OFFERS_BY_ITEMID.containsKey(item)) {
return false return OFFERS_BY_ITEMID[item]!!
} }
return mutableListOf()
}
if (BOT_OFFERS[itemID] == null) { @JvmStatic
BOT_OFFERS[itemID] = qty fun save(){
} else { GE_OFFER_LOCK.lock()
BOT_OFFERS[itemID] = (qty + BOT_OFFERS[itemID]!!) val root = JSONObject()
} val offers = JSONArray()
buyFromBotsWithItem(itemID)
return true if(OFFER_MAPPING.isEmpty() && BOT_OFFERS.isEmpty()){
return
} }
fun amtBotsSelling(itemID: Int): Int { for(entry in OFFER_MAPPING){
if (BOT_OFFERS[itemID] == null) { val offer = entry.value
return 0 if (offer.offerState == OfferState.REMOVED || entry.value.playerUID == PlayerDetails.getDetails("2009scape").uid) {
continue
} }
if (BOT_OFFERS[itemID]!! <= 0) { val o = JSONObject()
return 0 o["uid"] = entry.key.toString()
o["itemId"] = offer.itemID.toString()
o["sale"] = offer.sell
o["amount"] = offer.amount.toString()
o["completedAmount"] = offer.completedAmount.toString()
o["offeredValue"] = offer.offeredValue.toString()
o["timeStamp"] = offer.timeStamp.toString()
o["offerState"] = offer.offerState.ordinal.toString()
o["totalCoinExchange"] = offer.totalCoinExchange.toString()
o["playerUID"] = offer.playerUID.toString()
val withdrawItems = JSONArray()
for(item in offer.withdraw){
item ?: continue
val it = JSONObject()
it["id"] = item.id.toString()
it["amount"] = item.amount.toString()
withdrawItems.add(it)
} }
return BOT_OFFERS[itemID]!! o["withdrawItems"] = withdrawItems
offers.add(o)
} }
root["offsetUID"] = offsetUID.toString()
root["offers"] = offers
fun setIndex(offerID: Long, idx: Int) { val manager = ScriptEngineManager()
if (!OFFER_MAPPING.containsKey(offerID)) { val scriptEngine = manager.getEngineByName("JavaScript")
println("ERROR. GE Entry $offerID not found in database. Playerdata may be corrupted.") scriptEngine.put("jsonString", root.toJSONString())
return scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
} val prettyPrintedJson = scriptEngine["result"] as String
OFFER_MAPPING[offerID]!!.index = idx
val botRoot = JSONObject()
val botOffers = JSONArray()
for ((item, qty) in BOT_OFFERS) {
val o = JSONObject()
o["item"] = item
o["qty"] = qty
botOffers.add(o)
} }
botRoot["offers"] = botOffers
fun removeEntry(offer: GrandExchangeOffer): Boolean{ scriptEngine.put("jsonString", botRoot.toJSONString())
println("REMOVING ENTRY of ID " + offer.itemID) scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
GE_OFFER_LOCK.lock() val botJson = scriptEngine["result"] as String
if (!OFFER_MAPPING.containsKey(offer.uid)){
GE_OFFER_LOCK.unlock()
return false try {
FileWriter(DB_PATH).use { file ->
file.write(prettyPrintedJson)
file.flush()
file.close()
} }
OFFER_MAPPING.remove(offer.uid) FileWriter(BOT_DB_PATH).use { file ->
OFFERS_BY_ITEMID[offer.itemID]!!.remove(offer) file.write(botJson)
GE_OFFER_LOCK.unlock() file.flush()
return true file.close()
}
} catch (e: Exception) {
e.printStackTrace()
} }
GE_OFFER_LOCK.unlock()
}
fun addEntry(offer: GrandExchangeOffer){ /**
GE_OFFER_LOCK.lock() * Dispatches an offer.
OFFER_MAPPING[offer.uid] = offer * @param player The player.
if (!OFFERS_BY_ITEMID.containsKey(offer.itemID)) { * @param offer The grand exchange offer.
OFFERS_BY_ITEMID[offer.itemID] = mutableListOf() * @return `True` if successful.
} */
OFFERS_BY_ITEMID[offer.itemID]!!.add(offer) @JvmStatic
GE_OFFER_LOCK.unlock() fun dispatch(player: Player, offer: GrandExchangeOffer): Boolean {
if (offer.amount < 1) {
player.packetDispatch.sendMessage("You must choose the quantity you wish to buy!")
println("amountthing")
return false
} }
if (offer.offeredValue < 1) {
fun getQuantitySoldForItem(item: Int): Int { player.packetDispatch.sendMessage("You must choose the price you wish to buy for!")
var qty = 0 println("pricethng")
val offs = getOffersForItem(item) return false
for (o in offs) {
if (o.sell) {
qty += o.amountLeft
}
}
qty += amtBotsSelling(item)
return qty
} }
if (offer.offerState != OfferState.PENDING || offer.uid != 0L) {
fun getOffersForItem(item: Int): MutableList<GrandExchangeOffer> { println("pendingthing")
if (OFFERS_BY_ITEMID.containsKey(item)) { return false
return OFFERS_BY_ITEMID[item]!!
}
return mutableListOf()
} }
if (player.isArtificial) {
@JvmStatic offer.playerUID = PlayerDetails.getDetails("2009scape").uid
fun save(){ // Repository.sendNews("2009scape wants " + offer.amount + " " + ItemDefinition.forId(offer.itemID).name.toLowerCase() + " for " + offer.offeredValue + "each.")
GE_OFFER_LOCK.lock() } else {
val root = JSONObject() offer.playerUID = player.details.uid
val offers = JSONArray()
if(OFFER_MAPPING.isEmpty() && BOT_OFFERS.isEmpty()){
return
}
for(entry in OFFER_MAPPING){
val offer = entry.value
if (offer.offerState == OfferState.REMOVED || entry.value.playerUID == PlayerDetails.getDetails("2009scape").uid) {
continue
}
val o = JSONObject()
o["uid"] = entry.key.toString()
o["itemId"] = offer.itemID.toString()
o["sale"] = offer.sell
o["amount"] = offer.amount.toString()
o["completedAmount"] = offer.completedAmount.toString()
o["offeredValue"] = offer.offeredValue.toString()
o["timeStamp"] = offer.timeStamp.toString()
o["offerState"] = offer.offerState.ordinal.toString()
o["totalCoinExchange"] = offer.totalCoinExchange.toString()
o["playerUID"] = offer.playerUID.toString()
val withdrawItems = JSONArray()
for(item in offer.withdraw){
item ?: continue
val it = JSONObject()
it["id"] = item.id.toString()
it["amount"] = item.amount.toString()
withdrawItems.add(it)
}
o["withdrawItems"] = withdrawItems
offers.add(o)
}
root["offsetUID"] = offsetUID.toString()
root["offers"] = offers
val manager = ScriptEngineManager()
val scriptEngine = manager.getEngineByName("JavaScript")
scriptEngine.put("jsonString", root.toJSONString())
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
val prettyPrintedJson = scriptEngine["result"] as String
val botRoot = JSONObject()
val botOffers = JSONArray()
for ((item, qty) in BOT_OFFERS) {
val o = JSONObject()
o["item"] = item
o["qty"] = qty
botOffers.add(o)
}
botRoot["offers"] = botOffers
scriptEngine.put("jsonString", botRoot.toJSONString())
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
val botJson = scriptEngine["result"] as String
try {
FileWriter(DB_PATH).use { file ->
file.write(prettyPrintedJson)
file.flush()
file.close()
}
FileWriter(BOT_DB_PATH).use { file ->
file.write(botJson)
file.flush()
file.close()
}
} catch (e: Exception) {
e.printStackTrace()
}
GE_OFFER_LOCK.unlock()
} }
offer.uid = nextUID()
/** offer.offerState = OfferState.REGISTERED
* Dispatches an offer. addEntry(offer)
* @param player The player. offer.timeStamp = System.currentTimeMillis()
* @param offer The grand exchange offer. player.playerGrandExchange.update(offer)
* @return `True` if successful. if (offer.sell) {
*/ Repository.sendNews(player.username + " just offered " + offer.amount + " " + ItemDefinition.forId(offer.itemID).name.toLowerCase() + " on the GE.")
@JvmStatic
fun dispatch(player: Player, offer: GrandExchangeOffer): Boolean {
if (offer.amount < 1) {
player.packetDispatch.sendMessage("You must choose the quantity you wish to buy!")
println("amountthing")
return false
}
if (offer.offeredValue < 1) {
player.packetDispatch.sendMessage("You must choose the price you wish to buy for!")
println("pricethng")
return false
}
if (offer.offerState != OfferState.PENDING || offer.uid != 0L) {
println("pendingthing")
return false
}
if (player.isArtificial) {
offer.playerUID = PlayerDetails.getDetails("2009scape").uid
// Repository.sendNews("2009scape wants " + offer.amount + " " + ItemDefinition.forId(offer.itemID).name.toLowerCase() + " for " + offer.offeredValue + "each.")
} else {
offer.playerUID = player.details.uid
}
offer.uid = nextUID()
offer.offerState = OfferState.REGISTERED
addEntry(offer)
offer.timeStamp = System.currentTimeMillis()
player.playerGrandExchange.update(offer)
if (offer.sell) {
Repository.sendNews(player.username + " just offered " + offer.amount + " " + ItemDefinition.forId(offer.itemID).name.toLowerCase() + " on the GE.")
}
if(player !is AIPlayer) {
SystemLogger.logTrade("[GE] ${player.username} ${if (offer.sell) "listed for sale" else "listed buy offer for"} ${offer.amount} ${ItemDefinition.forId(offer.itemID).name.toLowerCase()}")
}
dumpDatabase = true
return true
} }
if(player !is AIPlayer) {
/** SystemLogger.logTrade("[GE] ${player.username} ${if (offer.sell) "listed for sale" else "listed buy offer for"} ${offer.amount} ${ItemDefinition.forId(offer.itemID).name.toLowerCase()}")
* Updates the offer.
* @param offer The G.E. offer to update.
*/
@JvmStatic
fun updateOffer(offer: GrandExchangeOffer) {
if (!offer.isActive) {
return
}
GE_OFFER_LOCK.lock()
for (o in OFFERS_BY_ITEMID[offer.itemID]!!) {
if (o.sell != offer.sell && o.isActive) {
exchange(offer, o)
if (offer.offerState == OfferState.COMPLETED) {
break
}
}
}
buyFromBots(offer)
GE_OFFER_LOCK.unlock()
} }
dumpDatabase = true
return true
}
private fun getBuylimitAmount(offer: GrandExchangeOffer): Int { /**
var left = offer.amountLeft * Updates the offer.
if (!offer.sell && left > 0) { * @param offer The G.E. offer to update.
val maximum = BuyingLimitation.getMaximumBuy(offer.itemID, offer.playerUID) */
if (left >= maximum) { @JvmStatic
left = maximum fun updateOffer(offer: GrandExchangeOffer) {
offer.isLimitation = true if (!offer.isActive) {
} return
}
return left
} }
GE_OFFER_LOCK.lock()
/** for (o in OFFERS_BY_ITEMID[offer.itemID]!!) {
* Exchanges between 2 offers. if (o.sell != offer.sell && o.isActive) {
* @param offer The grand exchange offer to update. exchange(offer, o)
* @param o The other offer to exchange with. if (offer.offerState == OfferState.COMPLETED) {
*/
private fun exchange(offer: GrandExchangeOffer, o: GrandExchangeOffer) {
if (o.sell == offer.sell) {
return
}
if (offer.sell && o.offeredValue < offer.offeredValue || !offer.sell && o.offeredValue > offer.offeredValue) {
return
}
var amount = min(getBuylimitAmount(offer), getBuylimitAmount(o))
if (amount < 1) {
return
}
var coinDifference = if (offer.sell) o.offeredValue - offer.offeredValue else offer.offeredValue - o.offeredValue
if (coinDifference < 0) {
return
}
if (EconomyManagement.getEcoState() == EcoStatus.DRAINING) {
coinDifference *= (1.0 - EconomyManagement.getModificationRate()).toInt()
}
offer.completedAmount = offer.completedAmount + amount
o.completedAmount = o.completedAmount + amount
offer.offerState = if (offer.amountLeft < 1) OfferState.COMPLETED else OfferState.UPDATED
o.offerState = if (o.amountLeft < 1) OfferState.COMPLETED else OfferState.UPDATED
if (offer.sell) {
if (offer.amountLeft < 1 && offer.player != null) {
offer.player!!.audioManager.send(Audio(4042, 1, 1))
}
addWithdraw(offer,995, amount * offer.offeredValue)
addWithdraw(o, o.itemID, amount)
BuyingLimitation.updateBoughtAmount(o.itemID, o.playerUID, amount)
} else {
if (o.amountLeft < 1 && o.player != null) {
o.player!!.audioManager.send(Audio(4042, 1, 1))
}
addWithdraw(offer, offer.itemID, amount)
addWithdraw(o, 995, amount * o.offeredValue)
BuyingLimitation.updateBoughtAmount(offer.itemID, offer.playerUID, amount)
}
if (coinDifference > 0) {
if (offer.sell) {
addWithdraw(o, 995, coinDifference * amount)
} else {
addWithdraw(offer, 995, coinDifference * amount)
}
}
GrandExchangeDatabase.getDatabase()[o.itemID]?.influenceValue(o.offeredValue)
offer.player?.packetDispatch?.sendMessage(UPDATE_NOTIFICATION)
o.player?.packetDispatch?.sendMessage(UPDATE_NOTIFICATION)
o.player?.playerGrandExchange?.update(o)
offer.player?.playerGrandExchange?.update(offer)
dumpDatabase = true
}
/**
* Adds a new item to withdraw.
* @param itemId The item id.
* @param amount The amount to add.
* @param abort If the item is added due to abort.
*/
fun addWithdraw(offer: GrandExchangeOffer, itemId: Int, amount: Int, abort: Boolean = false) {
if (!abort) {
if (offer.sell) {
if (itemId == 995) {
offer.totalCoinExchange += amount
}
} else {
if (itemId == 995) {
offer.totalCoinExchange -= amount
} else {
offer.totalCoinExchange += offer.offeredValue * amount
}
}
}
for (i in offer.withdraw.indices) {
if (offer.withdraw[i] == null) {
offer.withdraw[i] = Item(itemId, amount)
break
}
if (offer.withdraw[i]!!.id == itemId) {
offer.withdraw[i]!!.amount = offer.withdraw[i]!!.amount + amount
break break
} }
} }
if (offer.player != null) { }
PacketRepository.send( buyFromBots(offer)
ContainerPacket::class.java, GE_OFFER_LOCK.unlock()
ContainerContext(offer.player, -1, -1757, 523 + offer.index, offer.withdraw, false) }
)
private fun getBuylimitAmount(offer: GrandExchangeOffer): Int {
var left = offer.amountLeft
if (!offer.sell && left > 0) {
val maximum = BuyingLimitation.getMaximumBuy(offer.itemID, offer.playerUID)
if (left >= maximum) {
left = maximum
offer.isLimitation = true
} }
} }
return left
}
/** /**
* Gets the next UID. * Exchanges between 2 offers.
* @return The UID. * @param offer The grand exchange offer to update.
*/ * @param o The other offer to exchange with.
private fun nextUID(): Long { */
val id = offsetUID++ private fun exchange(offer: GrandExchangeOffer, o: GrandExchangeOffer) {
return if (id == 0L) { if (o.sell == offer.sell) {
nextUID() return
} else id }
if (offer.sell && o.offeredValue < offer.offeredValue || !offer.sell && o.offeredValue > offer.offeredValue) {
return
}
var amount = min(getBuylimitAmount(offer), getBuylimitAmount(o))
if (amount < 1) {
return
}
var coinDifference = if (offer.sell) o.offeredValue - offer.offeredValue else offer.offeredValue - o.offeredValue
if (coinDifference < 0) {
return
}
if (EconomyManagement.getEcoState() == EcoStatus.DRAINING) {
coinDifference *= (1.0 - EconomyManagement.getModificationRate()).toInt()
}
offer.completedAmount = offer.completedAmount + amount
o.completedAmount = o.completedAmount + amount
offer.offerState = if (offer.amountLeft < 1) OfferState.COMPLETED else OfferState.UPDATED
o.offerState = if (o.amountLeft < 1) OfferState.COMPLETED else OfferState.UPDATED
if (offer.sell) {
if (offer.amountLeft < 1 && offer.player != null) {
offer.player!!.audioManager.send(Audio(4042, 1, 1))
}
addWithdraw(offer,995, amount * offer.offeredValue)
addWithdraw(o, o.itemID, amount)
BuyingLimitation.updateBoughtAmount(o.itemID, o.playerUID, amount)
} else {
if (o.amountLeft < 1 && o.player != null) {
o.player!!.audioManager.send(Audio(4042, 1, 1))
}
addWithdraw(offer, offer.itemID, amount)
addWithdraw(o, 995, amount * o.offeredValue)
BuyingLimitation.updateBoughtAmount(offer.itemID, offer.playerUID, amount)
}
if (coinDifference > 0) {
if (offer.sell) {
addWithdraw(o, 995, coinDifference * amount)
} else {
addWithdraw(offer, 995, coinDifference * amount)
}
}
GrandExchangeDatabase.getDatabase()[o.itemID]?.influenceValue(o.offeredValue)
offer.player?.packetDispatch?.sendMessage(UPDATE_NOTIFICATION)
o.player?.packetDispatch?.sendMessage(UPDATE_NOTIFICATION)
o.player?.playerGrandExchange?.update(o)
offer.player?.playerGrandExchange?.update(offer)
dumpDatabase = true
}
/**
* Adds a new item to withdraw.
* @param itemId The item id.
* @param amount The amount to add.
* @param abort If the item is added due to abort.
*/
fun addWithdraw(offer: GrandExchangeOffer, itemId: Int, amount: Int, abort: Boolean = false) {
if (!abort) {
if (offer.sell) {
if (itemId == 995) {
offer.totalCoinExchange += amount
}
} else {
if (itemId == 995) {
offer.totalCoinExchange -= amount
} else {
offer.totalCoinExchange += offer.offeredValue * amount
}
}
}
for (i in offer.withdraw.indices) {
if (offer.withdraw[i] == null) {
offer.withdraw[i] = Item(itemId, amount)
break
}
if (offer.withdraw[i]!!.id == itemId) {
offer.withdraw[i]!!.amount = offer.withdraw[i]!!.amount + amount
break
}
}
if (offer.player != null) {
PacketRepository.send(
ContainerPacket::class.java,
ContainerContext(offer.player, -1, -1757, 523 + offer.index, offer.withdraw, false)
)
} }
} }
/**
* Gets the next UID.
* @return The UID.
*/
private fun nextUID(): Long {
val id = offsetUID++
return if (id == 0L) {
nextUID()
} else id
}
private fun getItemDefPrice(itemID: Int): Int {
return max(ContentAPI.itemDefinition(itemID).getConfiguration(ItemConfigParser.GE_PRICE) ?: 0, ContentAPI.itemDefinition(itemID).value)
}
@JvmStatic
fun getRecommendedPrice(itemID: Int, from_bot: Boolean = false): Int {
val base = max(GrandExchangeDatabase.getDatabase()[itemID]?.value ?: 0, getItemDefPrice(itemID))
return if(from_bot) (base + (base * 0.1).toInt())
else base
}
} }
@@ -1,5 +1,6 @@
package rs09.game.ge package rs09.game.ge
import api.ContentAPI
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.component.CloseEvent import core.game.component.CloseEvent
import core.game.component.Component import core.game.component.Component
@@ -27,8 +28,6 @@ import core.net.packet.out.GrandExchangePacket
import org.json.simple.JSONArray import org.json.simple.JSONArray
import org.json.simple.JSONObject import org.json.simple.JSONObject
import org.rs09.consts.Components import org.rs09.consts.Components
import rs09.game.ge.OfferManager.Companion.dispatch
import rs09.game.ge.OfferManager.Companion.updateOffer
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
@@ -319,13 +318,13 @@ class PlayerGrandExchange(private val player: Player) {
temporaryOffer!!.itemID = itemId temporaryOffer!!.itemID = itemId
temporaryOffer!!.sell = false temporaryOffer!!.sell = false
var itemDb = GrandExchangeDatabase.getDatabase()[itemId] var itemDb = GrandExchangeDatabase.getDatabase()[itemId]
if (itemDb == null) { if (itemDb == null || !ContentAPI.itemDefinition(itemId).isTradeable) {
player.packetDispatch.sendMessage("This item has been blacklisted from the Grand Exchange.") player.packetDispatch.sendMessage("This item has been blacklisted from the Grand Exchange.")
return return
} }
temporaryOffer!!.player = player temporaryOffer!!.player = player
temporaryOffer!!.amount = 1 temporaryOffer!!.amount = 1
temporaryOffer!!.offeredValue = itemDb.value temporaryOffer!!.offeredValue = OfferManager.getRecommendedPrice(itemId)
temporaryOffer!!.index = openedIndex temporaryOffer!!.index = openedIndex
sendConfiguration(temporaryOffer, false) sendConfiguration(temporaryOffer, false)
} }
@@ -350,7 +349,7 @@ class PlayerGrandExchange(private val player: Player) {
id = item.noteChange id = item.noteChange
} }
var itemDb = GrandExchangeDatabase.getDatabase()[id] var itemDb = GrandExchangeDatabase.getDatabase()[id]
if (itemDb == null) { if (itemDb == null || !item.definition.isTradeable) {
player.packetDispatch.sendMessage("This item can't be sold on the Grand Exchange.") player.packetDispatch.sendMessage("This item can't be sold on the Grand Exchange.")
return return
} }
@@ -358,7 +357,7 @@ class PlayerGrandExchange(private val player: Player) {
temporaryOffer!!.itemID = id temporaryOffer!!.itemID = id
temporaryOffer!!.sell = true temporaryOffer!!.sell = true
temporaryOffer!!.player = player temporaryOffer!!.player = player
temporaryOffer!!.offeredValue = itemDb.value temporaryOffer!!.offeredValue = OfferManager.getRecommendedPrice(id)
temporaryOffer!!.amount = item.amount temporaryOffer!!.amount = item.amount
temporaryOffer!!.index = openedIndex temporaryOffer!!.index = openedIndex
sendConfiguration(temporaryOffer, true) sendConfiguration(temporaryOffer, true)
@@ -425,9 +424,9 @@ class PlayerGrandExchange(private val player: Player) {
return return
} }
} }
if (dispatch(player, temporaryOffer!!)) { if (OfferManager.dispatch(player, temporaryOffer!!)) {
offers[openedIndex] = temporaryOffer offers[openedIndex] = temporaryOffer
updateOffer(temporaryOffer!!) OfferManager.updateOffer(temporaryOffer!!)
} }
} else { } else {
val total: Int = temporaryOffer!!.amount * temporaryOffer!!.offeredValue val total: Int = temporaryOffer!!.amount * temporaryOffer!!.offeredValue
@@ -436,9 +435,9 @@ class PlayerGrandExchange(private val player: Player) {
player.packetDispatch.sendMessage("You do not have enough coins to cover the offer.") player.packetDispatch.sendMessage("You do not have enough coins to cover the offer.")
return return
} }
if (dispatch(player, temporaryOffer!!) && player.inventory.remove(Item(995, total))) { if (OfferManager.dispatch(player, temporaryOffer!!) && player.inventory.remove(Item(995, total))) {
offers[openedIndex] = temporaryOffer offers[openedIndex] = temporaryOffer
updateOffer(temporaryOffer!!) OfferManager.updateOffer(temporaryOffer!!)
} }
} }
player.monitor.log( player.monitor.log(
@@ -546,7 +545,7 @@ class PlayerGrandExchange(private val player: Player) {
val botSales = OfferManager.amtBotsSelling(offer.itemID) val botSales = OfferManager.amtBotsSelling(offer.itemID)
if (botSales > 0) { if (botSales > 0) {
foundAmounts.add(botSales) foundAmounts.add(botSales)
foundOffers.add(BotPrices.getPrice(offer.itemID)) foundOffers.add(OfferManager.getRecommendedPrice(offer.itemID, true))
count++ count++
} }
if (foundOffers.isNotEmpty()) { if (foundOffers.isNotEmpty()) {
@@ -564,16 +563,17 @@ class PlayerGrandExchange(private val player: Player) {
player.packetDispatch.sendString(if (offer != null && !offer.sell) text.toString() else examine, 105, 142) player.packetDispatch.sendString(if (offer != null && !offer.sell) text.toString() else examine, 105, 142)
var lowPrice = 0 var lowPrice = 0
var highPrice = 0 var highPrice = 0
val recommendedPrice = OfferManager.getRecommendedPrice(entry?.itemId ?: 0)
if (entry != null) { if (entry != null) {
lowPrice = (entry.value * 0.95).toInt() lowPrice = (recommendedPrice * 0.95).toInt()
highPrice = (entry.value * 1.05).toInt() highPrice = (recommendedPrice * 1.05).toInt()
} }
player.varpManager.get(1109).setVarbit(0, offer?.itemID ?: -1).send(player) player.varpManager.get(1109).setVarbit(0, offer?.itemID ?: -1).send(player)
player.varpManager.get(1110).setVarbit(0, offer?.amount ?: 0).send(player) player.varpManager.get(1110).setVarbit(0, offer?.amount ?: 0).send(player)
player.varpManager.get(1111).setVarbit(0, offer?.offeredValue ?: 0).send(player) player.varpManager.get(1111).setVarbit(0, offer?.offeredValue ?: 0).send(player)
player.varpManager.get(1112).setVarbit(0, openedIndex).send(player) player.varpManager.get(1112).setVarbit(0, openedIndex).send(player)
player.varpManager.get(1113).setVarbit(0, if (sell) 1 else 0).send(player) player.varpManager.get(1113).setVarbit(0, if (sell) 1 else 0).send(player)
player.varpManager.get(1114).setVarbit(0, entry?.value ?: 0).send(player) player.varpManager.get(1114).setVarbit(0, recommendedPrice).send(player)
player.varpManager.get(1115).setVarbit(0, lowPrice).send(player) player.varpManager.get(1115).setVarbit(0, lowPrice).send(player)
player.varpManager.get(1116).setVarbit(0, highPrice).send(player) player.varpManager.get(1116).setVarbit(0, highPrice).send(player)
if (offer != null) { if (offer != null) {
@@ -0,0 +1,40 @@
package rs09.game.node.entity.npc.other
import api.ContentAPI
import core.game.node.entity.npc.AbstractNPC
import core.game.world.map.Location
import core.plugin.Initializable
import core.tools.RandomFunction
import org.rs09.consts.NPCs
@Initializable
class HonourGuardGFI : AbstractNPC {
//Constructor spaghetti because Arios I guess
constructor() : super(NPCs.HONOUR_GUARD_5514, null, true) {}
private constructor(id: Int, location: Location) : super(id, location) {}
override fun construct(id: Int, location: Location, vararg objects: Any?): AbstractNPC {
return HonourGuardGFI(id, location)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.HONOUR_GUARD_5514,NPCs.HONOUR_GUARD_5515,NPCs.HONOUR_GUARD_5516,NPCs.HONOUR_GUARD_5517)
}
override fun tick() {
if(isActive && !inCombat() && RandomFunction.roll(10)){
val localTrolls = ContentAPI.findLocalNPCs(this, intArrayOf(NPCs.ICE_TROLL_FEMALE_5523, NPCs.ICE_TROLL_MALE_5522, NPCs.ICE_TROLL_RUNT_5521, NPCs.ICE_TROLL_GRUNT_5524))
localTrolls.forEach{troll ->
if(troll.location.withinDistance(location,6)) {
attack(troll)
return super.tick()
}
}
}
if(!isActive){
properties.combatPulse.stop()
}
return super.tick()
}
}
@@ -69,6 +69,11 @@ object SystemLogger {
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[RAND] $message")}") if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[RAND] $message")}")
} }
@JvmStatic
fun logGE(message: String){
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[ GE] $message")}")
}
@JvmStatic @JvmStatic
fun logTrade(message: String){ fun logTrade(message: String){
if(message.isNotBlank()){ if(message.isNotBlank()){
@@ -1,6 +1,7 @@
package rs09.game.system.command.rottenpotato package rs09.game.system.command.rottenpotato
import api.ContentAPI import api.ContentAPI
import api.InputType
import core.game.content.dialogue.DialoguePlugin import core.game.content.dialogue.DialoguePlugin
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
@@ -38,7 +39,7 @@ class RottenPotatoExtraDialogue(player: Player? = null) : DialoguePlugin(player)
//Send Player Notification //Send Player Notification
1 -> { 1 -> {
end() end()
ContentAPI.sendInputDialogue(player, false, "Enter the notification message:"){value -> ContentAPI.sendInputDialogue(player, InputType.STRING_LONG, "Enter the notification message:"){ value ->
val message = value as String val message = value as String
for (p in Repository.players) { for (p in Repository.players) {
p ?: continue p ?: continue
@@ -61,7 +62,7 @@ class RottenPotatoExtraDialogue(player: Player? = null) : DialoguePlugin(player)
//Force Area NPC Chat //Force Area NPC Chat
4 -> { 4 -> {
end() end()
ContentAPI.sendInputDialogue(player, false,"Enter the chat message:"){value -> ContentAPI.sendInputDialogue(player, InputType.STRING_LONG,"Enter the chat message:"){ value ->
val msg = value as String val msg = value as String
RegionManager.getLocalNpcs(player).forEach { RegionManager.getLocalNpcs(player).forEach {
it.sendChat(msg) it.sendChat(msg)
@@ -81,7 +82,7 @@ class RottenPotatoExtraDialogue(player: Player? = null) : DialoguePlugin(player)
//AME Spawning //AME Spawning
100 -> { 100 -> {
end() end()
ContentAPI.sendInputDialogue(player, false, "Enter player name:"){value -> ContentAPI.sendInputDialogue(player, InputType.STRING_SHORT, "Enter player name:"){ value ->
val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ", "_")) val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ", "_"))
if (other == null) { if (other == null) {
player.sendMessage(colorize("%RInvalid player name.")) player.sendMessage(colorize("%RInvalid player name."))
@@ -1,6 +1,7 @@
package rs09.game.system.command.rottenpotato package rs09.game.system.command.rottenpotato
import api.ContentAPI import api.ContentAPI
import api.InputType
import core.game.content.dialogue.DialoguePlugin import core.game.content.dialogue.DialoguePlugin
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.info.login.PlayerParser import core.game.node.entity.player.info.login.PlayerParser
@@ -53,7 +54,7 @@ class RottenPotatoRSHDDialogue(player: Player? = null) : DialoguePlugin(player)
//View Bank //View Bank
4 -> { 4 -> {
end() end()
ContentAPI.sendInputDialogue(player, false, "Enter player name:"){value -> ContentAPI.sendInputDialogue(player, InputType.STRING_SHORT, "Enter player name:"){ value ->
val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ","_")) val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ","_"))
if(other == null){ if(other == null){
player.sendMessage(colorize("%RInvalid player name.")) player.sendMessage(colorize("%RInvalid player name."))
@@ -66,7 +67,7 @@ class RottenPotatoRSHDDialogue(player: Player? = null) : DialoguePlugin(player)
//View Inventory //View Inventory
5 -> { 5 -> {
end() end()
ContentAPI.sendInputDialogue(player, false, "Enter player name:"){value -> ContentAPI.sendInputDialogue(player, InputType.STRING_SHORT, "Enter player name:"){ value ->
val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ","_")) val other = Repository.getPlayerByName(value.toString().toLowerCase().replace(" ","_"))
if(other == null){ if(other == null){
player.sendMessage(colorize("%RInvalid player name.")) player.sendMessage(colorize("%RInvalid player name."))
@@ -156,9 +156,11 @@ class FunCommandSet : CommandSet(Command.Privilege.ADMIN) {
ContentAPI.addItemOrDrop(p, item.id, item.amount) ContentAPI.addItemOrDrop(p, item.id, item.amount)
ContentAPI.sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}") ContentAPI.sendMessage(p, "You dig and find ${if(item.amount > 1) "some" else "a"} ${item.name}")
} }
ContentAPI.sendNews("${player.username} has found the hidden treasure! Congratulations!!!")
SpadeDigListener.listeners.remove(loc) SpadeDigListener.listeners.remove(loc)
} }
player.inventory.clear() player.inventory.clear()
notify(player, "You have buried your loot at ${loc.toString()}") notify(player, "You have buried your loot at ${loc.toString()}")
} }
} }
@@ -9,6 +9,7 @@ import core.cache.def.impl.VarbitDefinition
import core.game.component.Component import core.game.component.Component
import core.game.ge.OfferState import core.game.ge.OfferState
import core.game.node.`object`.Scenery import core.game.node.`object`.Scenery
import core.game.node.entity.player.Player
import core.game.node.entity.player.info.Rights import core.game.node.entity.player.info.Rights
import core.game.node.entity.skill.Skills import core.game.node.entity.skill.Skills
import core.game.node.item.Item import core.game.node.item.Item
@@ -33,8 +34,10 @@ import rs09.game.world.repository.Repository
import rs09.tools.stringtools.colorize import rs09.tools.stringtools.colorize
import java.awt.Toolkit import java.awt.Toolkit
import java.awt.datatransfer.StringSelection import java.awt.datatransfer.StringSelection
import java.lang.Integer.max
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
@Initializable @Initializable
class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){ class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){
@@ -134,44 +137,20 @@ class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){
/** /**
* Shows the player a list of currently active GE sell offers * Shows the player a list of currently active GE sell offers
*/ */
define("ge", Command.Privilege.STANDARD) { player, _ -> define("ge", Command.Privilege.STANDARD) { player, args ->
val offers = HashMap<Int,Int>() if(args.size < 2){
for (offerIDs in OfferManager.OFFERS_BY_ITEMID) { reject(player, "Usage: ::ge mode", "Available modes: buying, selling, search")
var totalOffered = 0
for (offer in offerIDs.value) {
if (offer.offerState != OfferState.PENDING && offer.sell) {
totalOffered += offer.amountLeft
}
}
if (totalOffered != 0) {
offers[offerIDs.key] = totalOffered
}
} }
for (offerIDs in OfferManager.BOT_OFFERS) {
if (offerIDs.value > 0) {
if (offers[offerIDs.key] == null) {
offers[offerIDs.key] = offerIDs.value
} else {
offers[offerIDs.key] = offers[offerIDs.key]!! + offerIDs.value
}
}
}
for (i in 0..310) {
player!!.packetDispatch.sendString("", 275, i)
}
val offerList = offers.keys.map { "${ItemDefinition.forId(it).name} - ${offers[it]}" }.sorted()
var lineId = 11 val mode = args[1]
player!!.packetDispatch.sendString("Active Sell Offers", 275, 2) when(mode){
var counter = 0 "buying" -> showGeBuy(player)
for(i in 0..299) { "selling" -> showGeSell(player)
val offer = offerList.elementAtOrNull(i) "search" -> ContentAPI.sendInputDialogue(player, InputType.STRING_LONG, "Enter search term:"){value ->
if (offer != null) showOffers(player, value as String)
player.packetDispatch.sendString(offer, 275, lineId++) }
else else -> reject(player, "Invalid mode used. Available modes are: buying, selling, search")
player.packetDispatch.sendString("", 275, lineId++)
} }
player.interfaceManager.open(Component(Components.QUESTJOURNAL_SCROLL_275))
} }
/** /**
* ================================================================================== * ==================================================================================
@@ -480,4 +459,132 @@ class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){
} }
} }
} }
fun showGeSell(player: Player){
val offers = HashMap<Int,Int>()
for (offerIDs in OfferManager.OFFERS_BY_ITEMID) {
var totalOffered = 0
for (offer in offerIDs.value) {
if (offer.offerState != OfferState.PENDING && offer.sell) {
totalOffered += offer.amountLeft
}
}
if (totalOffered != 0) {
offers[offerIDs.key] = totalOffered
}
}
for (offerIDs in OfferManager.BOT_OFFERS) {
if (offerIDs.value > 0) {
if (offers[offerIDs.key] == null) {
offers[offerIDs.key] = offerIDs.value
} else {
offers[offerIDs.key] = offers[offerIDs.key]!! + offerIDs.value
}
}
}
val offerList = offers.keys.map { "${ItemDefinition.forId(it).name} - ${offers[it]}" }.sorted()
var lineId = 11
setScrollTitle(player, "Active Sell Offers")
for(i in 0..299) {
val offer = offerList.elementAtOrNull(i)
if (offer != null)
ContentAPI.setInterfaceText(player, offer, Components.QUESTJOURNAL_SCROLL_275, lineId++)
else
ContentAPI.setInterfaceText(player, "", Components.QUESTJOURNAL_SCROLL_275, lineId++)
}
ContentAPI.openInterface(player, Components.QUESTJOURNAL_SCROLL_275)
}
fun showGeBuy(player: Player){
val offers = HashMap<Int,Int>()
for (offerIDs in OfferManager.OFFERS_BY_ITEMID) {
var totalOffered = 0
for (offer in offerIDs.value) {
if (offer.offerState != OfferState.PENDING && !offer.sell) {
totalOffered += offer.amountLeft
}
}
if (totalOffered != 0) {
offers[offerIDs.key] = totalOffered
}
}
val offerList = offers.keys.map { "${ContentAPI.itemDefinition(it).name} - ${offers[it]}" }.sorted()
var lineId = 11
setScrollTitle(player, "Active Buy Offers")
for(i in 0..299) {
val offer = offerList.elementAtOrNull(i)
if (offer != null)
ContentAPI.setInterfaceText(player, offer, Components.QUESTJOURNAL_SCROLL_275, lineId++)
else
ContentAPI.setInterfaceText(player, "", Components.QUESTJOURNAL_SCROLL_275, lineId++)
}
ContentAPI.openInterface(player, Components.QUESTJOURNAL_SCROLL_275)
}
fun showOffers(player: Player, searchTerm: String){
val fakeOffers = ArrayList<FakeOffer>()
OfferManager.OFFERS_BY_ITEMID.forEach { (id, offers) ->
if(searchTerm.toLowerCase().contains(ContentAPI.itemDefinition(id).name.toLowerCase()) || ContentAPI.itemDefinition(id).name.toLowerCase().contains(searchTerm.toLowerCase())){
offers.forEach {
fakeOffers.add(FakeOffer(it.sell, ContentAPI.itemDefinition(id).name, it.amount))
}
}
}
OfferManager.BOT_OFFERS.forEach{ (id, amount) ->
val name = ContentAPI.getItemName(id)
if(searchTerm.toLowerCase().contains(name) || name.toLowerCase().contains(searchTerm.toLowerCase()))
fakeOffers.add(FakeOffer(true, ContentAPI.getItemName(id), amount))
}
val buyingList = fakeOffers.filter { !it.sell }
val sellingList = fakeOffers.filter { it.sell }
val buyingMap = HashMap<String, Int>()
val sellingMap = HashMap<String, Int>()
buyingList.forEach {
if(buyingMap[it.name] == null) buyingMap[it.name] = it.amount
else buyingMap[it.name] = buyingMap[it.name]?.plus(it.amount) ?: 0
}
sellingList.forEach {
if(sellingMap[it.name] == null) sellingMap[it.name] = it.amount
else sellingMap[it.name] = sellingMap[it.name]?.plus(it.amount) ?: 0
}
val buyList = buyingMap.map { (name,amount) -> "[Buying] $name - $amount" }.sortedBy { it.length }.toMutableList()
val sellList = sellingMap.map { (name, amount) -> "[Selling] $name - $amount" }.sortedBy { it.length }.toMutableList()
sellList.reverse()
sellList.add("<str> </str>")
sellList.reverse()
SystemLogger.logInfo("bl: ${buyList.size} sl: ${sellList.size}")
setScrollTitle(player, "Results for \"$searchTerm\"")
if(buyList.isEmpty()){
buyList.add("[Buying] Nothing!")
}
if(sellList.size == 1){
sellList.add("[Selling] Nothing!")
}
var lineId = 11
for(i in 0..299) {
val offer = if(i < buyList.size) buyList.getOrNull(i) else sellList.getOrNull(i - (buyList.size))
ContentAPI.setInterfaceText(player, offer ?: "", Components.QUESTJOURNAL_SCROLL_275, lineId++)
}
ContentAPI.openInterface(player, Components.QUESTJOURNAL_SCROLL_275)
}
fun setScrollTitle(player: Player, text: String){
ContentAPI.setInterfaceText(player, text, Components.QUESTJOURNAL_SCROLL_275, 2)
}
class FakeOffer(val sell: Boolean,val name: String,val amount: Int)
} }
@@ -3,6 +3,7 @@ package rs09.game.world.callback
import core.game.node.entity.skill.hunter.ImpetuousImpulses import core.game.node.entity.skill.hunter.ImpetuousImpulses
import core.game.world.callback.CallBack import core.game.world.callback.CallBack
import core.game.world.map.zone.ZoneBuilder import core.game.world.map.zone.ZoneBuilder
import rs09.game.ge.GrandExchange
import rs09.game.ge.OfferManager import rs09.game.ge.OfferManager
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import java.util.* import java.util.*
@@ -16,7 +17,7 @@ object CallbackHub {
fun call(): Boolean { fun call(): Boolean {
calls.add(ZoneBuilder()) calls.add(ZoneBuilder())
calls.add(OfferManager()) calls.add(GrandExchange)
calls.add(ImpetuousImpulses()) calls.add(ImpetuousImpulses())
for (call in calls) { for (call in calls) {
if (!call.call()) { if (!call.call()) {
@@ -72,12 +72,12 @@ object Repository {
* @param icon The icon. * @param icon The icon.
*/ */
@JvmStatic @JvmStatic
fun sendNews(string: String, icon: Int = 12, color: String = "<col=CC6600>") { fun sendNews(string: String, icon: Int = 12, color: String = "CC6600") {
val players: Array<Any> = playerNames.values.toTypedArray() val players: Array<Any> = playerNames.values.toTypedArray()
val size = players.size val size = players.size
for (i in 0 until size) { for (i in 0 until size) {
val player = players[i] as Player ?: continue val player = players[i] as Player ?: continue
player.sendMessage("<img=" + icon + ">" + color + "News: " + string) player.sendMessage("<img=$icon><col=$color>News: $string")
} }
} }
@@ -87,6 +87,7 @@ object Repository {
* I fucking hate java. * I fucking hate java.
*/ */
@JvmStatic @JvmStatic
@Deprecated("Old and bad",ReplaceWith("ContentAPI.sendNews()"),DeprecationLevel.WARNING)
fun sendNews(string: String){ fun sendNews(string: String){
sendNews(string,12) sendNews(string,12)
} }