From c9e20a21c89bc1389463871c312595dc2d08f13e Mon Sep 17 00:00:00 2001 From: Grant Horner Date: Sat, 3 Jan 2026 21:26:08 -0500 Subject: [PATCH] initial commit --- .gitignore | 2 + items.lisp | 54 ++++++++++++++++++++++ lispostory.asd | 12 +++++ main.lisp | 8 ++++ mobs.lisp | 51 +++++++++++++++++++++ ocicl.csv | 89 ++++++++++++++++++++++++++++++++++++ spawns.lisp | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ utils.lisp | 18 ++++++++ 8 files changed, 353 insertions(+) create mode 100644 .gitignore create mode 100644 items.lisp create mode 100644 lispostory.asd create mode 100644 main.lisp create mode 100644 mobs.lisp create mode 100644 ocicl.csv create mode 100644 spawns.lisp create mode 100644 utils.lisp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17c7801 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +ocicl +*.json \ No newline at end of file diff --git a/items.lisp b/items.lisp new file mode 100644 index 0000000..0381470 --- /dev/null +++ b/items.lisp @@ -0,0 +1,54 @@ +(in-package :lispostory) + +(defparameter *maplestory-items-url* "https://maplestory.io/api/gms/83/item") + +(defun get-maplestory-items () + (http-get-json *maplestory-items-url*)) + +(defparameter *chronostory-item-url-format* "https://chronostory.onrender.com/api/item-info?itemId=~a") + +(defparameter *chronostory-items* (make-array 0)) + +(defun chronostory-item-url (item-id) + (format nil *chronostory-item-url-format* item-id)) + +(defun reload-item-data () + (let ((item-data (shasht:read-json (uiop:read-file-string "items.json")))) + (setf *chronostory-items* item-data) + item-data)) + +(defun load-item-data () + (if (/= (length *chronostory-items*) 0) + *chronostory-items* + (reload-item-data))) + +(defun get-chrono-item (maple-item) + (if (gethash "isCash" maple-item) + nil + (let* ((item-id (gethash "id" maple-item)) + (url (chronostory-item-url item-id)) + (data (http-get-json url))) + (sleep 0.3) + (when data + (uiop:println (concatenate 'string "Retrieved id " (write-to-string item-id)))) + data))) + +(defun refresh-item-data () + (let* ((maple-items (get-maplestory-items)) + (_ (uiop:println "Retrieved maplestory items. Getting chronostory items...")) + (chrono-items + (loop for maple-item across maple-items + for chrono-item = (get-chrono-item maple-item) + when (and chrono-item + (stringp (gethash "item_name" chrono-item)) + (string-not-equal (gethash "item_name" chrono-item) "")) + collect chrono-item))) + (declare (ignore _)) + (uiop:println "Retrieved chronostory items. Writing out to json file...") + (setf *chronostory-items* chrono-items) + (alexandria-2:write-string-into-file + (shasht:write-json chrono-items nil) + "items.json" + :if-exists :overwrite + :if-does-not-exist :create) + (uiop:println "Done!"))) diff --git a/lispostory.asd b/lispostory.asd new file mode 100644 index 0000000..e71b859 --- /dev/null +++ b/lispostory.asd @@ -0,0 +1,12 @@ +(defsystem #:lispostory + :depends-on ("drakma" + "shasht" + "flexi-streams" + "alexandria" + "cl-csv" + "serapeum") + :components ((:file "utils") + (:file "main" :depends-on ("utils")) + (:file "mobs" :depends-on ("utils")) + (:file "items" :depends-on ("utils")) + (:file "spawns" :depends-on ("utils")))) diff --git a/main.lisp b/main.lisp new file mode 100644 index 0000000..5f014e5 --- /dev/null +++ b/main.lisp @@ -0,0 +1,8 @@ +(in-package :lispostory) + +(defparameter *chronostory-map-url-format* "https://chronostory.onrender.com/api/map-info?mapId=~a") +(defparameter *chronostory-gacha-search-format* "https://chronostory.onrender.com/api/gacha-search?itemId=~a") +(defparameter *chronostory-gacha-url-format "https://chronostory.onrender.com/api/gacha-items?gachaId=~a") +(defparameter *chronostory-drops-sheet-url* "https://docs.google.com/spreadsheets/d/e/2PACX-1vRpKuZGJQIFFxSi6kzYx4ALI0MQborpLEkh3J1qIGSd0Bw7U4NYg5CK-3ESzyK580z4D8NO59SUeC3k/pub?gid=1888753114&single=true&output=csv") + +; (sb-ext:save-lisp-and-die "my-prog" :toplevel #'show-mobs :executable t) diff --git a/mobs.lisp b/mobs.lisp new file mode 100644 index 0000000..c88e3fa --- /dev/null +++ b/mobs.lisp @@ -0,0 +1,51 @@ +(in-package :lispostory) + +(defparameter *maplestory-mobs-url* "https://maplestory.io/api/gms/83/mob") + +(defun get-maplestory-mobs () + (http-get-json *maplestory-mobs-url*)) + +(defparameter *chronostory-mob-url-format* "https://chronostory.onrender.com/api/mob-info?mobId=~a") +(defparameter *chronostory-mob-drop-url-format* "https://chronostory.onrender.com/api/mob-drops?mobId=~a") + +(defparameter *chronostory-mobs* (make-array 0)) + +(defun chronostory-mob-url (mob-id) + (format nil *chronostory-mob-url-format* mob-id)) + +(defun get-chrono-mob (maple-mob) + (let* ((mob-id (gethash "id" maple-mob)) + (url (chronostory-mob-url mob-id)) + (data (http-get-json url))) + (sleep 0.3) + (when data + (uiop:println (concatenate 'string "Retrieved id " (write-to-string mob-id)))) + data)) + +(defun refresh-mob-data () + (let* ((maple-mobs (get-maplestory-mobs)) + (_ (uiop:println "Retrieved maplestory mobs. Getting chronostory mobs...")) + (chrono-mobs + (loop for maple-mob across maple-mobs + for chrono-mob = (get-chrono-mob maple-mob) + when (let ((mob (and chrono-mob (gethash "mob" chrono-mob)))) + (and mob + (numberp (gethash "released" mob)) + (= (gethash "released" mob) 1))) + collect chrono-mob)) + (chrono-mobs-str (shasht:write-json chrono-mobs nil))) + (declare (ignore _)) + (uiop:println "Retrieved chronostory mobs. Writing out to json file...") + (setf *chronostory-mobs* chrono-mobs) + (alexandria-2:write-string-into-file chrono-mobs-str "mobs.json" :if-exists :overwrite :if-does-not-exist :create) + (uiop:println "Done!"))) + +(defun reload-mob-data () + (let ((mob-data (shasht:read-json (uiop:read-file-string "mobs.json")))) + (setf *chronostory-mobs* mob-data) + mob-data)) + +(defun load-mob-data () + (if (/= (length *chronostory-mobs*) 0) + *chronostory-mobs* + (reload-mob-data))) diff --git a/ocicl.csv b/ocicl.csv new file mode 100644 index 0000000..52b3d95 --- /dev/null +++ b/ocicl.csv @@ -0,0 +1,89 @@ +alexandria, ghcr.io/ocicl/alexandria@sha256:e433c2e076ed3bcf8641b97b00192680db2201d305efac9293539dee88c7fbf7, alexandria-20240503-8514d8e/alexandria.asd +autoload, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/autoload/autoload.asd +babel, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel.asd +babel-streams, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-streams.asd +babel-tests, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-tests.asd +bordeaux-threads, ghcr.io/ocicl/bordeaux-threads@sha256:bbb32afe3987e102149cc019f4f7366a05f7a37d1503f5f86a27745e671c320a, bordeaux-threads-0.9.4/bordeaux-threads.asd +cffi, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi.asd +cffi-examples, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-examples.asd +cffi-grovel, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-grovel.asd +cffi-libffi, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-libffi.asd +cffi-tests, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-tests.asd +cffi-toolchain, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-toolchain.asd +cffi-uffi-compat, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/cffi-uffi-compat.asd +chipz, ghcr.io/ocicl/chipz@sha256:fae0fae0c93199ba57c92d9102245a55c8a2c12af4442e0b141d5670bef4f2f0, chipz-20240503-6f80368/chipz.asd +chunga, ghcr.io/ocicl/chunga@sha256:a2558d54ac5d4ccdbf49d7b51fcb074762d77e263ec67245f6d2928477b6d19a, chunga-20250814-1310e96/chunga.asd +cl-base64, ghcr.io/ocicl/cl-base64@sha256:702412dbc1ed825e275fb23e22c29527eb786bf644e47c7621bf0dbb34e17c7e, cl-base64-20240503-80496b7/cl-base64.asd +cl-base64-tests, ghcr.io/ocicl/cl-base64@sha256:702412dbc1ed825e275fb23e22c29527eb786bf644e47c7621bf0dbb34e17c7e, cl-base64-20240503-80496b7/cl-base64-tests.asd +cl-csv, ghcr.io/ocicl/cl-csv@sha256:01600afb8570e45cfd2e1486138c844b13d940a1070140ff9341f6ec98b8e9c6, cl-csv-20240127-2d64d41/cl-csv.asd +cl-csv-clsql, ghcr.io/ocicl/cl-csv@sha256:01600afb8570e45cfd2e1486138c844b13d940a1070140ff9341f6ec98b8e9c6, cl-csv-20240127-2d64d41/cl-csv-clsql.asd +cl-csv-data-table, ghcr.io/ocicl/cl-csv@sha256:01600afb8570e45cfd2e1486138c844b13d940a1070140ff9341f6ec98b8e9c6, cl-csv-20240127-2d64d41/cl-csv-data-table.asd +cl-interpol, ghcr.io/ocicl/cl-interpol@sha256:bf02bce744361792150a04310b24a623596b99190a9f85a1c2ebf35f12b2288c, cl-interpol-2.0.7/cl-interpol.asd +cl-ppcre, ghcr.io/ocicl/cl-ppcre@sha256:bf073924cf4fd5957a4fd961a95d446ed0e53fa32a5002cbd2d52182874f45e5, cl-ppcre-20250606-a2ea581/cl-ppcre.asd +cl-ppcre-unicode, ghcr.io/ocicl/cl-ppcre@sha256:bf073924cf4fd5957a4fd961a95d446ed0e53fa32a5002cbd2d52182874f45e5, cl-ppcre-20250606-a2ea581/cl-ppcre-unicode.asd +cl-unicode, ghcr.io/ocicl/cl-unicode@sha256:d98f12c1271fb3c1812a27d64dfbe95b0bc5bcfd545b71b8101874e61270b120, cl-unicode-20240503-07e7ff5/cl-unicode.asd +cl_plus_ssl, ghcr.io/ocicl/cl_plus_ssl@sha256:d50fbbba38827e835eec2415744e0fb05a2a0bf4d44940cdc23922f15036efe5, cl-plus-ssl-20251220-499b2f5/cl+ssl.asd +cl_plus_ssl.test, ghcr.io/ocicl/cl_plus_ssl@sha256:d50fbbba38827e835eec2415744e0fb05a2a0bf4d44940cdc23922f15036efe5, cl-plus-ssl-20251220-499b2f5/cl+ssl.test.asd +closer-mop, ghcr.io/ocicl/closer-mop@sha256:0e7b398e671d48a0a1cfb5c1a017d0c2b009311c943ee3330d74fa0561c88fb2, closer-mop-20251228-4809f69/closer-mop.asd +drakma, ghcr.io/ocicl/drakma@sha256:09e748d5aba6ca99fef6a970ac4acbaead59596fdfd1080d7cda6b498b4a94dc, drakma-2.0.9/drakma.asd +drakma-test, ghcr.io/ocicl/drakma@sha256:09e748d5aba6ca99fef6a970ac4acbaead59596fdfd1080d7cda6b498b4a94dc, drakma-2.0.9/drakma-test.asd +dref, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/dref/dref.asd +dref-test, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/dref/dref-test.asd +dref-test-package-inferred, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/dref/test/data/dref-test-package-inferred.asd +flexi-streams, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams.asd +flexi-streams-test, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams-test.asd +global-vars, ghcr.io/ocicl/global-vars@sha256:d197e871c9c9abc4bf31b1186f5fd28f0ca848ebe2e9dddf2d82ecee01dbdc65, global-vars-20240503-c749f32/global-vars.asd +global-vars-test, ghcr.io/ocicl/global-vars@sha256:d197e871c9c9abc4bf31b1186f5fd28f0ca848ebe2e9dddf2d82ecee01dbdc65, global-vars-20240503-c749f32/global-vars-test.asd +idna, ghcr.io/ocicl/idna@sha256:b1737dbce42904f75c724350c3e057770c7777f1f5596c6358875dfb2e542eac, idna-20240503-bf789e6/idna.asd +introspect-environment, ghcr.io/ocicl/introspect-environment@sha256:4fa482690dee130996f1d0f89b470e0e84c92f22caea7649d3b83ce3e49c78ba, introspect-environment-20240503-69a50ac/introspect-environment.asd +introspect-environment-test, ghcr.io/ocicl/introspect-environment@sha256:4fa482690dee130996f1d0f89b470e0e84c92f22caea7649d3b83ce3e49c78ba, introspect-environment-20240503-69a50ac/introspect-environment-test.asd +iolib, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.asd +iolib.asdf, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.asdf.asd +iolib.base, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.base.asd +iolib.common-lisp, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.common-lisp.asd +iolib.conf, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.conf.asd +iolib.examples, ghcr.io/ocicl/iolib@sha256:953f1cb142e647da50562d51eca562afc2c5b941b89ae622332b53c7dbed7e1b, iolib-20240503-396cc43/iolib.examples.asd +iterate, ghcr.io/ocicl/iterate@sha256:6950c55e3782d58cabbbb5753111a70d8cafab8348b7fd6f2143d9abeaab46fb, iterate-20250703-d27d7ff/iterate.asd +lisp-namespace, ghcr.io/ocicl/lisp-namespace@sha256:ae08006e0b267958c50160658c729c799c6e1c18d94eef83f2ce5cf6ab8bbd20, lisp-namespace-20240503-699fccb/lisp-namespace.asd +lisp-namespace.test, ghcr.io/ocicl/lisp-namespace@sha256:ae08006e0b267958c50160658c729c799c6e1c18d94eef83f2ce5cf6ab8bbd20, lisp-namespace-20240503-699fccb/lisp-namespace.test.asd +mgl-pax, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/mgl-pax.asd +mgl-pax-bootstrap, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/mgl-pax-bootstrap.asd +mgl-pax-test, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/mgl-pax-test.asd +mgl-pax.asdf, ghcr.io/ocicl/mgl-pax-bootstrap@sha256:2adeaafc448ed8fd7fbe59459d57da7499625a00b8af92cacca5adfcb94509db, mgl-pax-20251221-c1c1edb/mgl-pax.asdf.asd +named-readtables, ghcr.io/ocicl/named-readtables@sha256:c3b4f9e8c99154d63c9adb94144af2c366f2560a7be3d12f7dfed728ff769c91, named-readtables-20251210-6eea566/named-readtables.asd +named-readtables-test, ghcr.io/ocicl/named-readtables@sha256:c3b4f9e8c99154d63c9adb94144af2c366f2560a7be3d12f7dfed728ff769c91, named-readtables-20251210-6eea566/named-readtables-test.asd +parse-declarations-1.0, ghcr.io/ocicl/parse-declarations-1.0@sha256:9305fa9624205b16fd1fc51cb1cc4282a18e50eee9ac75b66a14f6f2c5df9518, parse-declarations-20240503-549aebb/parse-declarations-1.0.asd +parse-number, ghcr.io/ocicl/parse-number@sha256:11f3f9f512871e1f96cea6b8260aa3610e34e8fd7272bbcdb210fd3c5dd8025c, parse-number-20240503-cb9e487/parse-number.asd +puri, ghcr.io/ocicl/puri@sha256:f6aa091a4d8eb5bdc91466daddc90dadd5b0fcf247370df237a223dc0588f29d, puri-4bbab9/puri.asd +serapeum, ghcr.io/ocicl/serapeum@sha256:c29107525dce97b63a2c8521ad00ef1581d484cd0729ea64433059b9f9fb38cc, serapeum-20251216-0f87830/serapeum.asd +shasht, ghcr.io/ocicl/shasht@sha256:ed683f73d865bb2d7231786797211774fce8f783890b295768f0794cd3de633b, shasht-20251015-40a4aee/shasht.asd +split-sequence, ghcr.io/ocicl/split-sequence@sha256:3a37662eedd99c42995587b9d443c4631f25c4c523091bcca31a27b880585b8e, split-sequence-2.0.1/split-sequence.asd +string-case, ghcr.io/ocicl/string-case@sha256:9db2d4160b76ce1ed9f754d12f679c665593a9a436177d36380a1a8a176ec16a, string-case-20240503-718c761/string-case.asd +swap-bytes, ghcr.io/ocicl/swap-bytes@sha256:06edc17deb0f27cdf6290689711ece670a8282dfd07b732a9adc541af1ce7ed6, swap-bytes-20240503-43ab141/swap-bytes.asd +trivia, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.asd +trivia.balland2006, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.balland2006.asd +trivia.benchmark, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.benchmark.asd +trivia.cffi, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.cffi.asd +trivia.fset, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.fset.asd +trivia.level0, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.level0.asd +trivia.level1, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.level1.asd +trivia.level2, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.level2.asd +trivia.ppcre, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.ppcre.asd +trivia.quasiquote, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.quasiquote.asd +trivia.test, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.test.asd +trivia.trivial, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.trivial.asd +trivial-cltl2, ghcr.io/ocicl/trivial-cltl2@sha256:69470b4f6469314799074b9d944050dc4bcb67d5cbb2ba32c7a8899bb492f04e, trivial-cltl2-20230809-2ada872/trivial-cltl2.asd +trivial-do, ghcr.io/ocicl/trivial-do@sha256:6d0c474b0a0ccac24298e8c90d12d7863b743256d17b2f37dd242399e7d8e68d, trivial-do-20240503-a19f932/trivial-do.asd +trivial-features, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features.asd +trivial-features-tests, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features-tests.asd +trivial-file-size, ghcr.io/ocicl/trivial-file-size@sha256:dfe138877e024d36e51fa14b1bcabf11e99e5745baa42ef4f627438485030f5c, trivial-file-size-20250427-60fd1bf/trivial-file-size.asd +trivial-garbage, ghcr.io/ocicl/trivial-garbage@sha256:a85dcf4110ad60ae9f6c70970acceb2bf12402ce5326891643d35506059afb1d, trivial-garbage-20240503-3474f64/trivial-garbage.asd +trivial-gray-streams, ghcr.io/ocicl/trivial-gray-streams@sha256:d0cc9fb73876100ee60647524f98b5b22566fa1c3a985d79548b0d2b228f8b51, trivial-gray-streams-20240503-a7ead68/trivial-gray-streams.asd +trivial-gray-streams-test, ghcr.io/ocicl/trivial-gray-streams@sha256:d0cc9fb73876100ee60647524f98b5b22566fa1c3a985d79548b0d2b228f8b51, trivial-gray-streams-20240503-a7ead68/trivial-gray-streams-test.asd +trivial-macroexpand-all, ghcr.io/ocicl/trivial-macroexpand-all@sha256:b23da4c2e508efe2396ec8f721cb22b8a4c076b2f0aea014a09f69dfd716d7f8, trivial-macroexpand-all-20250518-b6e4efa/trivial-macroexpand-all.asd +type-i, ghcr.io/ocicl/type-i@sha256:de5c3e7f7b72409c5ec49885eea8c6fe2e02def2846cf97f70c1c21f21a1567c, type-i-20240503-4407a68/type-i.asd +type-i.test, ghcr.io/ocicl/type-i@sha256:de5c3e7f7b72409c5ec49885eea8c6fe2e02def2846cf97f70c1c21f21a1567c, type-i-20240503-4407a68/type-i.test.asd +uffi, ghcr.io/ocicl/cffi-grovel@sha256:0854274d437e36f8bd30549103de36d23ac22f481f2746e61785e883f52b25fa, cffi-20250822-dad3520/uffi-compat/uffi.asd +usocket, ghcr.io/ocicl/usocket@sha256:282856b819b22a4319ba30a15605ee934aa23292a471fd29ea4d3f2074b3f16d, usocket-0.8.8/usocket.asd +usocket-server, ghcr.io/ocicl/usocket@sha256:282856b819b22a4319ba30a15605ee934aa23292a471fd29ea4d3f2074b3f16d, usocket-0.8.8/usocket-server.asd +usocket-test, ghcr.io/ocicl/usocket@sha256:282856b819b22a4319ba30a15605ee934aa23292a471fd29ea4d3f2074b3f16d, usocket-0.8.8/usocket-test.asd diff --git a/spawns.lisp b/spawns.lisp new file mode 100644 index 0000000..29b8061 --- /dev/null +++ b/spawns.lisp @@ -0,0 +1,119 @@ +(in-package :lispostory) + +(defparameter *chronostory-spawns-url-format* "https://docs.google.com/spreadsheets/d/e/2PACX-1vSIUj-72ADgwMqShxt4Dn7OP7dBN54l0wda1IPwlIVTZUN_ZtTlRx5DDidr43VXv2HYQ5RNqccLbbGS/pub?gid=~a&output=csv&single=true") + +(defparameter *chronostory-spawn-gids* + (alist + :maple-island 415330053 + :lith-harbor 486394009 + :kerning-city 0 + :henesys 898655980 + :perion 1754196543 + :ellinia 508846815 + :nautilus 714441637 + :sleepywood 615729202 + :orbis 350970245 + :el-nath 1897049096 + :ludibrium 1290087592)) + +(defvar *chronostory-spawns* nil) + +(defun chronostory-spawn-url (gid) + (format nil *chronostory-spawns-url-format* gid)) + +(defun find-first-empty-field (line) + "Upon receiving the csvs from google sheets, we need to find the first +'empty' header column. That column is the delimiter between two +separate csvs." + (loop for i from 0 below (- (length line) 1) + with comma-count = 0 + when (char= (char line i) #\,) + do (incf comma-count) + when (and (char= (char line i) #\,) + (char= (char line (+ i 1)) #\,)) + return comma-count)) + +(defun find-char-index-of-field (line field) + "Could be an off by one here?" + (loop for i from 0 below (length line) + with comma-count = 0 + when (char= (char line i) #\,) + do (incf comma-count) + when (= comma-count field) + return i)) + +(defun second-half (line field) + (let* ((index (find-char-index-of-field line field)) + (second-half (subseq line (+ 2 index)))) + second-half)) + + +(defun string-to-number-p (str) + (handler-case + (progn + (parse-integer str) + t) + (parse-error () nil))) + +(defun csv-to-hash-tables (csv) + (let* ((keys (mapcar (lambda (k) + (let ((k2 (string-upcase (serapeum:string-replace " " k "")))) + (intern k2 :keyword))) + (car csv))) + (result (make-array 0 :adjustable t :fill-pointer 0))) + (loop for row in csv + with mapname = "" + for hm = (serapeum:pairhash keys row (serapeum:dict)) + when (let ((name (gethash :monster hm))) + (and (string-not-equal "" name) + (string-not-equal "-" name) + (string-not-equal "Monster" name))) + do (progn + (if (and (string-not-equal mapname "") (string-equal (gethash :mapname hm) "")) + (setf (gethash :mapname hm) mapname) + (setf mapname (gethash :mapname hm))) + (vector-push-extend hm result))) + result)) + +(defun parse-sheet (sheet) + (let* ((lines (serapeum:lines sheet)) + (field (find-first-empty-field (car lines))) + (first-half (loop for line in lines + when (not (uiop:string-prefix-p ",,," line)) + collect (let ((index (find-char-index-of-field line field))) + (subseq line 0 index)))) + (second-half (loop for line in lines + for second-half = (second-half line field) + when (not (uiop:string-prefix-p ",,," second-half)) + collect second-half)) + (joined (serapeum:string-join (concatenate 'list first-half second-half) #\Newline))) + (csv-to-hash-tables (cl-csv:read-csv joined)))) + +(defun refresh-spawn-data () + (let ((spawn-data (serapeum:pairhash + (mapcar #'car *chronostory-spawn-gids*) + (mapcar (lambda (pair) + (let* ((gid (cdr pair)) + (data (drakma:http-request (chronostory-spawn-url gid)))) + (uiop:println (serapeum:concat "Requesting data for " (symbol-name (car pair)))) + (parse-sheet data))) + *chronostory-spawn-gids*)))) + (setf *chronostory-spawns* spawn-data) + (alexandria-2:write-string-into-file + (shasht:write-json spawn-data nil) + "spawns.json" + :if-exists :overwrite + :if-does-not-exist :create) + spawn-data)) + +(defun reload-spawn-data () + (let ((spawn-data (shasht:read-json (uiop:read-file-string "spawns.json" :if-does-not-exist nil)))) + (setf *chronostory-spawns* spawn-data) + spawn-data)) + +(defun load-spawn-data () + (serapeum:if-not *chronostory-spawns* + (reload-spawn-data) + *chronostory-spawns*)) + +(refresh-spawn-data) diff --git a/utils.lisp b/utils.lisp new file mode 100644 index 0000000..d883833 --- /dev/null +++ b/utils.lisp @@ -0,0 +1,18 @@ +(defpackage :lispostory + (:use cl)) + +(in-package :lispostory) + +(defun http-get-json (url) + (multiple-value-bind (body status) (drakma:http-request url) + (if (/= status 200) + nil + (let ((body-str (flexi-streams:octets-to-string body))) + (shasht:read-json body-str))))) + +(defun alist (&rest pairs) + (loop for (key value) on pairs by #'cddr + collect (cons key value))) + +(defun map-vector (func vec) + (map 'vector func vec))