mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-23 02:55:40 +00:00
Merge branch 'main' of https://github.com/openfrontio/OpenFrontIO
This commit is contained in:
@@ -52,4 +52,4 @@
|
||||
"flag": "am"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+192
-192
@@ -1,193 +1,193 @@
|
||||
{
|
||||
"name": "Europe",
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"nations": [
|
||||
{
|
||||
"coordinates": [171, 171],
|
||||
"name": "Iceland",
|
||||
"strength": 1,
|
||||
"flag": "is"
|
||||
},
|
||||
{
|
||||
"coordinates": [477, 473],
|
||||
"name": "Ireland",
|
||||
"strength": 1,
|
||||
"flag": "ie"
|
||||
},
|
||||
{
|
||||
"coordinates": [650, 500],
|
||||
"name": "United Kingdom",
|
||||
"strength": 3,
|
||||
"flag": "gb"
|
||||
},
|
||||
{
|
||||
"coordinates": [560, 800],
|
||||
"name": "Spain",
|
||||
"strength": 2,
|
||||
"flag": "es"
|
||||
},
|
||||
{
|
||||
"coordinates": [726, 616],
|
||||
"name": "France",
|
||||
"strength": 2,
|
||||
"flag": "fr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1050, 745],
|
||||
"name": "Italy",
|
||||
"strength": 1,
|
||||
"flag": "it"
|
||||
},
|
||||
{
|
||||
"coordinates": [872, 634],
|
||||
"name": "Switzerland",
|
||||
"strength": 1,
|
||||
"flag": "ch"
|
||||
},
|
||||
{
|
||||
"coordinates": [960, 271],
|
||||
"name": "Norway",
|
||||
"strength": 1,
|
||||
"flag": "no"
|
||||
},
|
||||
{
|
||||
"coordinates": [1095, 336],
|
||||
"name": "Sweden",
|
||||
"strength": 1,
|
||||
"flag": "se"
|
||||
},
|
||||
{
|
||||
"coordinates": [1403, 235],
|
||||
"name": "Finland",
|
||||
"strength": 1,
|
||||
"flag": "fi"
|
||||
},
|
||||
{
|
||||
"coordinates": [775, 541],
|
||||
"name": "Belgium",
|
||||
"strength": 1,
|
||||
"flag": "be"
|
||||
},
|
||||
{
|
||||
"coordinates": [868, 487],
|
||||
"name": "Netherlands",
|
||||
"strength": 1,
|
||||
"flag": "nl"
|
||||
},
|
||||
{
|
||||
"coordinates": [1000, 480],
|
||||
"name": "Germany",
|
||||
"strength": 1,
|
||||
"flag": "de"
|
||||
},
|
||||
{
|
||||
"coordinates": [1017, 628],
|
||||
"name": "Austria",
|
||||
"strength": 1,
|
||||
"flag": "at"
|
||||
},
|
||||
{
|
||||
"coordinates": [1120, 477],
|
||||
"name": "Poland",
|
||||
"strength": 1,
|
||||
"flag": "pl"
|
||||
},
|
||||
{
|
||||
"coordinates": [1060, 530],
|
||||
"name": "Czech Republic",
|
||||
"strength": 1,
|
||||
"flag": "cz"
|
||||
},
|
||||
{
|
||||
"coordinates": [1540, 602],
|
||||
"name": "Ukraine",
|
||||
"strength": 1,
|
||||
"flag": "ua"
|
||||
},
|
||||
{
|
||||
"coordinates": [1500, 440],
|
||||
"name": "Belarus",
|
||||
"strength": 1,
|
||||
"flag": "by"
|
||||
},
|
||||
{
|
||||
"coordinates": [1400, 670],
|
||||
"name": "Romania",
|
||||
"strength": 1,
|
||||
"flag": "ro"
|
||||
},
|
||||
{
|
||||
"coordinates": [1580, 834],
|
||||
"name": "Turkey",
|
||||
"strength": 1,
|
||||
"flag": "tr"
|
||||
},
|
||||
{
|
||||
"coordinates": [525, 955],
|
||||
"name": "Morocco",
|
||||
"strength": 1,
|
||||
"flag": "ma"
|
||||
},
|
||||
{
|
||||
"coordinates": [1674, 449],
|
||||
"name": "Russian Federation",
|
||||
"strength": 3,
|
||||
"flag": "ru"
|
||||
},
|
||||
{
|
||||
"coordinates": [1750, 950],
|
||||
"name": "Syrian Arab Republic",
|
||||
"strength": 1,
|
||||
"flag": "sy"
|
||||
},
|
||||
{
|
||||
"coordinates": [1930, 950],
|
||||
"name": "Iraq",
|
||||
"strength": 1,
|
||||
"flag": "iq"
|
||||
},
|
||||
{
|
||||
"coordinates": [1900, 720],
|
||||
"name": "Georgia",
|
||||
"strength": 1,
|
||||
"flag": "ge"
|
||||
},
|
||||
{
|
||||
"coordinates": [950, 930],
|
||||
"name": "Tunisia",
|
||||
"strength": 1,
|
||||
"flag": "tn"
|
||||
},
|
||||
{
|
||||
"coordinates": [740, 940],
|
||||
"name": "Algeria",
|
||||
"strength": 1,
|
||||
"flag": "dz"
|
||||
},
|
||||
{
|
||||
"coordinates": [460, 830],
|
||||
"name": "Portugal",
|
||||
"strength": 1,
|
||||
"flag": "pt"
|
||||
},
|
||||
{
|
||||
"coordinates": [1300, 830],
|
||||
"name": "Greece",
|
||||
"strength": 1,
|
||||
"flag": "gr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1270, 700],
|
||||
"name": "Serbia",
|
||||
"strength": 1,
|
||||
"flag": "rs"
|
||||
},
|
||||
{
|
||||
"coordinates": [1200, 630],
|
||||
"name": "Hungary",
|
||||
"strength": 1,
|
||||
"flag": "hu"
|
||||
}
|
||||
]
|
||||
}
|
||||
"name": "Europe",
|
||||
"width": 2000,
|
||||
"height": 1000,
|
||||
"nations": [
|
||||
{
|
||||
"coordinates": [171, 171],
|
||||
"name": "Iceland",
|
||||
"strength": 1,
|
||||
"flag": "is"
|
||||
},
|
||||
{
|
||||
"coordinates": [477, 473],
|
||||
"name": "Ireland",
|
||||
"strength": 1,
|
||||
"flag": "ie"
|
||||
},
|
||||
{
|
||||
"coordinates": [650, 500],
|
||||
"name": "United Kingdom",
|
||||
"strength": 3,
|
||||
"flag": "gb"
|
||||
},
|
||||
{
|
||||
"coordinates": [560, 800],
|
||||
"name": "Spain",
|
||||
"strength": 2,
|
||||
"flag": "es"
|
||||
},
|
||||
{
|
||||
"coordinates": [726, 616],
|
||||
"name": "France",
|
||||
"strength": 2,
|
||||
"flag": "fr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1050, 745],
|
||||
"name": "Italy",
|
||||
"strength": 1,
|
||||
"flag": "it"
|
||||
},
|
||||
{
|
||||
"coordinates": [872, 634],
|
||||
"name": "Switzerland",
|
||||
"strength": 1,
|
||||
"flag": "ch"
|
||||
},
|
||||
{
|
||||
"coordinates": [960, 271],
|
||||
"name": "Norway",
|
||||
"strength": 1,
|
||||
"flag": "no"
|
||||
},
|
||||
{
|
||||
"coordinates": [1095, 336],
|
||||
"name": "Sweden",
|
||||
"strength": 1,
|
||||
"flag": "se"
|
||||
},
|
||||
{
|
||||
"coordinates": [1403, 235],
|
||||
"name": "Finland",
|
||||
"strength": 1,
|
||||
"flag": "fi"
|
||||
},
|
||||
{
|
||||
"coordinates": [775, 541],
|
||||
"name": "Belgium",
|
||||
"strength": 1,
|
||||
"flag": "be"
|
||||
},
|
||||
{
|
||||
"coordinates": [868, 487],
|
||||
"name": "Netherlands",
|
||||
"strength": 1,
|
||||
"flag": "nl"
|
||||
},
|
||||
{
|
||||
"coordinates": [1000, 480],
|
||||
"name": "Germany",
|
||||
"strength": 1,
|
||||
"flag": "de"
|
||||
},
|
||||
{
|
||||
"coordinates": [1017, 628],
|
||||
"name": "Austria",
|
||||
"strength": 1,
|
||||
"flag": "at"
|
||||
},
|
||||
{
|
||||
"coordinates": [1120, 477],
|
||||
"name": "Poland",
|
||||
"strength": 1,
|
||||
"flag": "pl"
|
||||
},
|
||||
{
|
||||
"coordinates": [1060, 530],
|
||||
"name": "Czech Republic",
|
||||
"strength": 1,
|
||||
"flag": "cz"
|
||||
},
|
||||
{
|
||||
"coordinates": [1540, 602],
|
||||
"name": "Ukraine",
|
||||
"strength": 1,
|
||||
"flag": "ua"
|
||||
},
|
||||
{
|
||||
"coordinates": [1500, 440],
|
||||
"name": "Belarus",
|
||||
"strength": 1,
|
||||
"flag": "by"
|
||||
},
|
||||
{
|
||||
"coordinates": [1400, 670],
|
||||
"name": "Romania",
|
||||
"strength": 1,
|
||||
"flag": "ro"
|
||||
},
|
||||
{
|
||||
"coordinates": [1580, 834],
|
||||
"name": "Turkey",
|
||||
"strength": 1,
|
||||
"flag": "tr"
|
||||
},
|
||||
{
|
||||
"coordinates": [525, 955],
|
||||
"name": "Morocco",
|
||||
"strength": 1,
|
||||
"flag": "ma"
|
||||
},
|
||||
{
|
||||
"coordinates": [1674, 449],
|
||||
"name": "Russian Federation",
|
||||
"strength": 3,
|
||||
"flag": "ru"
|
||||
},
|
||||
{
|
||||
"coordinates": [1750, 950],
|
||||
"name": "Syrian Arab Republic",
|
||||
"strength": 1,
|
||||
"flag": "sy"
|
||||
},
|
||||
{
|
||||
"coordinates": [1930, 950],
|
||||
"name": "Iraq",
|
||||
"strength": 1,
|
||||
"flag": "iq"
|
||||
},
|
||||
{
|
||||
"coordinates": [1900, 720],
|
||||
"name": "Georgia",
|
||||
"strength": 1,
|
||||
"flag": "ge"
|
||||
},
|
||||
{
|
||||
"coordinates": [950, 930],
|
||||
"name": "Tunisia",
|
||||
"strength": 1,
|
||||
"flag": "tn"
|
||||
},
|
||||
{
|
||||
"coordinates": [740, 940],
|
||||
"name": "Algeria",
|
||||
"strength": 1,
|
||||
"flag": "dz"
|
||||
},
|
||||
{
|
||||
"coordinates": [460, 830],
|
||||
"name": "Portugal",
|
||||
"strength": 1,
|
||||
"flag": "pt"
|
||||
},
|
||||
{
|
||||
"coordinates": [1300, 830],
|
||||
"name": "Greece",
|
||||
"strength": 1,
|
||||
"flag": "gr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1270, 700],
|
||||
"name": "Serbia",
|
||||
"strength": 1,
|
||||
"flag": "rs"
|
||||
},
|
||||
{
|
||||
"coordinates": [1200, 630],
|
||||
"name": "Hungary",
|
||||
"strength": 1,
|
||||
"flag": "hu"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+35
-35
@@ -7,211 +7,211 @@
|
||||
"coordinates": [200, 100],
|
||||
"name": "Spain",
|
||||
"strength": 1,
|
||||
"flag": "ES"
|
||||
"flag": "es"
|
||||
},
|
||||
{
|
||||
"coordinates": [50, 135],
|
||||
"name": "Portugal",
|
||||
"strength": 1,
|
||||
"flag": "PT"
|
||||
"flag": "pt"
|
||||
},
|
||||
{
|
||||
"coordinates": [125, 375],
|
||||
"name": "Morocco",
|
||||
"strength": 1,
|
||||
"flag": "MA"
|
||||
"flag": "ma"
|
||||
},
|
||||
{
|
||||
"coordinates": [425, 300],
|
||||
"name": "Algeria",
|
||||
"strength": 1,
|
||||
"flag": "DZ"
|
||||
"flag": "dz"
|
||||
},
|
||||
{
|
||||
"coordinates": [600, 275],
|
||||
"name": "Tunisia",
|
||||
"strength": 1,
|
||||
"flag": "TN"
|
||||
"flag": "tn"
|
||||
},
|
||||
{
|
||||
"coordinates": [750, 450],
|
||||
"name": "Libyan Arab Jamahiriya",
|
||||
"strength": 1,
|
||||
"flag": "LY"
|
||||
"flag": "ly"
|
||||
},
|
||||
{
|
||||
"coordinates": [1100, 450],
|
||||
"name": "Egypt",
|
||||
"strength": 1,
|
||||
"flag": "EG"
|
||||
"flag": "eg"
|
||||
},
|
||||
{
|
||||
"coordinates": [1333, 333],
|
||||
"name": "Israel",
|
||||
"strength": 1,
|
||||
"flag": "IL"
|
||||
"flag": "il"
|
||||
},
|
||||
{
|
||||
"coordinates": [1338, 388],
|
||||
"name": "Palestinian Territory, Occupied",
|
||||
"strength": 1,
|
||||
"flag": "PS"
|
||||
"flag": "ps"
|
||||
},
|
||||
{
|
||||
"coordinates": [1370, 325],
|
||||
"name": "Lebanon",
|
||||
"strength": 1,
|
||||
"flag": "LB"
|
||||
"flag": "lb"
|
||||
},
|
||||
{
|
||||
"coordinates": [1228, 728],
|
||||
"name": "Sudan",
|
||||
"strength": 1,
|
||||
"flag": "SD"
|
||||
"flag": "sd"
|
||||
},
|
||||
{
|
||||
"coordinates": [1450, 275],
|
||||
"name": "Syrian Arab Republic",
|
||||
"strength": 1,
|
||||
"flag": "SY"
|
||||
"flag": "sy"
|
||||
},
|
||||
{
|
||||
"coordinates": [1600, 300],
|
||||
"name": "Iraq",
|
||||
"strength": 1,
|
||||
"flag": "IQ"
|
||||
"flag": "iq"
|
||||
},
|
||||
{
|
||||
"coordinates": [1550, 600],
|
||||
"name": "Saudi Arabia",
|
||||
"strength": 1,
|
||||
"flag": "SA"
|
||||
"flag": "sa"
|
||||
},
|
||||
{
|
||||
"coordinates": [1700, 850],
|
||||
"name": "Yemen",
|
||||
"strength": 1,
|
||||
"flag": "YE"
|
||||
"flag": "ye"
|
||||
},
|
||||
{
|
||||
"coordinates": [1950, 725],
|
||||
"name": "Oman",
|
||||
"strength": 1,
|
||||
"flag": "OM"
|
||||
"flag": "om"
|
||||
},
|
||||
{
|
||||
"coordinates": [1860, 620],
|
||||
"name": "United Arab Emirates",
|
||||
"strength": 1,
|
||||
"flag": "AE"
|
||||
"flag": "ae"
|
||||
},
|
||||
{
|
||||
"coordinates": [1730, 580],
|
||||
"name": "Qatar",
|
||||
"strength": 1,
|
||||
"flag": "QA"
|
||||
"flag": "qa"
|
||||
},
|
||||
{
|
||||
"coordinates": [1900, 350],
|
||||
"name": "Iran, Islamic Republic Of",
|
||||
"strength": 1,
|
||||
"flag": "IR"
|
||||
"flag": "ir"
|
||||
},
|
||||
{
|
||||
"coordinates": [1300, 150],
|
||||
"name": "Turkey",
|
||||
"strength": 1,
|
||||
"flag": "TR"
|
||||
"flag": "tr"
|
||||
},
|
||||
{
|
||||
"coordinates": [675, 50],
|
||||
"name": "Italy",
|
||||
"strength": 1,
|
||||
"flag": "IT"
|
||||
"flag": "it"
|
||||
},
|
||||
{
|
||||
"coordinates": [950, 125],
|
||||
"name": "Greece",
|
||||
"strength": 1,
|
||||
"flag": "GR"
|
||||
"flag": "gr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1000, 25],
|
||||
"name": "Bulgaria",
|
||||
"strength": 1,
|
||||
"flag": "BG"
|
||||
"flag": "bg"
|
||||
},
|
||||
{
|
||||
"coordinates": [1980, 45],
|
||||
"name": "Uzbekistan",
|
||||
"strength": 1,
|
||||
"flag": "UZ"
|
||||
"flag": "uz"
|
||||
},
|
||||
{
|
||||
"coordinates": [1400, 400],
|
||||
"name": "Jordan",
|
||||
"strength": 1,
|
||||
"flag": "JO"
|
||||
"flag": "jo"
|
||||
},
|
||||
{
|
||||
"coordinates": [750, 930],
|
||||
"name": "Chad",
|
||||
"strength": 1,
|
||||
"flag": "TD"
|
||||
"flag": "td"
|
||||
},
|
||||
{
|
||||
"coordinates": [500, 900],
|
||||
"name": "Niger",
|
||||
"strength": 1,
|
||||
"flag": "NE"
|
||||
"flag": "ne"
|
||||
},
|
||||
{
|
||||
"coordinates": [230, 940],
|
||||
"name": "Mali",
|
||||
"strength": 1,
|
||||
"flag": "ML"
|
||||
"flag": "ml"
|
||||
},
|
||||
{
|
||||
"coordinates": [40, 830],
|
||||
"name": "Mauritania",
|
||||
"strength": 1,
|
||||
"flag": "MR"
|
||||
"flag": "mr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1490, 980],
|
||||
"name": "Eritrea",
|
||||
"strength": 1,
|
||||
"flag": "ER"
|
||||
"flag": "er"
|
||||
},
|
||||
{
|
||||
"coordinates": [1630, 460],
|
||||
"name": "Kuwait",
|
||||
"strength": 1,
|
||||
"flag": "KW"
|
||||
"flag": "kw"
|
||||
},
|
||||
{
|
||||
"coordinates": [1550, 25],
|
||||
"name": "Georgia",
|
||||
"strength": 1,
|
||||
"flag": "GE"
|
||||
"flag": "ge"
|
||||
},
|
||||
{
|
||||
"coordinates": [1640, 100],
|
||||
"name": "Azerbaijan",
|
||||
"strength": 1,
|
||||
"flag": "AZ"
|
||||
"flag": "az"
|
||||
},
|
||||
{
|
||||
"coordinates": [1226, 280],
|
||||
"name": "Cyprus",
|
||||
"strength": 1,
|
||||
"flag": "CY"
|
||||
"flag": "cy"
|
||||
},
|
||||
{
|
||||
"coordinates": [1800, 40],
|
||||
"name": "Kazakhstan",
|
||||
"strength": 1,
|
||||
"flag": "KZ"
|
||||
"flag": "kz"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,97 +7,97 @@
|
||||
"coordinates": [1280, 582],
|
||||
"name": "United States",
|
||||
"strength": 3,
|
||||
"flag": "US"
|
||||
"flag": "us"
|
||||
},
|
||||
{
|
||||
"coordinates": [1235, 509],
|
||||
"name": "Canada",
|
||||
"strength": 2,
|
||||
"flag": "CA"
|
||||
"flag": "ca"
|
||||
},
|
||||
{
|
||||
"coordinates": [983, 832],
|
||||
"name": "Mexico",
|
||||
"strength": 2,
|
||||
"flag": "MX"
|
||||
"flag": "mx"
|
||||
},
|
||||
{
|
||||
"coordinates": [1126, 871],
|
||||
"name": "Belize",
|
||||
"strength": 1,
|
||||
"flag": "BZ"
|
||||
"flag": "bz"
|
||||
},
|
||||
{
|
||||
"coordinates": [1096, 893],
|
||||
"name": "Guatemala",
|
||||
"strength": 1,
|
||||
"flag": "GT"
|
||||
"flag": "gt"
|
||||
},
|
||||
{
|
||||
"coordinates": [1124, 916],
|
||||
"name": "El Salvador",
|
||||
"strength": 1,
|
||||
"flag": "SV"
|
||||
"flag": "sv"
|
||||
},
|
||||
{
|
||||
"coordinates": [1143, 906],
|
||||
"name": "Honduras",
|
||||
"strength": 1,
|
||||
"flag": "HN"
|
||||
"flag": "hn"
|
||||
},
|
||||
{
|
||||
"coordinates": [1157, 937],
|
||||
"name": "Nicaragua",
|
||||
"strength": 1,
|
||||
"flag": "NI"
|
||||
"flag": "ni"
|
||||
},
|
||||
{
|
||||
"coordinates": [1184, 963],
|
||||
"name": "Costa Rica",
|
||||
"strength": 1,
|
||||
"flag": "CR"
|
||||
"flag": "cr"
|
||||
},
|
||||
{
|
||||
"coordinates": [1235, 974],
|
||||
"name": "Panama",
|
||||
"strength": 1,
|
||||
"flag": "PA"
|
||||
"flag": "pa"
|
||||
},
|
||||
{
|
||||
"coordinates": [1304, 997],
|
||||
"name": "Colombia",
|
||||
"strength": 1,
|
||||
"flag": "CO"
|
||||
"flag": "co"
|
||||
},
|
||||
{
|
||||
"coordinates": [1392, 955],
|
||||
"name": "Venezuela",
|
||||
"strength": 1,
|
||||
"flag": "VE"
|
||||
"flag": "ve"
|
||||
},
|
||||
{
|
||||
"coordinates": [1228, 802],
|
||||
"name": "Cuba",
|
||||
"strength": 1,
|
||||
"flag": "CU"
|
||||
"flag": "cu"
|
||||
},
|
||||
{
|
||||
"coordinates": [1263, 857],
|
||||
"name": "Jamaica",
|
||||
"strength": 1,
|
||||
"flag": "JM"
|
||||
"flag": "jm"
|
||||
},
|
||||
{
|
||||
"coordinates": [1326, 849],
|
||||
"name": "Haiti",
|
||||
"strength": 1,
|
||||
"flag": "HT"
|
||||
"flag": "ht"
|
||||
},
|
||||
{
|
||||
"coordinates": [1358, 852],
|
||||
"name": "Dominican Republic",
|
||||
"strength": 1,
|
||||
"flag": "DO"
|
||||
"flag": "do"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+33
-33
@@ -7,199 +7,199 @@
|
||||
"coordinates": [718, 738],
|
||||
"name": "Australia",
|
||||
"strength": 1,
|
||||
"flag": "AU"
|
||||
"flag": "au"
|
||||
},
|
||||
{
|
||||
"coordinates": [1050, 809],
|
||||
"name": "New Zealand",
|
||||
"strength": 1,
|
||||
"flag": "NZ"
|
||||
"flag": "nz"
|
||||
},
|
||||
{
|
||||
"coordinates": [686, 407],
|
||||
"name": "Papua New Guinea",
|
||||
"strength": 1,
|
||||
"flag": "PG"
|
||||
"flag": "pg"
|
||||
},
|
||||
{
|
||||
"coordinates": [436, 407],
|
||||
"name": "Timor-Leste",
|
||||
"strength": 1,
|
||||
"flag": "TL"
|
||||
"flag": "tl"
|
||||
},
|
||||
{
|
||||
"coordinates": [182, 378],
|
||||
"name": "Indonesia",
|
||||
"strength": 1,
|
||||
"flag": "ID"
|
||||
"flag": "id"
|
||||
},
|
||||
{
|
||||
"coordinates": [292, 243],
|
||||
"name": "Brunei Darussalam",
|
||||
"strength": 1,
|
||||
"flag": "BN"
|
||||
"flag": "bn"
|
||||
},
|
||||
{
|
||||
"coordinates": [152, 282],
|
||||
"name": "Singapore",
|
||||
"strength": 1,
|
||||
"flag": "SG"
|
||||
"flag": "sg"
|
||||
},
|
||||
{
|
||||
"coordinates": [120, 261],
|
||||
"name": "Malaysia",
|
||||
"strength": 1,
|
||||
"flag": "MY"
|
||||
"flag": "my"
|
||||
},
|
||||
{
|
||||
"coordinates": [106, 129],
|
||||
"name": "Thailand",
|
||||
"strength": 1,
|
||||
"flag": "TH"
|
||||
"flag": "th"
|
||||
},
|
||||
{
|
||||
"coordinates": [51, 42],
|
||||
"name": "Myanmar",
|
||||
"strength": 1,
|
||||
"flag": "MM"
|
||||
"flag": "mm"
|
||||
},
|
||||
{
|
||||
"coordinates": [158, 162],
|
||||
"name": "Cambodia",
|
||||
"strength": 1,
|
||||
"flag": "KH"
|
||||
"flag": "kh"
|
||||
},
|
||||
{
|
||||
"coordinates": [182, 43],
|
||||
"name": "Viet Nam",
|
||||
"strength": 1,
|
||||
"flag": "VN"
|
||||
"flag": "vn"
|
||||
},
|
||||
{
|
||||
"coordinates": [143, 37],
|
||||
"name": "Lao People's Democratic Republic",
|
||||
"strength": 1,
|
||||
"flag": "LA"
|
||||
"flag": "la"
|
||||
},
|
||||
{
|
||||
"coordinates": [278, 18],
|
||||
"name": "Hong Kong",
|
||||
"strength": 1,
|
||||
"flag": "HK"
|
||||
"flag": "hk"
|
||||
},
|
||||
{
|
||||
"coordinates": [359, 1],
|
||||
"name": "Taiwan, Province of China",
|
||||
"strength": 1,
|
||||
"flag": "TW"
|
||||
"flag": "tw"
|
||||
},
|
||||
{
|
||||
"coordinates": [366, 119],
|
||||
"name": "Philippines",
|
||||
"strength": 1,
|
||||
"flag": "PH"
|
||||
"flag": "ph"
|
||||
},
|
||||
{
|
||||
"coordinates": [536, 207],
|
||||
"name": "Palau",
|
||||
"strength": 1,
|
||||
"flag": "PW"
|
||||
"flag": "pw"
|
||||
},
|
||||
{
|
||||
"coordinates": [834, 215],
|
||||
"name": "Micronesia, Federated States of",
|
||||
"strength": 1,
|
||||
"flag": "FM"
|
||||
"flag": "fm"
|
||||
},
|
||||
{
|
||||
"coordinates": [664, 113],
|
||||
"name": "Guam",
|
||||
"strength": 1,
|
||||
"flag": "GU"
|
||||
"flag": "gu"
|
||||
},
|
||||
{
|
||||
"coordinates": [1042, 317],
|
||||
"name": "Marshall Islands",
|
||||
"strength": 1,
|
||||
"flag": "MH"
|
||||
"flag": "mh"
|
||||
},
|
||||
{
|
||||
"coordinates": [799, 385],
|
||||
"name": "Papua New Guinea",
|
||||
"strength": 1,
|
||||
"flag": "PG"
|
||||
"flag": "pg"
|
||||
},
|
||||
{
|
||||
"coordinates": [862, 442],
|
||||
"name": "Solomon Islands",
|
||||
"strength": 1,
|
||||
"flag": "SB"
|
||||
"flag": "sb"
|
||||
},
|
||||
{
|
||||
"coordinates": [945, 497],
|
||||
"name": "Vanuatu",
|
||||
"strength": 1,
|
||||
"flag": "VU"
|
||||
"flag": "vu"
|
||||
},
|
||||
{
|
||||
"coordinates": [930, 574],
|
||||
"name": "New Caledonia",
|
||||
"strength": 1,
|
||||
"flag": "NC"
|
||||
"flag": "nc"
|
||||
},
|
||||
{
|
||||
"coordinates": [1085, 526],
|
||||
"name": "Fiji",
|
||||
"strength": 1,
|
||||
"flag": "FJ"
|
||||
"flag": "fj"
|
||||
},
|
||||
{
|
||||
"coordinates": [1169, 568],
|
||||
"name": "Tonga",
|
||||
"strength": 1,
|
||||
"flag": "TO"
|
||||
"flag": "to"
|
||||
},
|
||||
{
|
||||
"coordinates": [1236, 541],
|
||||
"name": "Niue",
|
||||
"strength": 1,
|
||||
"flag": "NU"
|
||||
"flag": "nu"
|
||||
},
|
||||
{
|
||||
"coordinates": [1204, 473],
|
||||
"name": "Samoa",
|
||||
"strength": 1,
|
||||
"flag": "WS"
|
||||
"flag": "ws"
|
||||
},
|
||||
{
|
||||
"coordinates": [1491, 523],
|
||||
"name": "Cook Islands",
|
||||
"strength": 1,
|
||||
"flag": "CK"
|
||||
"flag": "ck"
|
||||
},
|
||||
{
|
||||
"coordinates": [1623, 424],
|
||||
"name": "French Polynesia",
|
||||
"strength": 1,
|
||||
"flag": "PF"
|
||||
"flag": "pf"
|
||||
},
|
||||
{
|
||||
"coordinates": [1393, 278],
|
||||
"name": "Kiribati",
|
||||
"strength": 1,
|
||||
"flag": "KI"
|
||||
"flag": "ki"
|
||||
},
|
||||
{
|
||||
"coordinates": [1420, 56],
|
||||
"name": "United States",
|
||||
"strength": 1,
|
||||
"flag": "US"
|
||||
"flag": "us"
|
||||
},
|
||||
{
|
||||
"coordinates": [1996, 644],
|
||||
"name": "Chile",
|
||||
"strength": 1,
|
||||
"flag": "CL"
|
||||
"flag": "cl"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+322
-121
@@ -3,12 +3,15 @@ import { customElement, property, state } from "lit/decorators.js";
|
||||
import { Difficulty, GameMapType, GameType } from "../core/game/Game";
|
||||
import { Lobby } from "../core/Schemas";
|
||||
import { consolex } from "../core/Consolex";
|
||||
import "./components/Difficulties";
|
||||
import { DifficultyDescription } from "./components/Difficulties";
|
||||
import "./components/Maps";
|
||||
|
||||
@customElement("host-lobby-modal")
|
||||
export class HostLobbyModal extends LitElement {
|
||||
@state() private isModalOpen = false;
|
||||
@state() private selectedMap: GameMapType = GameMapType.World;
|
||||
@state() private selectedDiffculty: Difficulty = Difficulty.Medium;
|
||||
@state() private selectedDifficulty: Difficulty = Difficulty.Medium;
|
||||
@state() private disableNPCs = false;
|
||||
@state() private disableBots = false;
|
||||
@state() private creativeMode = false;
|
||||
@@ -28,16 +31,57 @@ export class HostLobbyModal extends LitElement {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: white;
|
||||
margin: 15% auto;
|
||||
background-color: rgb(35 35 35 / 0.8);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
backdrop-filter: blur(12px);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
max-width: 1280px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(8px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Add custom scrollbar styles */
|
||||
.modal-content::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
@@ -50,55 +94,183 @@ export class HostLobbyModal extends LitElement {
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
.start-game-button {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
padding: 15px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.3s;
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
.start-game-button:not(:disabled):hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
width: 200px;
|
||||
.start-game-button:disabled {
|
||||
background: linear-gradient(to right, #4a4a4a, #3d3d3d);
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.lobby-id-container {
|
||||
.options-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.options-section {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 12px 24px 24px 24px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.option-title {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.option-cards {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.option-card {
|
||||
width: 100%;
|
||||
min-width: 100px;
|
||||
max-width: 120px;
|
||||
padding: 4px 4px 0 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgba(30, 30, 30, 0.95);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.option-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
background: rgba(40, 40, 40, 0.95);
|
||||
}
|
||||
|
||||
.option-card.selected {
|
||||
border-color: #4a9eff;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.option-card-title {
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.option-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/2;
|
||||
color: #aaa;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* HostLobbyModal css */
|
||||
.clipboard-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.copy-success {
|
||||
position: relative;
|
||||
transform: translateY(-10px);
|
||||
color: green;
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.copy-success-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.lobby-id-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 8px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.clipboard-icon {
|
||||
.lobby-id-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.clipboard-icon:hover {
|
||||
opacity: 0.7;
|
||||
.lobby-id-button:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.copy-success {
|
||||
color: green;
|
||||
.lobby-id {
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.players-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.player-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 4px 16px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -106,97 +278,133 @@ export class HostLobbyModal extends LitElement {
|
||||
return html`
|
||||
<div
|
||||
class="modal-overlay"
|
||||
style="display: ${this.isModalOpen ? "block" : "none"}"
|
||||
style="display: ${this.isModalOpen ? "flex" : "none"}"
|
||||
>
|
||||
<div class="modal-content">
|
||||
<span class="close" @click=${this.close}>×</span>
|
||||
<h2>Private Lobby</h2>
|
||||
<div class="lobby-id-container">
|
||||
<h3>Lobby ID: ${this.lobbyId}</h3>
|
||||
<svg
|
||||
|
||||
<div class="title">Private Lobby</div>
|
||||
<div class="lobby-id-box">
|
||||
<button
|
||||
class="lobby-id-button"
|
||||
@click=${this.copyToClipboard}
|
||||
class="clipboard-icon"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
?disabled=${this.copySuccess}
|
||||
>
|
||||
<path
|
||||
d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"
|
||||
></path>
|
||||
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>
|
||||
</svg>
|
||||
</div>
|
||||
${this.copySuccess
|
||||
? html`<p class="copy-success">Copied to clipboard!</p>`
|
||||
: ""}
|
||||
<div>
|
||||
<label for="map-select">Map: </label>
|
||||
<select id="map-select" @change=${this.handleMapChange}>
|
||||
${Object.entries(GameMapType)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<option
|
||||
value=${value}
|
||||
?selected=${this.selectedMap === value}
|
||||
<span class="lobby-id">${this.lobbyId}</span>
|
||||
${this.copySuccess
|
||||
? html`<span class="copy-success-icon">✓</span>`
|
||||
: html`
|
||||
<svg
|
||||
class="clipboard-icon"
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
stroke-width="0"
|
||||
viewBox="0 0 512 512"
|
||||
height="18px"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
${key}
|
||||
</option>
|
||||
`,
|
||||
<path
|
||||
d="M296 48H176.5C154.4 48 136 65.4 136 87.5V96h-7.5C106.4 96 88 113.4 88 135.5v288c0 22.1 18.4 40.5 40.5 40.5h208c22.1 0 39.5-18.4 39.5-40.5V416h8.5c22.1 0 39.5-18.4 39.5-40.5V176L296 48zm0 44.6l83.4 83.4H296V92.6zm48 330.9c0 4.7-3.4 8.5-7.5 8.5h-208c-4.4 0-8.5-4.1-8.5-8.5v-288c0-4.1 3.8-7.5 8.5-7.5h7.5v255.5c0 22.1 10.4 32.5 32.5 32.5H344v7.5zm48-48c0 4.7-3.4 8.5-7.5 8.5h-208c-4.4 0-8.5-4.1-8.5-8.5v-288c0-4.1 3.8-7.5 8.5-7.5H264v128h128v167.5z"
|
||||
></path>
|
||||
</svg>
|
||||
`}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="options-layout">
|
||||
<!-- Map Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">Map</div>
|
||||
<div class="option-cards">
|
||||
${Object.entries(GameMapType)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<div @click=${() => this.handleMapSelection(value)}>
|
||||
<map-display
|
||||
.mapKey=${key}
|
||||
.selected=${this.selectedMap === value}
|
||||
></map-display>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Difficulty Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">Difficulty</div>
|
||||
<div class="option-cards">
|
||||
${Object.entries(Difficulty)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<div
|
||||
class="option-card ${this.selectedDifficulty === value
|
||||
? "selected"
|
||||
: ""}"
|
||||
@click=${() => this.handleDifficultySelection(value)}
|
||||
>
|
||||
<difficulty-display
|
||||
.difficultyKey=${key}
|
||||
></difficulty-display>
|
||||
<p class="option-card-title">
|
||||
${DifficultyDescription[key]}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lobby Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
${this.players.length}
|
||||
${this.players.length === 1 ? "Player" : "Players"}
|
||||
</div>
|
||||
|
||||
<div class="players-list">
|
||||
${this.players.map(
|
||||
(player) => html`<span class="player-tag">${player}</span>`
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="map-select">Difficulty: </label>
|
||||
<select id="map-select" @change=${this.handleDifficultyChange}>
|
||||
${Object.entries(Difficulty)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<option
|
||||
value=${value}
|
||||
?selected=${this.selectedDiffculty === value}
|
||||
>
|
||||
${key}
|
||||
</option>
|
||||
`,
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-bots"
|
||||
@change=${this.handleDisableBotsChange}
|
||||
/>
|
||||
<label for="disable-bots">Disable Bots</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-npcs"
|
||||
@change=${this.handleDisableNPCsChange}
|
||||
/>
|
||||
<label for="disable-npcs">Disable NPCs</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="creative-mode"
|
||||
@change=${this.handleCreativeModeChange}
|
||||
/>
|
||||
<label for="creative-mode">Creative mode</label>
|
||||
</div>
|
||||
<button @click=${this.startGame}>Start Game</button>
|
||||
<div>
|
||||
<p>Players: ${this.players.join(", ")}</p>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-bots"
|
||||
@change=${this.handleDisableBotsChange}
|
||||
/>
|
||||
<label for="disable-bots">Disable Bots</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-npcs"
|
||||
@change=${this.handleDisableNPCsChange}
|
||||
/>
|
||||
<label for="disable-npcs">Disable NPCs</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="creative-mode"
|
||||
@change=${this.handleCreativeModeChange}
|
||||
/>
|
||||
<label for="creative-mode">Creative mode</label>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
@click=${this.startGame}
|
||||
?disabled=${this.players.length < 2}
|
||||
class="start-game-button"
|
||||
>
|
||||
${this.players.length === 1
|
||||
? "Waiting for players..."
|
||||
: "Start Game"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -217,14 +425,14 @@ export class HostLobbyModal extends LitElement {
|
||||
id: this.lobbyId,
|
||||
},
|
||||
map: this.selectedMap,
|
||||
difficulty: this.selectedDiffculty,
|
||||
difficulty: this.selectedDifficulty,
|
||||
disableBots: this.disableBots,
|
||||
disableNPCs: this.disableNPCs,
|
||||
creativeMode: this.creativeMode,
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
this.isModalOpen = true;
|
||||
@@ -240,19 +448,12 @@ export class HostLobbyModal extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async handleMapChange(e: Event) {
|
||||
this.selectedMap = String(
|
||||
(e.target as HTMLSelectElement).value,
|
||||
) as GameMapType;
|
||||
consolex.log(`updating map to ${this.selectedMap}`);
|
||||
private async handleMapSelection(value: GameMapType) {
|
||||
this.selectedMap = value;
|
||||
this.putGameConfig();
|
||||
}
|
||||
|
||||
private async handleDifficultyChange(e: Event) {
|
||||
this.selectedDiffculty = String(
|
||||
(e.target as HTMLSelectElement).value,
|
||||
) as Difficulty;
|
||||
consolex.log(`updating difficulty to ${this.selectedDiffculty}`);
|
||||
private async handleDifficultySelection(value: Difficulty) {
|
||||
this.selectedDifficulty = value;
|
||||
this.putGameConfig();
|
||||
}
|
||||
|
||||
@@ -282,7 +483,7 @@ export class HostLobbyModal extends LitElement {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
gameMap: this.selectedMap,
|
||||
difficulty: this.selectedDiffculty,
|
||||
difficulty: this.selectedDifficulty,
|
||||
disableBots: this.disableBots,
|
||||
disableNPCs: this.disableNPCs,
|
||||
creativeMode: this.creativeMode,
|
||||
@@ -292,7 +493,7 @@ export class HostLobbyModal extends LitElement {
|
||||
|
||||
private async startGame() {
|
||||
consolex.log(
|
||||
`Starting private game with map: ${GameMapType[this.selectedMap]}`,
|
||||
`Starting private game with map: ${GameMapType[this.selectedMap]}`
|
||||
);
|
||||
this.close();
|
||||
const response = await fetch(`/start_private_lobby/${this.lobbyId}`, {
|
||||
|
||||
+92
-32
@@ -2,46 +2,31 @@ import { EventBus, GameEvent } from "../core/EventBus";
|
||||
import { Game } from "../core/game/Game";
|
||||
|
||||
export class MouseUpEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
constructor(public readonly x: number, public readonly y: number) {}
|
||||
}
|
||||
|
||||
export class MouseDownEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
constructor(public readonly x: number, public readonly y: number) {}
|
||||
}
|
||||
|
||||
export class MouseMoveEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
constructor(public readonly x: number, public readonly y: number) {}
|
||||
}
|
||||
|
||||
export class ContextMenuEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
constructor(public readonly x: number, public readonly y: number) {}
|
||||
}
|
||||
|
||||
export class ZoomEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
public readonly delta: number,
|
||||
public readonly delta: number
|
||||
) {}
|
||||
}
|
||||
|
||||
export class DragEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly deltaX: number,
|
||||
public readonly deltaY: number,
|
||||
) {}
|
||||
constructor(public readonly deltaX: number, public readonly deltaY: number) {}
|
||||
}
|
||||
|
||||
export class AlternateViewEvent implements GameEvent {
|
||||
@@ -51,10 +36,7 @@ export class AlternateViewEvent implements GameEvent {
|
||||
export class RefreshGraphicsEvent implements GameEvent {}
|
||||
|
||||
export class ShowBuildMenuEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
constructor(public readonly x: number, public readonly y: number) {}
|
||||
}
|
||||
|
||||
export class InputHandler {
|
||||
@@ -72,10 +54,13 @@ export class InputHandler {
|
||||
|
||||
private alternateView = false;
|
||||
|
||||
constructor(
|
||||
private canvas: HTMLCanvasElement,
|
||||
private eventBus: EventBus,
|
||||
) {}
|
||||
private moveInterval: any = null;
|
||||
private activeKeys = new Set<string>();
|
||||
|
||||
private readonly PAN_SPEED = 5;
|
||||
private readonly ZOOM_SPEED = 10;
|
||||
|
||||
constructor(private canvas: HTMLCanvasElement, private eventBus: EventBus) {}
|
||||
|
||||
initialize() {
|
||||
this.canvas.addEventListener("pointerdown", (e) => this.onPointerDown(e));
|
||||
@@ -95,14 +80,67 @@ export class InputHandler {
|
||||
});
|
||||
this.pointers.clear();
|
||||
|
||||
// Initialize the combined movement interval
|
||||
this.moveInterval = setInterval(() => {
|
||||
let deltaX = 0;
|
||||
let deltaY = 0;
|
||||
|
||||
// Handle both WASD and arrow keys
|
||||
if (this.activeKeys.has("KeyW") || this.activeKeys.has("ArrowUp"))
|
||||
deltaY += this.PAN_SPEED;
|
||||
if (this.activeKeys.has("KeyS") || this.activeKeys.has("ArrowDown"))
|
||||
deltaY -= this.PAN_SPEED;
|
||||
if (this.activeKeys.has("KeyA") || this.activeKeys.has("ArrowLeft"))
|
||||
deltaX += this.PAN_SPEED;
|
||||
if (this.activeKeys.has("KeyD") || this.activeKeys.has("ArrowRight"))
|
||||
deltaX -= this.PAN_SPEED;
|
||||
|
||||
if (deltaX !== 0 || deltaY !== 0) {
|
||||
this.eventBus.emit(new DragEvent(deltaX, deltaY));
|
||||
}
|
||||
|
||||
// Handle zooming
|
||||
const screenCenterX = window.innerWidth / 2;
|
||||
const screenCenterY = window.innerHeight / 2;
|
||||
|
||||
if (this.activeKeys.has("Minus")) {
|
||||
this.eventBus.emit(
|
||||
new ZoomEvent(screenCenterX, screenCenterY, this.ZOOM_SPEED)
|
||||
);
|
||||
}
|
||||
if (this.activeKeys.has("Equal")) {
|
||||
this.eventBus.emit(
|
||||
new ZoomEvent(screenCenterX, screenCenterY, -this.ZOOM_SPEED)
|
||||
);
|
||||
}
|
||||
}, 1);
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.code === "Space") {
|
||||
e.preventDefault(); // Prevent page scrolling
|
||||
e.preventDefault();
|
||||
if (!this.alternateView) {
|
||||
this.alternateView = true;
|
||||
this.eventBus.emit(new AlternateViewEvent(true));
|
||||
}
|
||||
}
|
||||
|
||||
// Add all movement keys to activeKeys
|
||||
if (
|
||||
[
|
||||
"KeyW",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"ArrowUp",
|
||||
"ArrowLeft",
|
||||
"ArrowDown",
|
||||
"ArrowRight",
|
||||
"Minus",
|
||||
"Equal",
|
||||
].includes(e.code)
|
||||
) {
|
||||
this.activeKeys.add(e.code);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("keyup", (e) => {
|
||||
@@ -115,6 +153,24 @@ export class InputHandler {
|
||||
e.preventDefault();
|
||||
this.eventBus.emit(new RefreshGraphicsEvent());
|
||||
}
|
||||
|
||||
// Remove all movement keys from activeKeys
|
||||
if (
|
||||
[
|
||||
"KeyW",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"ArrowUp",
|
||||
"ArrowLeft",
|
||||
"ArrowDown",
|
||||
"ArrowRight",
|
||||
"Minus",
|
||||
"Equal",
|
||||
].includes(e.code)
|
||||
) {
|
||||
this.activeKeys.delete(e.code);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -193,10 +249,9 @@ export class InputHandler {
|
||||
const pinchDelta = currentPinchDistance - this.lastPinchDistance;
|
||||
|
||||
if (Math.abs(pinchDelta) > 1) {
|
||||
// Threshold to avoid tiny zoom adjustments
|
||||
const zoomCenter = this.getPinchCenter();
|
||||
this.eventBus.emit(
|
||||
new ZoomEvent(zoomCenter.x, zoomCenter.y, -pinchDelta * 2),
|
||||
new ZoomEvent(zoomCenter.x, zoomCenter.y, -pinchDelta * 2)
|
||||
);
|
||||
this.lastPinchDistance = currentPinchDistance;
|
||||
}
|
||||
@@ -222,4 +277,9 @@ export class InputHandler {
|
||||
y: (pointerEvents[0].clientY + pointerEvents[1].clientY) / 2,
|
||||
};
|
||||
}
|
||||
|
||||
destroy() {
|
||||
clearInterval(this.moveInterval);
|
||||
this.activeKeys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,58 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.modal-content {
|
||||
background-color: white;
|
||||
margin: 15% auto;
|
||||
background-color: rgb(35 35 35 / 0.8);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
backdrop-filter: blur(12px);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(8px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Add custom scrollbar styles */
|
||||
.modal-content::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
@@ -37,47 +79,41 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
|
||||
.start-game-button {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
padding: 15px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.3s;
|
||||
display: inline-block;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
button:hover {
|
||||
|
||||
.start-game-button:not(:disabled):hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.lobby-id-container {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.lobby-id-container input {
|
||||
flex-grow: 1;
|
||||
max-width: 200px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.lobby-id-container button {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.join-button {
|
||||
margin-top: 10px;
|
||||
|
||||
.start-game-button:disabled {
|
||||
background: linear-gradient(to right, #4a4a4a, #3d3d3d);
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* JoinPrivateLobbyModal css */
|
||||
|
||||
.message-area {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
@@ -104,26 +140,84 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.lobby-id-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 40px 0px 0px 0px;
|
||||
}
|
||||
.lobby-id-box input {
|
||||
flex-grow: 1;
|
||||
max-width: 200px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.lobby-id-paste-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 10px 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.lobby-id-paste-button:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.lobby-id-paste-button-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div
|
||||
class="modal-overlay"
|
||||
style="display: ${this.isModalOpen ? "block" : "none"}"
|
||||
style="display: ${this.isModalOpen ? "flex" : "none"}"
|
||||
>
|
||||
<div class="modal-content">
|
||||
<span class="close" @click=${this.closeAndLeave}>×</span>
|
||||
<h2>Join Private Lobby</h2>
|
||||
<div class="lobby-id-container">
|
||||
<div class="title">Join Private Lobby</div>
|
||||
<div class="lobby-id-box">
|
||||
<input type="text" id="lobbyIdInput" placeholder="Enter Lobby ID" />
|
||||
<button @click=${this.pasteFromClipboard}>Paste</button>
|
||||
<button
|
||||
@click=${this.pasteFromClipboard}
|
||||
class="lobby-id-paste-button"
|
||||
>
|
||||
<svg
|
||||
class="lobby-id-paste-button-icon"
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
stroke-width="0"
|
||||
viewBox="0 0 32 32"
|
||||
height="18px"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M 15 3 C 13.742188 3 12.847656 3.890625 12.40625 5 L 5 5 L 5 28 L 13 28 L 13 30 L 27 30 L 27 14 L 25 14 L 25 5 L 17.59375 5 C 17.152344 3.890625 16.257813 3 15 3 Z M 15 5 C 15.554688 5 16 5.445313 16 6 L 16 7 L 19 7 L 19 9 L 11 9 L 11 7 L 14 7 L 14 6 C 14 5.445313 14.445313 5 15 5 Z M 7 7 L 9 7 L 9 11 L 21 11 L 21 7 L 23 7 L 23 14 L 13 14 L 13 26 L 7 26 Z M 15 16 L 25 16 L 25 28 L 15 28 Z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="message-area ${this.message ? "show" : ""}">
|
||||
${this.message}
|
||||
</div>
|
||||
${!this.hasJoined
|
||||
? html`<button class="join-button" @click=${this.joinLobby}>
|
||||
? html`<button class="start-game-button" @click=${this.joinLobby}>
|
||||
Join Lobby
|
||||
</button>`
|
||||
: ""}
|
||||
@@ -150,7 +244,7 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
detail: { lobby: this.lobbyIdInput.value },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -188,7 +282,7 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.message = "Lobby not found. Please check the ID and try again.";
|
||||
|
||||
+215
-59
@@ -3,6 +3,9 @@ import { customElement, property, state } from "lit/decorators.js";
|
||||
import { Difficulty, GameMapType, GameType } from "../core/game/Game";
|
||||
import { generateID as generateID } from "../core/Util";
|
||||
import { consolex } from "../core/Consolex";
|
||||
import "./components/Difficulties";
|
||||
import { DifficultyDescription } from "./components/Difficulties";
|
||||
import "./components/Maps";
|
||||
|
||||
@customElement("single-player-modal")
|
||||
export class SinglePlayerModal extends LitElement {
|
||||
@@ -23,16 +26,57 @@ export class SinglePlayerModal extends LitElement {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: white;
|
||||
margin: 15% auto;
|
||||
background-color: rgb(35 35 35 / 0.8);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
backdrop-filter: blur(12px);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
max-width: 1280px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(8px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Add custom scrollbar styles */
|
||||
.modal-content::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
@@ -45,33 +89,109 @@ export class SinglePlayerModal extends LitElement {
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
.start-game-button {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
padding: 15px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.3s;
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
.start-game-button:not(:disabled):hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
width: 200px;
|
||||
.start-game-button:disabled {
|
||||
background: linear-gradient(to right, #4a4a4a, #3d3d3d);
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.options-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.options-section {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 12px 24px 24px 24px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.option-title {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.option-cards {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.option-card {
|
||||
width: 100%;
|
||||
min-width: 100px;
|
||||
max-width: 120px;
|
||||
padding: 4px 4px 0 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgba(30, 30, 30, 0.95);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.option-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
background: rgba(40, 40, 40, 0.95);
|
||||
}
|
||||
|
||||
.option-card.selected {
|
||||
border-color: #4a9eff;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.option-card-title {
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.option-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/2;
|
||||
color: #aaa;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -79,44 +199,74 @@ export class SinglePlayerModal extends LitElement {
|
||||
return html`
|
||||
<div
|
||||
class="modal-overlay"
|
||||
style="display: ${this.isModalOpen ? "block" : "none"}"
|
||||
style="display: ${this.isModalOpen ? "flex" : "none"}"
|
||||
>
|
||||
<div class="modal-content">
|
||||
<span class="close" @click=${this.close}>×</span>
|
||||
<h2>Start Single Player Game</h2>
|
||||
<div>
|
||||
<label for="map-select">Map: </label>
|
||||
<select id="map-select" @change=${this.handleMapChange}>
|
||||
${Object.entries(GameMapType)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<option
|
||||
value=${value}
|
||||
?selected=${this.selectedMap === value}
|
||||
>
|
||||
${value}
|
||||
</option>
|
||||
`,
|
||||
)}
|
||||
</select>
|
||||
|
||||
<div class="title">Single Player</div>
|
||||
|
||||
<div class="options-layout">
|
||||
<!-- Map Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">Map</div>
|
||||
<div class="option-cards">
|
||||
${Object.entries(GameMapType)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<div @click=${() => this.handleMapSelection(value)}>
|
||||
<map-display
|
||||
.mapKey=${key}
|
||||
.selected=${this.selectedMap === value}
|
||||
></map-display>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Difficulty Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">Difficulty</div>
|
||||
<div class="option-cards">
|
||||
${Object.entries(Difficulty)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<div
|
||||
class="option-card ${this.selectedDifficulty === value
|
||||
? "selected"
|
||||
: ""}"
|
||||
@click=${() => this.handleDifficultySelection(value)}
|
||||
>
|
||||
<difficulty-display
|
||||
.difficultyKey=${key}
|
||||
></difficulty-display>
|
||||
<p class="option-card-title">
|
||||
${DifficultyDescription[key]}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="map-select">Difficulty: </label>
|
||||
<select id="map-select" @change=${this.handleDifficultyChange}>
|
||||
${Object.entries(Difficulty)
|
||||
.filter(([key]) => isNaN(Number(key)))
|
||||
.map(
|
||||
([key, value]) => html`
|
||||
<option
|
||||
value=${value}
|
||||
?selected=${this.selectedDifficulty === value}
|
||||
>
|
||||
${value}
|
||||
</option>
|
||||
`,
|
||||
)}
|
||||
</select>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-bots"
|
||||
@change=${this.handleDisableBotsChange}
|
||||
/>
|
||||
<label for="disable-bots">Disable Bots</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="disable-npcs"
|
||||
@change=${this.handleDisableNPCsChange}
|
||||
/>
|
||||
<label for="disable-npcs">Disable NPCs</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
@@ -144,7 +294,18 @@ export class SinglePlayerModal extends LitElement {
|
||||
<label for="creative-mode">Creative mode</label>
|
||||
</div>
|
||||
|
||||
<button @click=${this.startGame}>Start Game</button>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="creative-mode"
|
||||
@change=${this.handleCreativeModeChange}
|
||||
/>
|
||||
<label for="creative-mode">Creative mode</label>
|
||||
</div>
|
||||
|
||||
<button @click=${this.startGame} class="start-game-button">
|
||||
Start Game
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -157,16 +318,11 @@ export class SinglePlayerModal extends LitElement {
|
||||
public close() {
|
||||
this.isModalOpen = false;
|
||||
}
|
||||
|
||||
private handleMapChange(e: Event) {
|
||||
this.selectedMap = String(
|
||||
(e.target as HTMLSelectElement).value,
|
||||
) as GameMapType;
|
||||
private handleMapSelection(value: GameMapType) {
|
||||
this.selectedMap = value;
|
||||
}
|
||||
private handleDifficultyChange(e: Event) {
|
||||
this.selectedDifficulty = String(
|
||||
(e.target as HTMLSelectElement).value,
|
||||
) as Difficulty;
|
||||
private handleDifficultySelection(value: Difficulty) {
|
||||
this.selectedDifficulty = value;
|
||||
}
|
||||
private handleDisableBotsChange(e: Event) {
|
||||
this.disableBots = Boolean((e.target as HTMLInputElement).checked);
|
||||
@@ -179,7 +335,7 @@ export class SinglePlayerModal extends LitElement {
|
||||
}
|
||||
private startGame() {
|
||||
consolex.log(
|
||||
`Starting single player game with map: ${GameMapType[this.selectedMap]}`,
|
||||
`Starting single player game with map: ${GameMapType[this.selectedMap]}`
|
||||
);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("join-lobby", {
|
||||
@@ -196,7 +352,7 @@ export class SinglePlayerModal extends LitElement {
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
})
|
||||
);
|
||||
this.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
export enum DifficultyDescription {
|
||||
Easy = "Relaxed",
|
||||
Medium = "Balanced",
|
||||
Hard = "Intense",
|
||||
Impossible = "Challenging",
|
||||
}
|
||||
|
||||
@customElement("difficulty-display")
|
||||
export class DifficultyDisplay extends LitElement {
|
||||
@property({ type: String }) difficultyKey = "";
|
||||
|
||||
static styles = css`
|
||||
.difficulty-indicator {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
gap: 6px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
|
||||
.difficulty-skull {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.3;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.difficulty-skull.big {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.difficulty-skull.active {
|
||||
opacity: 1;
|
||||
color: #ff3838;
|
||||
filter: drop-shadow(0 0 4px rgba(255, 56, 56, 0.4));
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
:host(:hover) .difficulty-skull.active {
|
||||
filter: drop-shadow(0 0 6px rgba(255, 56, 56, 0.6));
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
`;
|
||||
|
||||
private getDifficultyIcon(difficultyKey: string) {
|
||||
const skull = html`<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
height="100%"
|
||||
width="100%"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="m12.5 17-.5-1-.5 1h1z"></path>
|
||||
<path
|
||||
d="M15 22a1 1 0 0 0 1-1v-1a2 2 0 0 0 1.56-3.25 8 8 0 1 0-11.12 0A2 2 0 0 0 8 20v1a1 1 0 0 0 1 1z"
|
||||
></path>
|
||||
<circle cx="15" cy="12" r="1"></circle>
|
||||
<circle cx="9" cy="12" r="1"></circle>
|
||||
</svg>`;
|
||||
|
||||
const burningSkull = html`<svg
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
stroke-width="0"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="100%"
|
||||
width="100%"
|
||||
>
|
||||
<path
|
||||
d="M268.725 389.28l3.74 28.7h-30.89l3.74-28.7a11.705 11.705 0 1 1 23.41 0zm33.84-71.83a29.5 29.5 0 1 0 29.5 29.5 29.5 29.5 0 0 0-29.51-29.5zm-94.4 0a29.5 29.5 0 1 0 29.5 29.5 29.5 29.5 0 0 0-29.51-29.5zm245.71-62c0 98.2-48.22 182.68-117.39 220.24-46 28.26-112.77 28.26-156.19 2.5-71.72-36.21-122.17-122.29-122.17-222.73 0-78.16 30.54-147.63 77.89-191.67 0 0-42.08 82.86 9.1 135-11.67-173.77 169.28-63 118-184 151.79 83.33 9.14 105 84.1 148.21 0 0 66.21 47 36.4-91.73 42.95 43.99 70.25 110.3 70.25 184.19zm-68.54 29.87c-2.45-65.49-54.88-119.59-120.26-124.07-3.06-.21-6.15-.31-9.16-.31a129.4 129.4 0 0 0-129.43 129.35 132.15 132.15 0 0 0 24.51 76v25a35 35 0 0 0 34.74 34.69h6.26v16.61a34.66 34.66 0 0 0 34.71 34.39h61.78a34.48 34.48 0 0 0 34.51-34.39v-16.61h5.38a34.89 34.89 0 0 0 34.62-34.75v-28a129.32 129.32 0 0 0 22.33-77.9z"
|
||||
></path>
|
||||
</svg>`;
|
||||
|
||||
const kingSkull = html`<svg
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
stroke-width="0"
|
||||
viewBox="0 0 512 512"
|
||||
height="100%"
|
||||
width="100%"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M92.406 13.02l-.164 156.353c3.064.507 6.208 1.38 9.39 2.627 36.496 14.306 74.214 22.435 111.864 25.473l43.402-60.416 42.317 58.906c36.808-4.127 72.566-12.502 105.967-24.09 3.754-1.302 7.368-2.18 10.818-2.6l1.523-156.252-75.82 95.552-34.084-95.55-53.724 103.74-53.722-103.74-35.442 95.55-72.32-95.55h-.006zm164.492 156.07l-28.636 39.86 28.634 39.86 28.637-39.86-28.635-39.86zM86.762 187.55c-2.173-.08-3.84.274-5.012.762-2.345.977-3.173 2.19-3.496 4.196-.645 4.01 2.825 14.35 23.03 21.36 41.7 14.468 84.262 23.748 126.778 26.833l-17.75-24.704c-38.773-3.285-77.69-11.775-115.5-26.596-3.197-1.253-5.877-1.77-8.05-1.85zm333.275.19c-2.156.052-5.048.512-8.728 1.79-33.582 11.65-69.487 20.215-106.523 24.646l-19.264 26.818c40.427-2.602 80.433-11.287 119.22-26.96 15.913-6.43 21.46-17.81 21.36-22.362-.052-2.276-.278-2.566-1.753-3.274-.738-.353-2.157-.71-4.313-.658zm-18.117 47.438c-42.5 15.87-86.26 23.856-130.262 25.117l-14.76 20.547-14.878-20.71c-44.985-1.745-89.98-10.23-133.905-24.306-12.78 28.51-18.94 61.14-19.603 93.44 37.52 17.497 62.135 39.817 75.556 64.63C177 417.8 179.282 443.62 174.184 467.98c7.72 5.007 16.126 9.144 24.98 12.432l5.557-47.89 18.563 2.154-5.935 51.156c9.57 2.21 19.443 3.53 29.377 3.982v-54.67h18.69v54.49c9.903-.638 19.705-2.128 29.155-4.484l-5.857-50.474 18.564-2.155 5.436 46.852c8.747-3.422 17.004-7.643 24.506-12.69-5.758-24.413-3.77-49.666 9.01-72.988 13.28-24.234 37.718-46 74.803-64.29-.62-33.526-6.687-66.122-19.113-94.23zm-266.733 47.006c34.602.23 68.407 12.236 101.358 36.867-46.604 33.147-129.794 34.372-108.29-36.755 2.315-.09 4.626-.127 6.933-.11zm242.825 0c2.307-.016 4.617.022 6.93.11 21.506 71.128-61.684 69.903-108.288 36.757 32.95-24.63 66.756-36.637 101.358-36.866zM255.164 332.14c11.77 21.725 19.193 43.452 25.367 65.178h-50.737c4.57-21.726 13.77-43.45 25.37-65.18z"
|
||||
></path>
|
||||
</svg>`;
|
||||
|
||||
const questionMark = html`<svg
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
stroke-width="0"
|
||||
viewBox="0 0 24 24"
|
||||
height="100%"
|
||||
width="100%"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path fill="none" d="M0 0h24v24H0z"></path>
|
||||
<path
|
||||
d="M11.07 12.85c.77-1.39 2.25-2.21 3.11-3.44.91-1.29.4-3.7-2.18-3.7-1.69 0-2.52 1.28-2.87 2.34L6.54 6.96C7.25 4.83 9.18 3 11.99 3c2.35 0 3.96 1.07 4.78 2.41.7 1.15 1.11 3.3.03 4.9-1.2 1.77-2.35 2.31-2.97 3.45-.25.46-.35.76-.35 2.24h-2.89c-.01-.78-.13-2.05.48-3.15zM14 20c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2z"
|
||||
></path>
|
||||
</svg>`;
|
||||
|
||||
switch (difficultyKey) {
|
||||
case "Easy":
|
||||
return html`
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
<div class="difficulty-skull">${skull}</div>
|
||||
<div class="difficulty-skull">${skull}</div>
|
||||
`;
|
||||
case "Medium":
|
||||
return html`
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
<div class="difficulty-skull">${skull}</div>
|
||||
`;
|
||||
case "Hard":
|
||||
return html`
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
<div class="difficulty-skull active">${skull}</div>
|
||||
`;
|
||||
case "Impossible":
|
||||
return html`
|
||||
<div class="difficulty-skull big active">${burningSkull}</div>
|
||||
`;
|
||||
default:
|
||||
return html`<div class="difficulty-skull big active">
|
||||
${questionMark}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="difficulty-indicator">
|
||||
${this.getDifficultyIcon(this.difficultyKey)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { GameMapType } from "../../core/game/Game";
|
||||
|
||||
// Add map descriptions
|
||||
export const MapDescription: Record<keyof typeof GameMapType, string> = {
|
||||
World: "World",
|
||||
Europe: "Europe",
|
||||
Mena: "MENA",
|
||||
NorthAmerica: "North America",
|
||||
Oceania: "Oceania",
|
||||
BlackSea: "Black Sea",
|
||||
};
|
||||
|
||||
import world from "../../../resources/maps/WorldMap.png";
|
||||
import oceania from "../../../resources/maps/Oceania.png";
|
||||
import europe from "../../../resources/maps/Europe.png";
|
||||
import mena from "../../../resources/maps/Mena.png";
|
||||
import northAmerica from "../../../resources/maps/NorthAmerica.png";
|
||||
import blackSea from "../../../resources/maps/BlackSea.png";
|
||||
|
||||
@customElement("map-display")
|
||||
export class MapDisplay extends LitElement {
|
||||
@property({ type: String }) mapKey = "";
|
||||
@property({ type: Boolean }) selected = false;
|
||||
|
||||
static styles = css`
|
||||
.option-card {
|
||||
width: 100%;
|
||||
min-width: 100px;
|
||||
max-width: 120px;
|
||||
padding: 4px 4px 0 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgba(30, 30, 30, 0.95);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.option-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
background: rgba(40, 40, 40, 0.95);
|
||||
}
|
||||
|
||||
.option-card.selected {
|
||||
border-color: #4a9eff;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.option-card-title {
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.option-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/2;
|
||||
color: #aaa;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
private getMapsImage(map: GameMapType): string {
|
||||
switch (map) {
|
||||
case GameMapType.World:
|
||||
return world;
|
||||
case GameMapType.Oceania:
|
||||
return oceania;
|
||||
case GameMapType.Europe:
|
||||
return europe;
|
||||
case GameMapType.Mena:
|
||||
return mena;
|
||||
case GameMapType.NorthAmerica:
|
||||
return northAmerica;
|
||||
case GameMapType.BlackSea:
|
||||
return blackSea;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const mapValue = GameMapType[this.mapKey as keyof typeof GameMapType];
|
||||
|
||||
return html`
|
||||
<div class="option-card ${this.selected ? "selected" : ""}">
|
||||
${this.getMapsImage(mapValue)
|
||||
? html`<img
|
||||
src="${this.getMapsImage(mapValue)}"
|
||||
alt="${this.mapKey}"
|
||||
class="option-image"
|
||||
/>`
|
||||
: html`<div class="option-image">
|
||||
<p>${this.mapKey}</p>
|
||||
</div>`}
|
||||
<div class="option-card-title">
|
||||
${MapDescription[this.mapKey as keyof typeof GameMapType]}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -94,14 +94,6 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
return;
|
||||
}
|
||||
|
||||
myPlayer.incomingAttacks().forEach((a) => {
|
||||
console.log(
|
||||
`got type: ${(
|
||||
this.game.playerBySmallID(a.attackerID) as PlayerView
|
||||
).type()}`
|
||||
);
|
||||
});
|
||||
|
||||
// Update attacks
|
||||
this.incomingAttacks = myPlayer.incomingAttacks().filter((a) => {
|
||||
const t = (this.game.playerBySmallID(a.attackerID) as PlayerView).type();
|
||||
|
||||
@@ -143,13 +143,12 @@ export class NameLayer implements Layer {
|
||||
element.style.alignItems = "center";
|
||||
element.style.gap = "0px";
|
||||
|
||||
|
||||
if (player.flag()) {
|
||||
const flagImg = document.createElement("img");
|
||||
flagImg.classList.add('player-flag');
|
||||
flagImg.classList.add("player-flag");
|
||||
flagImg.style.marginBottom = "-5%";
|
||||
flagImg.style.opacity = '0.8';
|
||||
flagImg.src = 'flags/' + sanitize(player.flag()) + '.svg';
|
||||
flagImg.style.opacity = "0.8";
|
||||
flagImg.src = "flags/" + sanitize(player.flag()) + ".svg";
|
||||
flagImg.style.zIndex = "1";
|
||||
flagImg.style.width = "40%";
|
||||
flagImg.style.aspectRatio = "3/4";
|
||||
@@ -157,8 +156,9 @@ export class NameLayer implements Layer {
|
||||
}
|
||||
|
||||
const nameDiv = document.createElement("div");
|
||||
nameDiv.classList.add('player-name');
|
||||
nameDiv.innerHTML = (player.type() !== PlayerType.Human ? "🤖 " : '') + player.name();
|
||||
nameDiv.classList.add("player-name");
|
||||
nameDiv.innerHTML =
|
||||
(player.type() !== PlayerType.Human ? "🤖 " : "") + player.name();
|
||||
nameDiv.style.color = this.theme.playerInfoColor(player.id()).toHex();
|
||||
nameDiv.style.fontFamily = this.theme.font();
|
||||
nameDiv.style.whiteSpace = "nowrap";
|
||||
@@ -167,9 +167,8 @@ export class NameLayer implements Layer {
|
||||
nameDiv.style.zIndex = "3";
|
||||
element.appendChild(nameDiv);
|
||||
|
||||
|
||||
const troopsDiv = document.createElement("div");
|
||||
troopsDiv.classList.add('player-troops');
|
||||
troopsDiv.classList.add("player-troops");
|
||||
troopsDiv.textContent = renderTroops(player.troops());
|
||||
troopsDiv.style.color = this.theme.playerInfoColor(player.id()).toHex();
|
||||
troopsDiv.style.fontFamily = this.theme.font();
|
||||
@@ -178,7 +177,7 @@ export class NameLayer implements Layer {
|
||||
element.appendChild(troopsDiv);
|
||||
|
||||
const iconsDiv = document.createElement("div");
|
||||
iconsDiv.classList.add('player-icons');
|
||||
iconsDiv.classList.add("player-icons");
|
||||
iconsDiv.style.display = "flex";
|
||||
iconsDiv.style.gap = "4px";
|
||||
iconsDiv.style.justifyContent = "center";
|
||||
@@ -189,6 +188,9 @@ export class NameLayer implements Layer {
|
||||
iconsDiv.style.height = "100%";
|
||||
element.appendChild(iconsDiv);
|
||||
|
||||
// Start off invisible so it doesn't flash at 0,0
|
||||
element.style.display = "none";
|
||||
|
||||
this.container.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
@@ -226,14 +228,20 @@ export class NameLayer implements Layer {
|
||||
render.lastRenderCalc = now + this.rand.nextInt(0, 100);
|
||||
|
||||
// Update text sizes
|
||||
const nameDiv = render.element.querySelector(".player-name") as HTMLDivElement;
|
||||
const troopsDiv = render.element.querySelector(".player-troops") as HTMLDivElement;
|
||||
const nameDiv = render.element.querySelector(
|
||||
".player-name"
|
||||
) as HTMLDivElement;
|
||||
const troopsDiv = render.element.querySelector(
|
||||
".player-troops"
|
||||
) as HTMLDivElement;
|
||||
nameDiv.style.fontSize = `${render.fontSize}px`;
|
||||
troopsDiv.style.fontSize = `${render.fontSize}px`;
|
||||
troopsDiv.textContent = renderTroops(render.player.troops());
|
||||
|
||||
// Handle icons
|
||||
const iconsDiv = render.element.querySelector(".player-icons") as HTMLDivElement;
|
||||
const iconsDiv = render.element.querySelector(
|
||||
".player-icons"
|
||||
) as HTMLDivElement;
|
||||
const iconSize = Math.min(render.fontSize * 1.5, 48);
|
||||
const myPlayer = this.getPlayer();
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { Colord, colord, random } from "colord";
|
||||
import { Game, PlayerID, PlayerInfo, TerrainType } from "../game/Game";
|
||||
import {
|
||||
Game,
|
||||
PlayerID,
|
||||
PlayerInfo,
|
||||
PlayerType,
|
||||
TerrainType,
|
||||
} from "../game/Game";
|
||||
import { Theme } from "./Config";
|
||||
import { time } from "console";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
@@ -122,6 +128,112 @@ export const pastelTheme = new (class implements Theme {
|
||||
colord({ r: 170, g: 150, b: 170 }), // Dusty Rose
|
||||
];
|
||||
|
||||
private humanColors: Colord[] = [
|
||||
// Original set
|
||||
colord({ r: 235, g: 75, b: 75 }), // Bright Red
|
||||
colord({ r: 67, g: 190, b: 84 }), // Fresh Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Royal Blue
|
||||
colord({ r: 245, g: 158, b: 11 }), // Amber
|
||||
colord({ r: 236, g: 72, b: 153 }), // Deep Pink
|
||||
colord({ r: 48, g: 178, b: 180 }), // Teal
|
||||
colord({ r: 168, g: 85, b: 247 }), // Vibrant Purple
|
||||
colord({ r: 251, g: 191, b: 36 }), // Marigold
|
||||
colord({ r: 74, g: 222, b: 128 }), // Mint
|
||||
colord({ r: 239, g: 68, b: 68 }), // Crimson
|
||||
colord({ r: 34, g: 197, b: 94 }), // Emerald
|
||||
colord({ r: 96, g: 165, b: 250 }), // Sky Blue
|
||||
colord({ r: 249, g: 115, b: 22 }), // Tangerine
|
||||
colord({ r: 192, g: 132, b: 252 }), // Lavender
|
||||
colord({ r: 45, g: 212, b: 191 }), // Turquoise
|
||||
colord({ r: 244, g: 114, b: 182 }), // Rose
|
||||
colord({ r: 132, g: 204, b: 22 }), // Lime
|
||||
colord({ r: 56, g: 189, b: 248 }), // Light Blue
|
||||
colord({ r: 234, g: 179, b: 8 }), // Sunflower
|
||||
colord({ r: 217, g: 70, b: 239 }), // Fuchsia
|
||||
colord({ r: 16, g: 185, b: 129 }), // Sea Green
|
||||
colord({ r: 251, g: 146, b: 60 }), // Light Orange
|
||||
colord({ r: 147, g: 51, b: 234 }), // Bright Purple
|
||||
colord({ r: 79, g: 70, b: 229 }), // Indigo
|
||||
colord({ r: 245, g: 101, b: 101 }), // Coral
|
||||
colord({ r: 134, g: 239, b: 172 }), // Light Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Cerulean
|
||||
colord({ r: 253, g: 164, b: 175 }), // Salmon Pink
|
||||
colord({ r: 147, g: 197, b: 253 }), // Powder Blue
|
||||
colord({ r: 252, g: 211, b: 77 }), // Golden
|
||||
colord({ r: 190, g: 92, b: 251 }), // Amethyst
|
||||
colord({ r: 82, g: 183, b: 136 }), // Jade
|
||||
colord({ r: 248, g: 113, b: 113 }), // Warm Red
|
||||
colord({ r: 99, g: 202, b: 253 }), // Azure
|
||||
colord({ r: 240, g: 171, b: 252 }), // Orchid
|
||||
colord({ r: 163, g: 230, b: 53 }), // Yellow Green
|
||||
colord({ r: 234, g: 88, b: 12 }), // Burnt Orange
|
||||
colord({ r: 125, g: 211, b: 252 }), // Crystal Blue
|
||||
colord({ r: 251, g: 113, b: 133 }), // Watermelon
|
||||
colord({ r: 52, g: 211, b: 153 }), // Spearmint
|
||||
colord({ r: 167, g: 139, b: 250 }), // Periwinkle
|
||||
colord({ r: 245, g: 158, b: 11 }), // Honey
|
||||
colord({ r: 110, g: 231, b: 183 }), // Seafoam
|
||||
colord({ r: 233, g: 213, b: 255 }), // Light Lilac
|
||||
colord({ r: 202, g: 138, b: 4 }), // Rich Gold
|
||||
colord({ r: 151, g: 255, b: 187 }), // Fresh Mint
|
||||
colord({ r: 220, g: 38, b: 38 }), // Ruby
|
||||
colord({ r: 124, g: 58, b: 237 }), // Royal Purple
|
||||
colord({ r: 45, g: 212, b: 191 }), // Ocean
|
||||
colord({ r: 252, g: 165, b: 165 }), // Peach
|
||||
|
||||
// Additional 50 colors
|
||||
colord({ r: 179, g: 136, b: 255 }), // Light Purple
|
||||
colord({ r: 133, g: 77, b: 14 }), // Chocolate
|
||||
colord({ r: 52, g: 211, b: 153 }), // Aquamarine
|
||||
colord({ r: 234, g: 179, b: 8 }), // Mustard
|
||||
colord({ r: 236, g: 72, b: 153 }), // Hot Pink
|
||||
colord({ r: 147, g: 197, b: 253 }), // Sky
|
||||
colord({ r: 249, g: 115, b: 22 }), // Pumpkin
|
||||
colord({ r: 167, g: 139, b: 250 }), // Iris
|
||||
colord({ r: 16, g: 185, b: 129 }), // Pine
|
||||
colord({ r: 251, g: 146, b: 60 }), // Mango
|
||||
colord({ r: 192, g: 132, b: 252 }), // Wisteria
|
||||
colord({ r: 79, g: 70, b: 229 }), // Sapphire
|
||||
colord({ r: 245, g: 101, b: 101 }), // Salmon
|
||||
colord({ r: 134, g: 239, b: 172 }), // Spring Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Ocean Blue
|
||||
colord({ r: 253, g: 164, b: 175 }), // Rose Gold
|
||||
colord({ r: 16, g: 185, b: 129 }), // Forest
|
||||
colord({ r: 252, g: 211, b: 77 }), // Sunshine
|
||||
colord({ r: 190, g: 92, b: 251 }), // Grape
|
||||
colord({ r: 82, g: 183, b: 136 }), // Eucalyptus
|
||||
colord({ r: 248, g: 113, b: 113 }), // Cherry
|
||||
colord({ r: 99, g: 202, b: 253 }), // Arctic
|
||||
colord({ r: 240, g: 171, b: 252 }), // Lilac
|
||||
colord({ r: 163, g: 230, b: 53 }), // Chartreuse
|
||||
colord({ r: 234, g: 88, b: 12 }), // Rust
|
||||
colord({ r: 125, g: 211, b: 252 }), // Ice Blue
|
||||
colord({ r: 251, g: 113, b: 133 }), // Strawberry
|
||||
colord({ r: 52, g: 211, b: 153 }), // Sage
|
||||
colord({ r: 167, g: 139, b: 250 }), // Violet
|
||||
colord({ r: 245, g: 158, b: 11 }), // Apricot
|
||||
colord({ r: 110, g: 231, b: 183 }), // Mint Green
|
||||
colord({ r: 233, g: 213, b: 255 }), // Thistle
|
||||
colord({ r: 202, g: 138, b: 4 }), // Bronze
|
||||
colord({ r: 151, g: 255, b: 187 }), // Pistachio
|
||||
colord({ r: 220, g: 38, b: 38 }), // Fire Engine
|
||||
colord({ r: 124, g: 58, b: 237 }), // Electric Purple
|
||||
colord({ r: 45, g: 212, b: 191 }), // Caribbean
|
||||
colord({ r: 252, g: 165, b: 165 }), // Melon
|
||||
colord({ r: 168, g: 85, b: 247 }), // Byzantium
|
||||
colord({ r: 74, g: 222, b: 128 }), // Kelly Green
|
||||
colord({ r: 239, g: 68, b: 68 }), // Cardinal
|
||||
colord({ r: 34, g: 197, b: 94 }), // Shamrock
|
||||
colord({ r: 96, g: 165, b: 250 }), // Marina
|
||||
colord({ r: 249, g: 115, b: 22 }), // Carrot
|
||||
colord({ r: 192, g: 132, b: 252 }), // Heliotrope
|
||||
colord({ r: 45, g: 212, b: 191 }), // Lagoon
|
||||
colord({ r: 244, g: 114, b: 182 }), // Bubble Gum
|
||||
colord({ r: 132, g: 204, b: 22 }), // Apple
|
||||
colord({ r: 56, g: 189, b: 248 }), // Electric Blue
|
||||
colord({ r: 234, g: 179, b: 8 }), // Daffodil
|
||||
];
|
||||
|
||||
private _selfColor = colord({ r: 0, g: 255, b: 0 });
|
||||
private _allyColor = colord({ r: 255, g: 255, b: 0 });
|
||||
private _enemyColor = colord({ r: 255, g: 0, b: 0 });
|
||||
@@ -133,6 +245,11 @@ export const pastelTheme = new (class implements Theme {
|
||||
}
|
||||
|
||||
territoryColor(playerInfo: PlayerInfo): Colord {
|
||||
if (playerInfo.playerType == PlayerType.Human) {
|
||||
return this.humanColors[
|
||||
simpleHash(playerInfo.name) % this.humanColors.length
|
||||
];
|
||||
}
|
||||
return this.territoryColors[
|
||||
simpleHash(playerInfo.name) % this.territoryColors.length
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user