WIP: update to include sectors!
authorxangelo <git@xangelo.ca>
Mon, 9 May 2022 15:29:05 +0000 (11:29 -0400)
committerxangelo <git@xangelo.ca>
Mon, 9 May 2022 17:24:50 +0000 (13:24 -0400)
14 files changed:
dump.sql
package.json
scripts/setup.ts [new file with mode: 0644]
src/api.ts
src/config.ts
src/lib/db.ts
src/lib/server.ts
src/render/fight.ts
src/render/kingdom-overview.ts
src/render/land-development.ts
src/render/unit-training.ts
src/repository/army.ts
src/repository/city.ts
src/tasks/fight.ts

index cee6242fbb728ba5a636b697b6cb83e6c557e752..9cd3202a88e9b7ecccf2a96cc7d89306d0cb917d 100644 (file)
--- a/dump.sql
+++ b/dump.sql
@@ -25,10 +25,14 @@ CREATE TABLE IF NOT EXISTS "cities" (
        "barracks"      int,
        "special_attacker_trainer"      int,
        "special_defender_trainer"      int,
-       "location_x"    int,
-       "location_y"    int,
        PRIMARY KEY("id")
 );
+CREATE TABLE IF NOT EXISTS "locations" (
+       "sector_id"             int,
+       "city_id"               text unique,
+       "location_x"    int,
+       "location_y"    int
+);
 CREATE TABLE IF NOT EXISTS "ticks" (
        "current_tick"  int,
        "last_tick_at"  int
@@ -105,111 +109,7 @@ CREATE TABLE IF NOT EXISTS "mail" (
        PRIMARY KEY("id")
 );
 INSERT INTO "accounts" VALUES ('-','Advisor','xos');
-INSERT INTO "accounts" VALUES ('54270f97-6c22-4398-a34e-0cd0ff3b8347','otaria','$2b$10$/N.WUQtnoGmPcwQuzZil/eKjh3tbs3ybU4CpUErfcZ01gaooS/YBm');
-INSERT INTO "cities" VALUES ('9a1350f6-2c5e-4676-ab68-f29d3a5dc617','934673de-27ad-452e-aba1-c7559f2b6c2c',100,24,2480498133976174,9770,8960,1782836,490,NULL,0,0,0,0,85,7,0,0,0,74,12);
-INSERT INTO "cities" VALUES ('4d3a80e6-ba68-42ef-ac94-f9e04b1d7f02','f439c929-bade-4bf9-9c03-f50005e878e6',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,97,92);
-INSERT INTO "cities" VALUES ('3bff09a5-2a83-4225-abb6-b9ed43058184','bcd32831-cb3b-4047-97dc-e87b9f8538c6',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,76,46);
-INSERT INTO "cities" VALUES ('f832ff46-08d0-4581-9460-7eae7048e4cf','45dd633a-ef2c-4491-9224-4b6784e73e29',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,3,10);
-INSERT INTO "cities" VALUES ('c1851f16-605a-4237-be11-6297ee46ff67','de51e72e-f51e-4f10-9a6e-9ecfc3c17126',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,13,61);
-INSERT INTO "cities" VALUES ('0edbe4a9-1f57-422a-8089-496cd6c7c7a3','8731686f-3caf-4030-8825-30f616a86dcd',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,23,0);
-INSERT INTO "cities" VALUES ('1c37d72d-0a73-422c-a93f-5eb5c0c97438','1e4646ee-2072-46a5-ab7b-4e0e05b1cf57',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,31,60);
-INSERT INTO "cities" VALUES ('3039c15a-36ae-4342-9b92-f7c8d431a0d6','17940bd5-2aa7-455f-95bf-9eca87cbdd0c',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,72,82);
-INSERT INTO "cities" VALUES ('1a6a926d-1223-4a06-95d7-5302bc370292','01fd5cdf-8fcb-4486-beac-805b7c6b222a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,46,90);
-INSERT INTO "cities" VALUES ('dea5617c-05bc-4551-95b6-40c2796007ee','be961d8f-e47a-426a-a262-9b3bf34da6f3',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,40,86);
-INSERT INTO "cities" VALUES ('7e5b4d82-178f-4238-b5ba-19d3b3ecf13c','049043b0-ba9f-4c06-afb0-762d660a56c0',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,34,48);
-INSERT INTO "cities" VALUES ('cbea0fc7-3422-4702-a433-39bc0633b1cd','a729651e-ac6a-4ce4-8008-e3e098f5f3e2',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,7,99);
-INSERT INTO "cities" VALUES ('356b0b56-64b2-4c0b-a6d6-748aa013edeb','9476f5cd-be44-424f-a525-882d9c240896',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,55,1);
-INSERT INTO "cities" VALUES ('41d90ecf-2961-413d-8f7e-b8ecc5af24f6','9b6aeb06-6a04-4413-a96f-2b33230eb426',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,7,32);
-INSERT INTO "cities" VALUES ('8fa82c61-d205-455f-9e88-d7176c9e8a36','888e29e4-06e6-4ab8-a60e-dc483102f467',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,40,58);
-INSERT INTO "cities" VALUES ('5d50dfbc-5cd7-4a94-8e52-7f12b7307e1d','1c648776-73a9-456a-8c9b-c0a23e9d19c0',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,58,5);
-INSERT INTO "cities" VALUES ('f566302d-735e-4258-9ba6-d96ba5f359c0','727051d7-5b0b-4a1e-a6a4-1325d4a7ebbc',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,67,45);
-INSERT INTO "cities" VALUES ('9aaff9eb-f047-43c9-a49d-122cb5defa5b','2d811a47-121d-4749-ae5b-bf6968c6de0e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,87,14);
-INSERT INTO "cities" VALUES ('b5592711-9411-4048-88b2-4de87dbc6c7b','fd3346c5-fdd6-4a8b-9aa1-aa8e2d8f7ce1',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,44,32);
-INSERT INTO "cities" VALUES ('14693011-5e6b-4d02-accd-d81676e43220','00604e16-ba10-4a1b-bd5d-bcc839630a82',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,61,61);
-INSERT INTO "cities" VALUES ('f0579927-6128-4cfc-a661-1d140c43adfc','b1c565eb-56e2-4c83-98cf-aa13317a6c2c',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,43,35);
-INSERT INTO "cities" VALUES ('b5940bf2-64e7-4aee-9176-7d93242eb22c','d59a0464-2ffe-4b79-868c-7b960d2915b7',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,1,5);
-INSERT INTO "cities" VALUES ('62f0555a-01bd-4cfc-8517-883100821d05','654856ed-0f83-4415-a9ca-31815b4bb28d',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,4,77);
-INSERT INTO "cities" VALUES ('1b9034de-7eeb-4a32-b91c-596307d59f3d','6738f9ff-0dc7-4c30-ac24-12bc49ae6c4f',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,41,41);
-INSERT INTO "cities" VALUES ('db3a2ae1-a773-4663-ab10-44edfb89d328','e1cc7c43-a70d-4e3b-bf52-b9eabee6bf41',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,96,6);
-INSERT INTO "cities" VALUES ('6b988dc7-1c98-463c-9910-f31b6828cd2c','1dd518e6-322e-4634-b76a-bb9e4c4d9c63',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,82,60);
-INSERT INTO "cities" VALUES ('e0bb4d85-7064-4a07-ab55-c33a0f66c86c','13ef9bd0-d7ae-403f-a497-3ea31e222a09',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,20,37);
-INSERT INTO "cities" VALUES ('f6ddfec3-a254-46b2-81b6-2a14b7ed00f6','83e2cc80-b777-47f9-99f7-350020e14da0',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,6,99);
-INSERT INTO "cities" VALUES ('4952f176-2597-4dd1-a9c8-b2bfa258f5b0','523ca052-4509-4266-9aa3-42c15e689982',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,38,28);
-INSERT INTO "cities" VALUES ('1526636e-4acc-4216-bd7a-389d3640d77a','50c7d344-344d-4160-a920-ea4b182e0ef0',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,71,90);
-INSERT INTO "cities" VALUES ('61305386-f8b8-496a-b073-76bae5af02d7','738b4d62-cc3b-41de-a852-1287b2acbd20',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,6,23);
-INSERT INTO "cities" VALUES ('3ca0d9b4-0b4e-4bc8-ba26-05f2b7c6331e','ece23dbc-3a91-4a7b-a51a-fb629cc5bd72',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,61,94);
-INSERT INTO "cities" VALUES ('202fb387-5414-4b05-91ea-a6a36d363013','dbafa7d8-4559-4f23-b105-46905e663ca1',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,56,96);
-INSERT INTO "cities" VALUES ('47ccb44c-e9b8-433b-890b-fb80578ebbfd','643555fe-18ea-4d35-b4e9-cf6dac5f9d1a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,40,91);
-INSERT INTO "cities" VALUES ('536a343f-20c2-4823-a0da-2ec456351f7f','981145d8-285e-4b88-b766-ce2139cd1a75',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,11,32);
-INSERT INTO "cities" VALUES ('6e096f8a-0c38-4951-88b5-19b1b8e8d721','e6321f65-3393-47b1-b77a-af7d7342c237',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,24,55);
-INSERT INTO "cities" VALUES ('f3a89abf-0b1e-4eb1-a5f4-a6ecb4ac1811','b1cd8806-3b80-4416-9415-0dd9a2237ae0',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,79,52);
-INSERT INTO "cities" VALUES ('123b12e6-0118-4d62-8225-2d8025030c4e','5852bbd0-51d6-4b61-afde-7f0f92162a1e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,47,1);
-INSERT INTO "cities" VALUES ('8475a1f1-ed7f-4205-aaa7-3cf6e4408253','1d852b2a-76b1-435d-8e19-dfac1729aa2e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,20,31);
-INSERT INTO "cities" VALUES ('ff0c82e8-afeb-4915-a2db-ec570a39e810','60c2de9c-7d70-44b8-8012-cef33c70097e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,26,27);
-INSERT INTO "cities" VALUES ('4acdd785-c606-432e-b83a-0cac33e5e45e','2727c469-9085-4350-9d66-44eca0c612ee',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,53,13);
-INSERT INTO "cities" VALUES ('fb674506-2529-4930-937a-35102e291199','ae7d20de-9115-4b59-ae96-553beff36477',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,10,13);
-INSERT INTO "cities" VALUES ('94cf3015-cd92-43ad-a10f-c0724f2680c9','43d54f20-2c91-4d46-b95e-f451105e0c97',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,11,4);
-INSERT INTO "cities" VALUES ('f8f273c1-3238-40fd-ad4d-d5018c263e47','2aaa212d-3fa2-4ccf-a021-797856363af6',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,6,19);
-INSERT INTO "cities" VALUES ('92e9722b-0379-4fea-a1d7-f70b8f4e2d7b','2cdf84d2-e0de-4daf-b0c5-b510464b82a5',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,68,34);
-INSERT INTO "cities" VALUES ('b09c2842-e95f-4c0e-8742-7a965c755ff9','d3cd6a4c-81d6-4897-971d-b25168342a75',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,47,24);
-INSERT INTO "cities" VALUES ('0546c5dd-8470-494b-93ea-5e24aedcb6b5','e345a220-4a8e-406d-9039-6798b4f81652',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,57,60);
-INSERT INTO "cities" VALUES ('482bb899-af7f-4545-a5dc-e0c810f5fc9b','d02997b0-0830-4269-9a13-c472222bf28b',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,58,35);
-INSERT INTO "cities" VALUES ('4b3ffe24-1645-4373-b69e-6a29f15d8215','53c20d14-9d3f-45fc-9736-e3e48bef2783',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,51,27);
-INSERT INTO "cities" VALUES ('005a85fc-cf2e-4bc9-a39b-9a3bad23469d','6001a973-465f-4ced-839b-eac5463859af',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,52,50);
-INSERT INTO "cities" VALUES ('cf862e8b-8465-4f23-a8d9-0e04a1603ea4','127b3a6e-1745-426a-8e28-d8ecbf4202be',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,13,9);
-INSERT INTO "cities" VALUES ('6547eb32-4094-421b-97f1-3dc3fea0d6dd','c1d9e4db-9a02-4aac-86c9-0e8040e57a88',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,48,71);
-INSERT INTO "cities" VALUES ('9083add2-37ad-40a2-a6ea-ee66c79c238a','accc82b9-189b-4b42-bc67-7c16abfa8c46',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,79,2);
-INSERT INTO "cities" VALUES ('dfade128-f6f2-4552-9ebc-4037d255d557','f27bbdb7-8002-45cd-8f95-a88cdfaf63ba',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,95,79);
-INSERT INTO "cities" VALUES ('bb016d2a-2d42-4ff5-abb1-7e996f20a748','a304e1bb-e420-4405-a76b-f5b5040568f2',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,97,0,0,0,0,84,61);
-INSERT INTO "cities" VALUES ('02ca1f1c-3b22-4f20-a584-cc013a31dc2d','698d43ea-3df1-4ae1-8f15-536ea3147c8d',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,38,36);
-INSERT INTO "cities" VALUES ('1ce47966-f1de-4db2-b2ac-babb63173309','9b91e1a8-0854-4e71-9c24-c5ff36fe008c',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,93,87);
-INSERT INTO "cities" VALUES ('10264b6e-0711-49c6-a873-d68049e6898c','5eb1a39c-c916-4b4e-8e14-839bba6e6c5e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,8,1);
-INSERT INTO "cities" VALUES ('acedda91-c45e-41f7-b60b-2c4d5def0813','8292435b-baca-4961-8a77-eb48410488bf',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,77,34);
-INSERT INTO "cities" VALUES ('4c0f3905-67cb-4cb2-bff5-be20708cf1a0','a58266cc-956d-45be-b3e3-5c00c9303e73',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,54,70);
-INSERT INTO "cities" VALUES ('30b41df8-ff05-49a9-acf4-c2164571e0e6','e1501e6d-2dcd-4ca6-bf2b-c265472cd406',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,97,50);
-INSERT INTO "cities" VALUES ('8ca8d68c-c381-4297-9337-39034f5782de','d2d2a7ac-754e-4a3d-880b-975d1be1676b',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,6,13);
-INSERT INTO "cities" VALUES ('03a937a3-dccd-4668-97e0-fbab36267e16','1e598ca7-26cf-4046-a18f-1f1e0db0be3a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,76,95);
-INSERT INTO "cities" VALUES ('115ce7f8-c079-4056-8153-67aa4eb3736b','0e60ae00-38b5-42c7-a0b1-06f95810d0e2',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,59,6);
-INSERT INTO "cities" VALUES ('4a1719ce-a802-4935-99a5-c0b52318c422','73997426-d16a-440d-b63a-679dda72b89c',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,92,12);
-INSERT INTO "cities" VALUES ('23eb1c0d-e735-4624-a0e3-a20a52612a7b','a243a916-8953-41a4-b86f-1130bcb4dd00',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,59,6);
-INSERT INTO "cities" VALUES ('4cf5ef70-d251-4b27-80aa-25dc03bbc2c7','babf461e-6239-4497-a504-5d24d9d689ca',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,16,90);
-INSERT INTO "cities" VALUES ('ef403e54-b214-4cb4-801a-b5d44064e366','34b5fc5c-81a7-41a3-b41e-68030a0d0639',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,85,17);
-INSERT INTO "cities" VALUES ('4ed70869-3ada-4787-a1ae-79e943d3c795','0055ef4e-84ab-417b-9873-b5b35f91b093',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,22,22);
-INSERT INTO "cities" VALUES ('a3f53533-bf75-4382-993e-28a9d3811641','97c61058-454d-4738-bc27-92d7088372f1',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,76,3);
-INSERT INTO "cities" VALUES ('00dc2a01-8703-474d-b9c3-d4db90b699bc','f5e33f96-cff4-4b04-a6d0-5732e9313de2',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,92,53);
-INSERT INTO "cities" VALUES ('9a29ffef-8bfb-4dc1-ba5b-b42fe76f5f68','3b433e27-b34f-4333-9196-f86897a4a9db',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,64,75);
-INSERT INTO "cities" VALUES ('a6a41994-561a-4b24-9c03-0ebcea4e9ca3','22a65552-9bac-4478-a925-2f517441ec98',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,91,18);
-INSERT INTO "cities" VALUES ('630a2eb3-4799-4e04-b6de-95052b95f932','42e63cf7-8909-4a0e-b7f8-164a609efe33',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,19,52);
-INSERT INTO "cities" VALUES ('f36bf98b-b54c-47f0-875a-0f753e38f49a','e7659374-ef74-44be-8deb-e355bda95c4f',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,94,97);
-INSERT INTO "cities" VALUES ('20f32716-f7db-4a9d-970a-5a491288d11e','64844d0d-9ccc-4023-b1d6-ba1a3fa1322e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,19,84);
-INSERT INTO "cities" VALUES ('4e9e6e64-619e-4c91-8c13-db940cbe9af1','2b97dff6-1e2e-448b-a51c-337ecfe836d6',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,4,83);
-INSERT INTO "cities" VALUES ('d8817d09-308d-46b2-a4ca-6bad80a2f83c','3483c0bc-6224-4b47-8b0d-4f4012693de1',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,10,66);
-INSERT INTO "cities" VALUES ('1fc525e5-3eef-4007-8f4f-92822fb2f98f','20d52370-a7a6-4e93-8c1f-40535c7b5fd9',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,65,11);
-INSERT INTO "cities" VALUES ('e2529402-9048-4dbc-bf5e-81ec115e4b85','7b271864-7671-49ee-8982-ab827d28ad45',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,11,60);
-INSERT INTO "cities" VALUES ('44a1f18e-6bc5-4f54-b8e3-4c876408844b','21de73af-8d84-483d-85fd-a2cb57662eaa',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,91,60);
-INSERT INTO "cities" VALUES ('b1cc4e47-eeb3-42f4-971a-998e1b663c53','988efec2-ed5a-4537-b50b-db0fa8f06445',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,58,93);
-INSERT INTO "cities" VALUES ('42a03e80-0b93-48ca-9e89-056b305b9f31','9b05b8ce-a3c5-4f4a-907b-747aa9b1cf68',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,38,83);
-INSERT INTO "cities" VALUES ('37b1a7df-890b-45d4-985d-831c3ef3fc74','8c9515fc-e18b-4132-a32b-ecbe7bbeb90f',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,90,80);
-INSERT INTO "cities" VALUES ('12eab809-6d06-4302-8d5c-f32e4715edfd','b95f1bef-239e-4a7b-b6ec-f064c3ef9c54',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,45,5);
-INSERT INTO "cities" VALUES ('9a5242b0-2737-4b90-9dbf-29812e399326','03c538b3-596b-4b89-b183-d18f5245c209',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,62,87);
-INSERT INTO "cities" VALUES ('b8d35860-2911-4570-b0b3-10848311d5fe','4b808479-d427-4288-9454-fd2e4060aaee',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,64,25);
-INSERT INTO "cities" VALUES ('b250ff81-7dc7-4e1b-a137-29c4ce4b9c5d','570d80f3-b158-42c6-9015-a98ffbdd7b5d',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,4,40);
-INSERT INTO "cities" VALUES ('56920e71-4b84-460b-bfa1-e3971f5876f6','e945ac13-3c9d-4cd1-a1a6-ce417a6ff19a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,92,30);
-INSERT INTO "cities" VALUES ('6f2ed644-cf12-4d25-a04a-6f854f27d284','21dc5c4d-95d3-45bb-a66a-720f7766a383',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,6,24);
-INSERT INTO "cities" VALUES ('979d63a6-7463-46b6-b401-d1fba912f6a5','a3b458af-d115-411d-ac9a-e8a3cac17920',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,60,58);
-INSERT INTO "cities" VALUES ('1b40da4e-1e10-44fd-bf05-979822d351a6','5f4b42a6-6e71-4bd9-8c86-e7e3b347bf74',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,33,25);
-INSERT INTO "cities" VALUES ('d51165ee-d0ff-4bb7-bf71-8107dc9c818d','7682b7c6-cdab-4c06-9ec0-5885f30ef608',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,88,92);
-INSERT INTO "cities" VALUES ('d96d5b18-f93f-4121-bcc2-b0ed3cb91482','009ec244-231a-40e7-8aa5-d3ef38958f86',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,28,86);
-INSERT INTO "cities" VALUES ('eb4596b2-87ad-47f2-8304-530f4533a4a6','0dc6ca85-7666-4ecd-b2f8-23c8dbcba13a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,65,17);
-INSERT INTO "cities" VALUES ('00ed9306-1fab-44c7-a42a-7890937c3815','aede9eb3-ac80-4d52-9654-4f3da412a335',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,3,84);
-INSERT INTO "cities" VALUES ('8b2882e1-6ce1-47ee-98bb-4809fef7bb2e','2a189dba-307d-4cb5-b615-bb987917495e',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,95,30);
-INSERT INTO "cities" VALUES ('211afe3c-beac-4034-8434-eb72048e63e6','666b614e-4584-41a6-9315-e42b0df7252a',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,76,60);
-INSERT INTO "cities" VALUES ('12625b90-4d7d-4280-9390-b541f46123db','73c6d662-f08c-4f36-8135-8a7e82e89e56',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,22,89);
-INSERT INTO "cities" VALUES ('6e6cb3c3-b3ba-40f7-8407-7f77553e1938','b7c8bafa-037f-44df-8c51-3aed4223dcec',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,56,36);
-INSERT INTO "cities" VALUES ('c5924972-a2fb-4dfa-b1b7-e6b2fb2c2c6b','fa131a4a-2c37-4656-9a75-5b5b082cca6d',100,0,14712000,10000,10000,0,1000,NULL,0,0,0,0,100,0,0,0,0,73,98);
-INSERT INTO "cities" VALUES ('3562c730-1d6a-47a1-89d1-dadb5e4bfa5d','83f82a2b-6b29-4cff-8937-baba748117d6',100,23,15094182,9900,8880,791122,1400,NULL,100,88,0,0,0,20,10,0,0,82,66);
-INSERT INTO "cities" VALUES ('dfe2f966-71b9-4af9-80a7-f79525efe3af','54270f97-6c22-4398-a34e-0cd0ff3b8347',100,0,10600,10000,10000,9000,500,NULL,0,0,0,0,0,0,0,0,0,29,28);
-INSERT INTO "ticks" VALUES (1,1651866761619);
+INSERT INTO "locations" VALUES (1, '-', -1, -1);
 INSERT INTO "buildings" VALUES ('farms','Farms',20,0,40,1,14);
 INSERT INTO "buildings" VALUES ('barracks','Barracks',40,10,60,1,16);
 INSERT INTO "buildings" VALUES ('special_attacker_trainer','Sp. Attacker Trainer',80,40,100,2,20);
@@ -218,5 +118,4 @@ INSERT INTO "units" VALUES ('soldiers','Soldiers',2,1,1,0,0,0,2,2.1,1);
 INSERT INTO "units" VALUES ('attackers','Attackers',5,2,0,1,0,0,3,4,1);
 INSERT INTO "units" VALUES ('defenders','Defenders',4,2,0,1,0,0,5,1,4);
 INSERT INTO "units" VALUES ('sp_attackers','Sp. Attacker',9,4,0,0,1,0,7,7,3);
-INSERT INTO "units" VALUES ('sp_defenders','Sp. Defender',11,5,0,0,0,1,10,2,9);
-COMMIT;
+INSERT INTO "units" VALUES ('sp_defenders','Sp. Defender',11,5,0,0,0,1,10,2,9);
\ No newline at end of file
index 10fef747c527732dc85d562a857ff2be7833ff4c..070db231eb8245973041daa5b108816590c80c6f 100644 (file)
@@ -1,7 +1,10 @@
 {
        "name": "tick-city",
        "scripts": {
-               "dev": "npx nodemon src/api.ts"
+               "dev": "npx nodemon src/api.ts",
+               "setup:rebels": "npx ts-node scripts/generate-cities.ts",
+               "setup:database": "npx ts-node scripts/setup.ts",
+               "setup": "npm run setup:database && npm run setup:rebels"
        },
        "dependencies": {
                "@bull-board/api": "^3.11.0",
@@ -30,5 +33,8 @@
                "ts-node": "^10.7.0",
                "tsconfig-paths": "^4.0.0",
                "typescript": "^4.6.4"
+       },
+       "volta": {
+               "node": "16.4.0"
        }
 }
diff --git a/scripts/setup.ts b/scripts/setup.ts
new file mode 100644 (file)
index 0000000..2485aae
--- /dev/null
@@ -0,0 +1,13 @@
+import { db } from '../src/lib/db';
+import fs from 'fs';
+import { join } from 'path';
+
+fs.readFile(join(__dirname, '..', 'dump.sql'), {encoding: 'utf-8'} ,async (err, data) => {
+    if(err)
+        throw err;
+
+    await db.raw(data);
+
+    console.log('Database configured');
+    process.exit(0);
+});
\ No newline at end of file
index e5e155758823d74a42fdd6275c768254ccaf6714..76873678c2d2741723ddcb932c702439760f9c08 100644 (file)
@@ -79,8 +79,8 @@ server.post<{body: {
 
 server.get<{params: { cityId: string }}, string>('/city/:cityId', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const yourCity = await cityRepo.FindOne({ owner: account.id });
-       const city = await cityRepo.FindOne({ id: req.params.cityId });
+       const yourCity = await cityRepo.getUsersCity(account.id);
+       const city = await cityRepo.findById(req.params.cityId);
        const acct = await accountRepo.FindOne({id: city.owner});
 
 
@@ -93,14 +93,14 @@ server.get<{params: { cityId: string }}, string>('/city/:cityId', async req => {
 
 server.get<{}, string>('/poll/overview', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const city = await cityRepo.FindOne({ owner: account.id });
+       const city = await cityRepo.getUsersCity(account.id);
 
        return renderKingomOverview(city, account);
 });
 
 server.get<{}, string>('/poll/construction', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const city = await cityRepo.FindOne({ owner: account.id });
+       const city = await cityRepo.getUsersCity(account.id);
        const buildings = await cityRepo.buildingRepository.list();
 
        const buildQueues = await cityRepo.getBuildQueues(account.id);
@@ -109,7 +109,7 @@ server.get<{}, string>('/poll/construction', async req => {
 
 server.get<{}, string>('/poll/unit-training', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const city = await cityRepo.FindOne({ owner: account.id });
+       const city = await cityRepo.getUsersCity(account.id);
 
        const unitTrainingQueues = await cityRepo.getUnitTrainingQueues(account.id);
        const units = await cityRepo.unitRepository.list();
@@ -119,9 +119,9 @@ server.get<{}, string>('/poll/unit-training', async req => {
 
 server.get<{}, string>('/poll/map', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const city = await cityRepo.FindOne({ owner: account.id });
+       const city = await cityRepo.getUsersCity(account.id);
 
-       return renderOverworldMap(await cityRepo.FindAll(), city);
+       return renderOverworldMap(await cityRepo.findAllInSector(city.sector_id), city);
 });
 
 server.get<{}, string>('/poll/mailroom', async req => {
@@ -234,7 +234,7 @@ server.post<{
        >('/attack', async req => {
                const acct = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
                const city = await cityRepo.getUsersCity(acct.id);
-               const attackedCity = await cityRepo.FindOne({id: req.body.city});
+               const attackedCity = await cityRepo.findById(req.body.city);
 
                const army = {
                        soldiers: parseInt(req.body.soldiers),
@@ -280,6 +280,4 @@ server.get<void, string>('/attacks/outgoing', async req => {
 });
 
 
-server.start();
-
-tick.trigger({lastTickAt: 0, lastTick: 0});
\ No newline at end of file
+server.start();
\ No newline at end of file
index 908d21e7ece01c80c61d0c03dc32ca9bc685ec81..ad7a3c5b976506898be2bf10b888898752b4295a 100644 (file)
@@ -3,4 +3,5 @@ import { config as dotenv } from 'dotenv';
 dotenv();
 
 export const TICK_LENGTH = process.env.TICK_LENGTH || 1000 * 60 * 5;
-export const API_PORT = process.env.API_PORT || '9090';
+export const API_PORT = process.env.API_PORT || 9090;
+export const AVAILABLE_SECTORS = 1
index 5964ca9e7ca774d5789c4a0bd057925ede292660..e17185937dd4d9123bbc4f0932b729061995ac2a 100644 (file)
@@ -3,7 +3,7 @@ import knex from 'knex';
 export const db = knex({
        client: 'better-sqlite3',
        connection: {
-               filename: './data.sql'
+               filename: './data.db'
        },
        debug: true
 });
index 249cc069fea921e24d0685dcbf7e1c798b974980..13545e41cee10fcab849fddde57a4909ba90f40a 100644 (file)
@@ -17,10 +17,10 @@ export type HttpHandler<I, O> = (params: I & AuthInfo, rawReq: Request, rawRes:
 
 export class HttpServer {
        server: express.Application;
-       port: number;
+       port: string | number;
        bullAdapter: ExpressAdapter;
-       constructor(port: string) {
-               this.port = parseInt(port, 10);
+       constructor(port: string | number) {
+               this.port = port;
                this.bullAdapter = new ExpressAdapter()
                this.server = express();
                this.configureMiddleWare();
index 833341e17db62654aa698fc68257c9fad1b1ca6e..a4864a2e240033a3dcb4456ec5b9de256182ee4f 100644 (file)
@@ -2,24 +2,24 @@ import _ from "lodash";
 import { DateTime } from "luxon";
 import { Account } from "../repository/accounts";
 import { ArmyQueueWithAttackedOwner } from "../repository/army";
-import { City, CityRepository } from "../repository/city";
+import { City, CityRepository, CityWithLocation } from "../repository/city";
 
 const cityRepo = new CityRepository();
 
-export function renderOverworldMap(cities: City[], yourCity: City): string {
-    let map: City[][] = new Array(100);
+export function renderOverworldMap(cities: CityWithLocation[], yourCity: CityWithLocation): string {
+    let map: CityWithLocation[][] = new Array(25);
     for(let i = 0; i < cities.length; ++i) {
         if(!map[cities[i].location_y]) {
-            map[cities[i].location_y] = new Array(100);
+            map[cities[i].location_y] = new Array(25);
         }
 
         map[cities[i].location_y][cities[i].location_x] = cities[i];
     }
 
     let rows: string[] = [];
-    for(let y = 0; y < 100; ++y) {
+    for(let y = 0; y < 25; ++y) {
         rows[y] = '<tr>';
-        for(let x = 0; x < 100; ++x) {
+        for(let x = 0; x < 25; ++x) {
             if(!map[y] || !map[y][x]) {
                 rows[y] += '<td><div class="empty"></div></td>' ;
             }
@@ -36,7 +36,7 @@ export function renderOverworldMap(cities: City[], yourCity: City): string {
         rows[y] += '</tr>';
     }
     let html = `
-    <h2>Map</h2>
+    <h2 data-augmented-ui="tl-clip bl-clip none">Map</h2>
     <div id="city-offence"></div>
     <div id="outgoing-attacks" hx-trigger="reload-outgoing-attacks, every 600s, load" hx-get="/attacks/outgoing"></div>
     <table id="overworld-map">
@@ -82,7 +82,7 @@ export function listOperations(outgoingOps: ArmyQueueWithAttackedOwner[]): strin
     return html;
 }
 
-export async function launchOffensive(city: City, owner: Account, yourCity: City, you: Account): Promise<string> {
+export async function launchOffensive(city: CityWithLocation, owner: Account, yourCity: CityWithLocation, you: Account): Promise<string> {
     const distance = cityRepo.distanceInHours(city, yourCity);
     const power = await cityRepo.power({
         soldiers: yourCity.soldiers,
@@ -92,7 +92,7 @@ export async function launchOffensive(city: City, owner: Account, yourCity: City
         sp_defenders: yourCity.sp_defenders
     })
     let html = `
-    <h3>Viewing (${city.location_x},${city.location_y}) owned by ${owner.username}</h3>
+    <h3 data-augmented-ui="tl-clip bl-clip none">Viewing (${city.location_x},${city.location_y}) owned by ${owner.username}</h3>
     <h4>Report</h4>
     <p>This city is ${distance} hours away.</p>
     <form hx-post="/attack">
index 802eb010f239a379a2991391db3be9d226038a9a..d82f6a411d80042c23423a5fd1155f0aaf351eb8 100644 (file)
@@ -1,8 +1,8 @@
 import { Account } from "../repository/accounts";
-import { City } from "../repository/city";
+import { CityWithLocation } from "../repository/city";
 import * as _ from 'lodash';
 
-export function renderKingomOverview(city: City, account: Account): string {
+export function renderKingomOverview(city: CityWithLocation, account: Account): string {
     return `
        <div hx-trigger="every 600s" hx-get="/poll/overview">
        <h2 data-augmented-ui="tl-clip bl-clip none">Kingdom Overview</h2>
index 0f584427112e1dcafdf6581546461e1a5590fa7c..935ff74dbdd74868b9dedda76480e209e9467f68 100644 (file)
@@ -1,5 +1,5 @@
 import { BuildQueue } from "../repository/build-queue";
-import { City } from "../repository/city";
+import { CityWithLocation } from "../repository/city";
 import { Building } from '../repository/buildings';
 import _ from "lodash";
 
@@ -13,7 +13,7 @@ function progressBar(current, max): string {
     `;
 }
 
-export function renderLandDevelopment(city: City, buildings: Building[], buildQueues: BuildQueue[]): string {
+export function renderLandDevelopment(city: CityWithLocation, buildings: Building[], buildQueues: BuildQueue[]): string {
     const freeSpace = city.totalSpace - city.usedSpace;
     let html = `
     <div hx-trigger="reload-construction-queue, every 600s" hx-get="/poll/construction">
index dfbbb1bc40fee300ca5c66558f9e9059c8e65db0..5b4ffcf026cd3d0613af6f76c5ac3da2f73c0c9d 100644 (file)
@@ -1,5 +1,5 @@
 import _ from "lodash";
-import { City } from "../repository/city";
+import { CityWithLocation } from "../repository/city";
 import { UnitTrainingQueue } from "../repository/training-queue";
 import { Unit } from "../repository/unit";
 
@@ -13,7 +13,7 @@ function progressBar(current, max): string {
     `;
 }
 
-export function renderUnitTraining(city: City, units: Unit[], trainingQueues: UnitTrainingQueue[]): string {
+export function renderUnitTraining(city: CityWithLocation, units: Unit[], trainingQueues: UnitTrainingQueue[]): string {
     const unit = _.keyBy(units, 'slug');
     let html = `
     <div hx-trigger="reload-unit-training, every 600s" hx-get="/poll/unit-training">
index d5e47e6014401f4f1623665abaa24ca830553ef0..46ddf570dbbaa49d28aa6d771cf015a12970b37d 100644 (file)
@@ -1,6 +1,6 @@
 import { Repository } from "./base";
 import { v4 as uuid } from 'uuid';
-import { City } from "./city";
+import { CityWithLocation } from "./city";
 
 export type Army = {
     soldiers: number;
@@ -30,7 +30,7 @@ export class ArmyRepository extends Repository<ArmyQueue> {
         super('army_queue');
     }
 
-    async create(owner: string, city: City, attacked_city: City, army: Army, distance: number): Promise<ArmyQueue> {
+    async create(owner: string, city: CityWithLocation, attacked_city: CityWithLocation, army: Army, distance: number): Promise<ArmyQueue> {
         // figure out the distance to the attacked city
 
         const info: ArmyQueue = {
@@ -50,9 +50,10 @@ export class ArmyRepository extends Repository<ArmyQueue> {
 
     async listOutgoing(city_id: string): Promise<ArmyQueueWithAttackedOwner[]> {
         return await (this.db.raw(`select 
-        aq.*, o.username as attacked_account, c.location_x, c.location_y
+        aq.*, o.username as attacked_account, l.location_x, l.location_y, l.sector_id 
         from army_queue aq
         join cities c on c.id = aq.attacked_city 
+        join locations l on l.city_id = aq.attacked_city 
         join accounts o on o.id = c.owner 
         order by due asc`)) as ArmyQueueWithAttackedOwner[];
     }
index 4aaa12778842291b4746efc9da8f156b588e75a1..df808786e71fbf7890b91b0ce35d573530d357b5 100644 (file)
@@ -1,13 +1,14 @@
 import { v4 as uuid } from 'uuid';
 import { ERROR_CODE, InsufficientResourceError, NotFoundError } from '../errors';
 import {Repository} from './base';
+import * as config from '../config';
 import { BuildQueue, BuildQueueRepository } from './build-queue';
 import { DateTime, Duration } from 'luxon';
 import { UnitTrainingQueue, UnitTrainingQueueRepository } from './training-queue';
 import { coalesce } from '../lib/util';
 import { Building, BuildingRepository } from './buildings';
 import { Unit, UnitRepository } from './unit';
-import _ from 'lodash';
+import _, { random } from 'lodash';
 import { Army, ArmyQueue, ArmyRepository } from './army';
 
 export type City = {
@@ -29,9 +30,13 @@ export type City = {
     barracks: number;
     special_attacker_trainer: number;
     special_defender_trainer: number;
+}
+
+export type CityWithLocation = {
+    sector_id: number;
     location_x: number;
     location_y: number;
-}
+} & City;
 
 export class CityRepository extends Repository<City> {
     buildQueue: BuildQueueRepository;
@@ -49,7 +54,7 @@ export class CityRepository extends Repository<City> {
         this.armyRepository = new ArmyRepository();
     }
 
-    async create(accountId: string): Promise<City> {
+    async create(accountId: string): Promise<CityWithLocation> {
         const info: City = {
             id: uuid(),
             owner: accountId,
@@ -69,32 +74,81 @@ export class CityRepository extends Repository<City> {
             barracks: 0,
             special_attacker_trainer: 0,
             special_defender_trainer: 0,
-            location_x: _.random(0, 100),
-            location_y: _.random(0, 100)
         };
 
+        await this.Insert(info);
+
         // placement can happen randomly
+        const availableSectors = config.AVAILABLE_SECTORS;
+        const sector = _.random(1, availableSectors);
 
-        await this.Insert(info);
+        const location = {
+            sector_id: await this.getAvailableSector(),
+            location_x: random(0, 25),
+            location_y: random(0, 25)
+        }
+
+        await this.db.raw('insert into locations (sector_id, city_id, location_x, location_y) values (?, ?, ?, ?)', [
+            location.sector_id,
+            info.id,
+            location.location_x,
+            location.location_y
+        ]);
+
+        return {
+            ...info,
+            sector_id: location.sector_id,
+            location_x: location.location_x,
+            location_y: location.location_y
+        };
+    }
+
+    async getAvailableSector(): Promise<number> {
+        // figure out which sectors have space (40% fill rate at 25x25);
+        const availableSectors = await this.db.raw<{count: Number, sector_id: number}[]>(`select count(sector_id) as count, sector_id from locations group by sector_id`);
+        const sample = _.sample(availableSectors.filter(sector => sector.count < 250)) as {count: number, sector_id: number};
 
-        return info;
+        if(!sample) {
+            return _.sortBy(availableSectors, 'sector_id').pop().sector_id+1;
+        }
+        
+        return sample.sector_id;
     }
 
-    async save(city: City) {
+    async save(city: Partial<City>) {
         await this.Save(city, {id: city.id});
         return city;
     }
 
-    async getUsersCity(owner: string): Promise<City> {
-        const city = await this.FindOne({
-            owner
-        });
+    async findById(cityId: string): Promise<CityWithLocation> {
+        const city = await this.db.raw<CityWithLocation[]>(`select c.*, l.sector_id, l.location_x, l.location_y from cities c
+        join locations l on c.id = l.city_id 
+        where id = ? limit 1`, [cityId]);
 
         if(!city) {
             throw new NotFoundError('User has no city', ERROR_CODE.NO_CITY);
         }
 
-        return city;
+        return city.pop();
+
+    }
+
+    async getUsersCity(owner: string): Promise<CityWithLocation> {
+        const city = await this.db.raw<CityWithLocation[]>(`select c.*, l.sector_id, l.location_x, l.location_y from cities c
+        join locations l on c.id = l.city_id 
+        where owner = ? limit 1`, [owner]);
+
+        if(!city) {
+            throw new NotFoundError('User has no city', ERROR_CODE.NO_CITY);
+        }
+
+        return city.pop();
+    }
+
+    findAllInSector(sector_id: number): Promise<CityWithLocation[]> {
+        return this.db.raw<CityWithLocation[]>(`select c.*, l.sector_id, l.location_x, l.location_y from cities c
+join locations l on c.id = l.city_id 
+where l.sector_id = ?`, [sector_id]);
     }
 
     async buildBuilding(building: Building, amount: number, city: City): Promise<BuildQueue> {
@@ -139,11 +193,11 @@ export class CityRepository extends Repository<City> {
      * @param city1 
      * @param city2 
      */
-    distanceInSeconds(city1: City, city2: City): number {
+    distanceInSeconds(city1: CityWithLocation, city2: CityWithLocation): number {
         return this.distanceInHours(city1, city2) * 60 * 60;
     }
 
-    distanceInHours(city1: City, city2: City): number {
+    distanceInHours(city1: CityWithLocation, city2: CityWithLocation): number {
         const dist = Math.sqrt(
             Math.pow((city2.location_x - city1.location_x), 2) 
             + 
@@ -219,7 +273,7 @@ export class CityRepository extends Repository<City> {
         return power
     }
 
-    async attack(attacker: City, attacked: City, army: Army): Promise<ArmyQueue> {
+    async attack(attacker: CityWithLocation, attacked: CityWithLocation, army: Army): Promise<ArmyQueue> {
         // validate the user has enough of a military! 
         if(attacker.soldiers < army.soldiers) {
             throw new InsufficientResourceError('soldiers', army.soldiers, attacker.soldiers);
index ceeb676f95e44276ff7d7cd533401191d6bf45ab..7be73a6031d50f9562f7230a363b2b542b3f5e8f 100644 (file)
@@ -1,6 +1,6 @@
 import { ArmyQueue } from "../repository/army"
 import { Task } from "./task";
-import { CityRepository, City } from "../repository/city";
+import { CityRepository, CityWithLocation } from "../repository/city";
 import { MailRepository } from "../repository/mail";
 
 const cityRepo = new CityRepository();
@@ -17,9 +17,9 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
     }
 
     // lets get the two cities!
-    const [attacker, attacked] = await Promise.all<City>([
-        cityRepo.FindOne({id: army.your_city}),
-        cityRepo.FindOne({id: army.attacked_city})
+    const [attacker, attacked] = await Promise.all<CityWithLocation>([
+        cityRepo.findById(army.your_city),
+        cityRepo.findById(army.attacked_city)
     ]);
 
     if(!attacker) {