commit c9e20a21c89bc1389463871c312595dc2d08f13e Author: Grant Horner Date: Sat Jan 3 21:26:08 2026 -0500 initial commit 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))