Merge branch 'openfrontio:main' into main
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: New Contribution Template (Clean)
|
||||
about: "For new Contributions to be added to the Project Management Process, examples removed"
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
.
|
||||
|
||||
---
|
||||
|
||||
## Objectives
|
||||
|
||||
- .
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
.
|
||||
|
||||
---
|
||||
|
||||
[Discord Name if Different]
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: New Contribution Template
|
||||
about: "For new Contributions to be added to the Project Management Process "
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
By the time the contribution is ready for final review, the main post of the Issue should be able to serve as the PR description, supplemented by the testing results/peer reviews.
|
||||
|
||||
## Purpose
|
||||
|
||||
Very brief statement as to what this contribution's purpose is. Examples:
|
||||
|
||||
- Add new feature that allows users to create custom flags.
|
||||
- Fix bug: modals not closing on game start.
|
||||
- Add new Iceland map.
|
||||
|
||||
---
|
||||
|
||||
## Objectives
|
||||
|
||||
Please provide a short list of objectives for the contribution, the number and level of specificity of the items will depend on the scope of the contribution. Is the means by which completion can be measured and success of the changes assessed. May be the starting point for the creation of sub-issues if collaboration is needed/desired. Examples:
|
||||
|
||||
**For the Custom Flags Feature**
|
||||
|
||||
- Create UI for Flag Customization.
|
||||
- Create customization features that provide a wide range of possibilities for users to express themselves.
|
||||
- Ensure some customization features are limited to users with certain traits.
|
||||
- Assess user traits related to limited customization against Discord roles.
|
||||
- Create method for customized flags to be displayed correctly on all connected clients.
|
||||
- Create means of restricting certain customization combinations to prevent hate symbols, or ensure it is not possible to create hate symbols with provided customizations.
|
||||
|
||||
**For a Bug Fix**
|
||||
|
||||
- Ensure all open modals except game start (and any other expected) modal close as expected when the game starts.
|
||||
- Ensure all modals still function as expected prior to game start.
|
||||
|
||||
**For New Map**
|
||||
|
||||
- Add New Map, Iceland to the game for use in Singleplayer and Custom lobbies.
|
||||
- Add map to lobby rotation.
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Please provide a more detailed description of what is being changed/added, how it is being changed/added, provide any additional detail related to the objectives which would be needed or useful in assessing the contribution overall.
|
||||
|
||||
Examples of what info would be expected:
|
||||
|
||||
**For the Custom Flags Feature**
|
||||
|
||||
- Details about where the UI would be accessed from, mockups of a concept UI if they exist.
|
||||
- What kind of customizations will be available.
|
||||
- What traits will be provided limited customization features? (Patreons, Devs, Owner, etc.)
|
||||
- What kind of customizations will be limited.
|
||||
- Any high-level technical implementation details that may be useful in assessing viability, or which will require assistance from other contributors or the project owner (communication between the clients, use or access to a backend DB, discord integration, etc.)
|
||||
|
||||
**For a Bug Fix**
|
||||
|
||||
- Details about the bug's behavior
|
||||
- Details about the cause of the bug (once known)
|
||||
- Details about the fix
|
||||
- Any secondary effects of implementing the fix
|
||||
|
||||
**For a New Map**
|
||||
|
||||
- Size of the map
|
||||
- Number of Nation Bots
|
||||
- Images of the Map
|
||||
- Any interesting features of the map
|
||||
|
||||
---
|
||||
|
||||
[Discord Name if Different]
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Deploy to Remote
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_environment:
|
||||
description: "Deployment Environment"
|
||||
required: true
|
||||
default: "staging"
|
||||
type: choice
|
||||
options:
|
||||
- production
|
||||
- staging
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy to ${{ inputs.target_environment }}
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ inputs.target_environment }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
|
||||
cat >.env <<EOF
|
||||
SERVER_HOST_STAGING=${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}
|
||||
DOCKER_REPO_STAGING=${{ vars.DOCKERHUB_REPO }}
|
||||
DOCKER_USERNAME=${{ vars.DOCKERHUB_USERNAME }}
|
||||
EOF
|
||||
./deploy.sh ${{ inputs.target_environment }}
|
||||
@@ -9,6 +9,7 @@
|
||||
</p>
|
||||
|
||||

|
||||
[](https://crowdin.com/project/openfront-mls)
|
||||
|
||||
OpenFront is an online real-time strategy game focused on territorial control and alliance building. Players compete to expand their territory, build structures, and form strategic alliances in various maps based on real-world geography.
|
||||
|
||||
@@ -125,9 +126,10 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
Translators are welcome! Please feel free to help translate into your language.
|
||||
How to help?
|
||||
1. Go to the project's Crowdin translation page: [https://crowdin.com/project/openfrontio](https://crowdin.com/project/openfrontio)
|
||||
|
||||
1. Go to the project's Crowdin translation page: [https://crowdin.com/project/openfront-mls](https://crowdin.com/project/openfront-mls)
|
||||
2. Login if you already have an account/ Sign up if you don't have one
|
||||
3. Select the language you want to translate in/ If your language isn't on the list, create a new topic in "Discussions" about adding the language
|
||||
3. Select the language you want to translate in/ If your language isn't on the list, click the "Request New Language" button and enter the language you want added there.
|
||||
4. Translate the strings
|
||||
|
||||
### Project Governance
|
||||
|
||||
@@ -1 +1,997 @@
|
||||
google.com, pub-7035513310742290, DIRECT, f08c47fec0942fa0
|
||||
ownerdomain=openfront.io
|
||||
managerdomain=venatus.com
|
||||
#V 01.04.2025 VH
|
||||
#V
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
# . #
|
||||
# .o8 #
|
||||
# oooo ooo .ooooo. ooo. .oo. .oooo. .o888oo oooo oooo .oooo.o #
|
||||
# `88. .8' d88' `88b `888P"Y88b `P )88b 888 `888 `888 d88( "8 #
|
||||
# `88..8' 888ooo888 888 888 .oP"888 888 888 888 `"Y88b. #
|
||||
# `888' 888 . 888 888 d8( 888 888 . 888 888 o. )88b #
|
||||
# `8' `Y8bod8P' o888o o888o `Y888""8o "888" `V88V"V8P' 8""888P' #
|
||||
# #
|
||||
# The leading advertising solution for gaming and entertainment #
|
||||
# #
|
||||
# To become a publisher or advertise please contact info@venatus.com #
|
||||
# #
|
||||
#----------------------------------------------------------------------------#
|
||||
adagio.io, 1090, DIRECT
|
||||
rubiconproject.com, 19116, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 159110, RESELLER, 5d62403b186f2ace
|
||||
lijit.com, 367236, RESELLER, fafdf38b16bf6b2b
|
||||
improvedigital.com, 1790, RESELLER
|
||||
triplelift.com, 13482, RESELLER, 6c33edb13117fd86
|
||||
rubiconproject.com, 12186, RESELLER, 0bfd66d529a55807
|
||||
video.unrulymedia.com, 5672421953199218469, RESELLER
|
||||
amxrtb.com, 105199358, DIRECT
|
||||
amxrtb.com, 105199778, DIRECT
|
||||
sharethrough.com, a6a34444, RESELLER, d53b998a7bd4ecd2
|
||||
appnexus.com, 12290, RESELLER
|
||||
pubmatic.com, 158355, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 23844, RESELLER, 0bfd66d529a55807
|
||||
openx.com, 559680764, RESELLER, 6a698e2ec38604c6
|
||||
adform.com, 2767, RESELLER
|
||||
adyoulike.com, c1314a52de718f3c214c00173d2994f9, DIRECT
|
||||
pubmatic.com, 160925, RESELLER, 5d62403b186f2ace
|
||||
aps.amazon.com,70247b00-ff8f-4016-b3ab-8344daf96e09,DIRECT
|
||||
aniview.com, 5f2063121d82c82557194737, RESELLER, 78b21b97965ec3f8
|
||||
aniview.com, 643f8e74688b10f72307cc24, DIRECT, 78b21b97965ec3f8
|
||||
google.com, pub-6346866704322274, RESELLER, f08c47fec0942fa0
|
||||
pubmatic.com, 160993, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 13918, RESELLER, 0bfd66d529a55807
|
||||
google.com, pub-5717092533913515, RESELLER, f08c47fec0942fa0
|
||||
gannett.com, 22652678936, RESELLER
|
||||
richaudience.com, 1ru8dKmJJV, RESELLER
|
||||
sharethrough.com, zLsEa05k, RESELLER, d53b998a7bd4ecd2
|
||||
aps.amazon.com, 1ad7261b-91ea-4b6f-b9e9-b83522205b75, RESELLER
|
||||
pubmatic.com, 161335, RESELLER, 5d62403b186f2ace
|
||||
openx.com, 556532676, RESELLER, 6a698e2ec38604c6
|
||||
mediago.io, 045ac24b888bcf59a09731e7f0f2084f, RESELLER
|
||||
blockthrough.com, 5643766199222272, DIRECT
|
||||
criteo.com, B-062405, DIRECT, 9fac4a4a87c2a44f
|
||||
themediagrid.com, CVQXOH, DIRECT, 35d5010d7789b49d
|
||||
freewheel.tv, 211121, DIRECT
|
||||
freewheel.tv, 211129-524565, DIRECT
|
||||
freewheel.tv, 211129-169843, DIRECT
|
||||
google.com, pub-5781531207509232, DIRECT, f08c47fec0942fa0
|
||||
google.com, pub-5781531207509232, RESELLER, f08c47fec0942fa0
|
||||
google.com, pub-2553634189837243, RESELLER, f08c47fec0942fa0
|
||||
gumgum.com, 13385, RESELLER, ffdef49475d318a9
|
||||
gumgum.com, 14302, RESELLER, ffdef49475d318a9
|
||||
rubiconproject.com, 23434, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 157897, RESELLER, 5d62403b186f2ace
|
||||
indexexchange.com, 183921, DIRECT, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 193067, DIRECT, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 194127, DIRECT, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 205972, RESELLER, 50b1c356f2c5c8fc
|
||||
Blis.com,33,RESELLER,61453ae19a4b73f4
|
||||
conversantmedia.com,40881,RESELLER,03113cd04947736d
|
||||
insticator.com,843c9a44-60ea-4342-8ad4-68f894283b3e,DIRECT,b3511ffcafb23a32
|
||||
sharethrough.com,Q9IzHdvp,DIRECT,d53b998a7bd4ecd2
|
||||
rubiconproject.com,17062,RESELLER,0bfd66d529a55807
|
||||
risecodes.com,6124caed9c7adb0001c028d8,DIRECT
|
||||
pubmatic.com,95054,DIRECT,5d62403b186f2ace
|
||||
openx.com,558230700,RESELLER,6a698e2ec38604c6
|
||||
video.unrulymedia.com,136898039,RESELLER
|
||||
lijit.com,257618,RESELLER,fafdf38b16bf6b2b
|
||||
minutemedia.com,01garg96c88b,RESELLER
|
||||
appnexus.com,3695,RESELLER,f5ab79cb980f11d1
|
||||
kargo.com, 8688, DIRECT
|
||||
kueez.com,e5b6208bc94ed2d5788e1e4c1cf5452e, DIRECT
|
||||
rubiconproject.com, 16920, RESELLER, 0bfd66d529a55807
|
||||
openx.com, 557564833, RESELLER, 6a698e2ec38604c6
|
||||
lijit.com, 407406, RESELLER, fafdf38b16bf6b2b #SOVRN
|
||||
appnexus.com, 8826,RESELLER, f5ab79cb980f11d1
|
||||
Media.net,8CU4JTRF9, RESELLER
|
||||
rubiconproject.com, 13762, RESELLER, 0bfd66d529a55807
|
||||
media.net, 8CU8ARTF8, DIRECT
|
||||
Media.net, 8CU198XI2, DIRECT
|
||||
themediagrid.com, LTW57M, DIRECT, 35d5010d7789b49d
|
||||
ogury.com, 086233d2-e8a8-44fc-907b-f0752e1c85de, DIRECT
|
||||
appnexus.com, 11470, RESELLER
|
||||
openx.com, 542378302, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540134228, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 537144009, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 560557013, RESELLER, 6a698e2ec38604c6
|
||||
optidigital.com,p230,DIRECT
|
||||
pubmatic.com,158939,RESELLER,5d62403b186f2ace
|
||||
rubiconproject.com,20336,RESELLER,0bfd66d529a55807
|
||||
smartadserver.com,3379,RESELLER,060d053dcf45cbf3
|
||||
triplelift.com,8183,RESELLER,6c33edb13117fd86
|
||||
the-ozone-project.com, ozoneven0005, DIRECT
|
||||
openx.com, 540731760, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 160557, RESELLER, 5d62403b186f2ace
|
||||
themediagrid.com, WF71T3, DIRECT, 35d5010d7789b49d
|
||||
Yahoo.com, 60170, DIRECT, e1a5b5b6e3255540
|
||||
pubmatic.com, 159234, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 160552, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 159401, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 165533, RESELLER, 5d62403b186f2ace
|
||||
richaudience.com, 1XvIoD5o0S, DIRECT
|
||||
pubmatic.com, 81564, DIRECT, 5d62403b186f2ace
|
||||
pubmatic.com, 156538, DIRECT, 5d62403b186f2ace
|
||||
appnexus.com, 8233, DIRECT
|
||||
rubiconproject.com, 13510, DIRECT
|
||||
risecodes.com, 5fa94677b2db6a00015b22a9, DIRECT
|
||||
pubmatic.com, 160295, RESELLER, 5d62403b186f2ace
|
||||
xandr.com, 14082, RESELLER
|
||||
rubiconproject.com, 23876, RESELLER, 0bfd66d529a55807
|
||||
sharethrough.com, 5926d422, RESELLER, d53b998a7bd4ecd2
|
||||
yieldmo.com, 2754490424016969782, RESELLER
|
||||
media.net, 8CUQ6928Q, RESELLER
|
||||
onetag.com, 69f48c2160c8113, RESELLER
|
||||
amxrtb.com, 105199691, RESELLER
|
||||
openx.com, 537140488, RESELLER, 6a698e2ec38604c6
|
||||
video.unrulymedia.com, 335119963, RESELLER
|
||||
seedtag.com, 5aa6c80640c9e209009721e0, DIRECT
|
||||
xandr.com, 4009, DIRECT, f5ab79cb980f11d1
|
||||
rubiconproject.com, 17280, DIRECT, 0bfd66d529a55807
|
||||
smartadserver.com, 3050, DIRECT
|
||||
lijit.com, 397546, DIRECT, fafdf38b16bf6b2b
|
||||
sharethrough.com, 31c129df, DIRECT, d53b998a7bd4ecd2
|
||||
sharethrough.com, awx1H4AI, RESELLER, d53b998a7bd4ecd2
|
||||
smaato.com, 1100055690, DIRECT, 07bcf65f187117b4
|
||||
smaato.com, 1100049216, DIRECT, 07bcf65f187117b5
|
||||
rubiconproject.com, 24600, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 156177, RESELLER, 5d62403b186f2ace
|
||||
smartadserver.com, 3490, DIRECT
|
||||
smartadserver.com, 4016, DIRECT
|
||||
smartadserver.com, 4074, DIRECT
|
||||
sovrn.com, 237754, DIRECT, fafdf38b16bf6b2b
|
||||
lijit.com, 237754, DIRECT, fafdf38b16bf6b2b
|
||||
lijit.com, 506352, DIRECT, fafdf38b16bf6b2b
|
||||
teads.tv, 23348, DIRECT, 15a9c44f6d26cbe1
|
||||
triplelift.com, 6059, RESELLER, 6c33edb13117fd86
|
||||
video.unrulymedia.com, 985572675, DIRECT
|
||||
video.unrulymedia.com, 985572675, RESELLER
|
||||
sharethrough.com, 6qlnf8SY, RESELLER, d53b998a7bd4ecd2
|
||||
appnexus.com, 12986, RESELLER, f5ab79cb980f11d1
|
||||
improvedigital.com, 1069, RESELLER
|
||||
pubmatic.com, 158056, RESELLER
|
||||
Weborama.nl, 10714, DIRECT
|
||||
adwmg.com, 101261, DIRECT, c9688a22012618e7
|
||||
google.com, pub-8622186303703569, DIRECT, f08c47fec0942fa0
|
||||
freewheel.tv, 1604590, DIRECT
|
||||
freewheel.tv, 1604595, DIRECT
|
||||
pubmatic.com, 156512, DIRECT
|
||||
indexexchange.com, 183753, DIRECT
|
||||
wunderkind.co, 6438, DIRECT
|
||||
wunderkind.co, 6449, DIRECT
|
||||
criteo.com, B-068503, DIRECT
|
||||
appnexus.com, 806, DIRECT, f5ab79cb980f11d1
|
||||
appnexus.com,1908,RESELLER,f5ab79cb980f11d1
|
||||
adinplay.com, FTB, DIRECT
|
||||
venatus.com, 67f90df66f43edab7e84d165, DIRECT
|
||||
|
||||
##################################
|
||||
# AdinPlay.com ads.txt - 2025-04-16
|
||||
##################################
|
||||
|
||||
adinplay.com, OFI, DIRECT
|
||||
|
||||
#Google
|
||||
google.com, pub-3282547114800347, RESELLER, f08c47fec0942fa0
|
||||
|
||||
#Appnexus
|
||||
appnexus.com, 8631, RESELLER, f5ab79cb980f11d1
|
||||
|
||||
#Index
|
||||
indexexchange.com, 186547, RESELLER, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 187218, RESELLER, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 177754, RESELLER, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 196862, RESELLER, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 207014, RESELLER, 50b1c356f2c5c8fc
|
||||
|
||||
|
||||
#Pulsepoint
|
||||
contextweb.com, 561767, RESELLER, 89ff185a4c4e857c
|
||||
|
||||
#Pubmatic
|
||||
pubmatic.com, 156975, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156857, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 162231, RESELLER, 5d62403b186f2ace
|
||||
|
||||
#OpenX
|
||||
openx.com, 540164985, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540010967, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540182293, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 556894440, RESELLER, 6a698e2ec38604c6
|
||||
|
||||
|
||||
#Sovrn
|
||||
sovrn.com, 268781, RESELLER, fafdf38b16bf6b2b
|
||||
lijit.com, 268781, RESELLER, fafdf38b16bf6b2b
|
||||
lijit.com, 268781-eb, DIRECT, fafdf38b16bf6b2b
|
||||
appnexus.com, 1360, RESELLER, f5ab79cb980f11d1
|
||||
openx.com, 538959099, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 539924617, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 137711, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156212, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 17960, RESELLER, 0bfd66d529a55807
|
||||
sovrn.com, 264160, RESELLER, fafdf38b16bf6b2b
|
||||
lijit.com, 264160, RESELLER, fafdf38b16bf6b2b
|
||||
lijit.com, 264160-eb, DIRECT, fafdf38b16bf6b2b
|
||||
smartadserver.com, 4125, RESELLER
|
||||
sharethrough.com,7144eb80,RESELLER
|
||||
|
||||
|
||||
#Oath
|
||||
coxmt.com, 2000067907202, RESELLER
|
||||
pubmatic.com, 156377, RESELLER, 5d62403b186f2ace #banner
|
||||
pubmatic.com, 156078, RESELLER, 5d62403b186f2ace #banner
|
||||
pubmatic.com, 155967, RESELLER, 5d62403b186f2ace #banner
|
||||
openx.com, 537143344, RESELLER, 6a698e2ec38604c6
|
||||
indexexchange.com, 175407, RESELLER, 50b1c356f2c5c8fc
|
||||
|
||||
#Rhythmone
|
||||
rhythmone.com, 1432377581,DIRECT, a670c89d4a324e47
|
||||
rhythmone.com, 665259327, DIRECT, a670c89d4a324e47
|
||||
rhythmone.com, 2451244104, RESELLER, a670c89d4a324e47
|
||||
video.unrulymedia.com, 2451244104, RESELLER
|
||||
video.unrulymedia.com, 1432377581, DIRECT
|
||||
|
||||
|
||||
#Gumgum
|
||||
aolcloud.net,9904,RESELLER
|
||||
appnexus.com,1001,DIRECT,f5ab79cb980f11d1
|
||||
appnexus.com,2758,RESELLER,f5ab79cb980f11d1
|
||||
appnexus.com,3135,DIRECT,f5ab79cb980f11d1
|
||||
bidtellect.com,1407,RESELLER,1c34aa2d85d45e93
|
||||
contextweb.com,558355,RESELLER,89ff185a4c4e857c
|
||||
openx.com,537120563,DIRECT,6a698e2ec38604c6
|
||||
openx.com,537149485,RESELLER,6a698e2ec38604c6
|
||||
google.com,pub-9557089510405422,DIRECT,f08c47fec0942fa0
|
||||
google.com,pub-3848273848634341,RESELLER,f08c47fec0942fa0
|
||||
google.com, pub-7861278482560604, RESELLER, f08c47fec0942fa0
|
||||
rhythmone.com,78519861,RESELLER, a670c89d4a324e47
|
||||
outbrain.com,01a755b08c8c22b15d46a8b753ab6955d4,RESELLER
|
||||
appnexus.com,7597,RESELLER,f5ab79cb980f11d1
|
||||
openx.com,540003333,RESELLER,6a698e2ec38604c6
|
||||
33across.com,0013300001r0t9mAAA,RESELLER
|
||||
|
||||
|
||||
#Amazon
|
||||
aps.amazon.com,53b902f9-cf9c-4605-aec3-2c8ce65042b8,DIRECT
|
||||
gumgum.com,13543,DIRECT,ffdef49475d318a9
|
||||
appnexus.com,8631,DIRECT,f5ab79cb980f11d1
|
||||
indexexchange.com,196862,DIRECT,50b1c356f2c5c8fc
|
||||
pubmatic.com,160006,RESELLER,5d62403b186f2ace
|
||||
pubmatic.com,160096,RESELLER,5d62403b186f2ace
|
||||
rubiconproject.com,18020,RESELLER,0bfd66d529a55807
|
||||
pubmatic.com,162231,DIRECT,5d62403b186f2ace
|
||||
appnexus.com,1908,RESELLER,f5ab79cb980f11d1
|
||||
smaato.com,1100044650,RESELLER,07bcf65f187117b4
|
||||
ad-generation.jp,12474,RESELLER,7f4ea9029ac04e53
|
||||
districtm.io,100962,RESELLER,3fd707be9c4527c3
|
||||
yieldmo.com,2719019867620450718,RESELLER
|
||||
appnexus.com,3663,RESELLER,f5ab79cb980f11d1
|
||||
rhythmone.com,1654642120,RESELLER,a670c89d4a324e47
|
||||
yahoo.com,55029,RESELLER,e1a5b5b6e3255540
|
||||
gumgum.com,14141,RESELLER,ffdef49475d318a9
|
||||
admanmedia.com,726,RESELLER
|
||||
emxdgt.com,2009,RESELLER,1e1d41537f7cad7f
|
||||
appnexus.com,1356,RESELLER,f5ab79cb980f11d1
|
||||
contextweb.com,562541,RESELLER,89ff185a4c4e857c
|
||||
themediagrid.com,JTQKMP,RESELLER,35d5010d7789b49d
|
||||
sovrn.com,375328,RESELLER,fafdf38b16bf6b2b
|
||||
lijit.com,375328,RESELLER,fafdf38b16bf6b2b
|
||||
beachfront.com,14804,RESELLER,e2541279e8e2ca4d
|
||||
improvedigital.com,2050,RESELLER
|
||||
mintegral.com,10043,RESELLER,0aeed750c80d6423
|
||||
sonobi.com,7f5fa520f8,RESELLER,d1a215d9eb5aee9e
|
||||
openx.com,556894440,DIRECT,6a698e2ec38604c6
|
||||
onetag.com,7683ebe7bee7969,DIRECT
|
||||
media.net,8CUZ1MK22,RESELLER
|
||||
sharethrough.com,buaxQzOE,DIRECT,d53b998a7bd4ecd2
|
||||
smartadserver.com,4571,DIRECT,060d053dcf45cbf3
|
||||
mediago.io,045ac24b888bcf59a09731e7f0f2084f,RESELLER
|
||||
adyoulike.com,7463c359225e043c111036d7a29affa5,RESELLER
|
||||
minutemedia.com,01gya4708ddm,RESELLER
|
||||
visiblemeasures.com,1052,RESELLER
|
||||
undertone.com,4205,RESELLER,d954590d0cb265b9
|
||||
admedia.com,AM1601,RESELLER,ae6c32151e71f19d
|
||||
triplelift.com,8472,DIRECT,6c33edb13117fd86
|
||||
kargo.com,8824,RESELLER
|
||||
start.io,123111883,RESELLER
|
||||
connectad.io,455,RESELLER,85ac85a30c93b3e5
|
||||
|
||||
# 33Across
|
||||
rubiconproject.com, 16414, RESELLER, 0bfd66d529a55807 #33Across #hb #tag
|
||||
rubiconproject.com, 21642, RESELLER, 0bfd66d529a55807 #33Across #hb #tag #viewable
|
||||
rubiconproject.com, 21434, RESELLER, 0bfd66d529a55807 #33Across #tag #ebda
|
||||
rubiconproject.com, 21720, RESELLER, 0bfd66d529a55807 #33Across EU #hb #tag
|
||||
pubmatic.com, 156423, RESELLER, 5d62403b186f2ace #33Across #hb #tag
|
||||
pubmatic.com, 158136, RESELLER, 5d62403b186f2ace #33Across EU #hb #tag
|
||||
pubmatic.com, 158569, RESELLER, 5d62403b186f2ace #33Across #tag #ebda
|
||||
appnexus.com, 10239, RESELLER, f5ab79cb980f11d1 #33Across #hb #tag #viewable
|
||||
appnexus.com, 1001, RESELLER, f5ab79cb980f11d1 #33Across #tag
|
||||
appnexus.com, 3135, RESELLER, f5ab79cb980f11d1 #33Across #tag
|
||||
openx.com, 537120563, RESELLER, 6a698e2ec38604c6 #33Across #hb #tag
|
||||
openx.com, 539392223, RESELLER, 6a698e2ec38604c6 #33Across #tag #ebda
|
||||
openx.com, 540995201, RESELLER, 6a698e2ec38604c6 #33Across #hb #tag #viewable
|
||||
adtech.com, 12094, RESELLER #33Across #hb #tag
|
||||
adtech.com, 9993, RESELLER #33Across #tag
|
||||
aol.com, 47594, RESELLER, e1a5b5b6e3255540 #33Across #hb #tag #viewable
|
||||
yahoo.com, 55188, DIRECT, e1a5b5b6e3255540 #33Across #tag #ebda
|
||||
advangelists.com, 8d3bba7425e7c98c50f52ca1b52d3735, RESELLER, 60d26397ec060f98 #33Across #hb #tag
|
||||
sonobi.com, a416546bb7, RESELLER, d1a215d9eb5aee9e #33Across #tag #ebda
|
||||
indexexchange.com, 190966, RESELLER, 50b1c356f2c5c8fc #33Across #tag #ebda
|
||||
indexexchange.com, 183635, RESELLER, 50b1c356f2c5c8fc #33Across #hb #tag #viewable
|
||||
google.com, pub-9557089510405422, RESELLER, f08c47fec0942fa0 #33Across #tag
|
||||
|
||||
#Rubiconproject
|
||||
rubiconproject.com, 15636, RESELLER, 0bfd66d529a55807
|
||||
|
||||
#LockerDome
|
||||
lockerdome.com, 11908041977355520, DIRECT
|
||||
|
||||
#Yield Nexus
|
||||
yieldnexus.com, 1, DIRECT
|
||||
ssp.ynxs.io, 185, DIRECT
|
||||
appnexus.com, 10617, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 9393, RESELLER, f5ab79cb980f11d1
|
||||
advertising.com, 25034, RESELLER
|
||||
sonobi.com, 783272317b, RESELLER, d1a215d9eb5aee9e
|
||||
indexexchange.com, 186684,RESELLER, 50b1c356f2c5c8fc
|
||||
|
||||
#CPM
|
||||
appnexus.com, 9624, RESELLER, f5ab79cb980f11d1
|
||||
adtech.com, 11506, RESELLER
|
||||
yahoo.com, 56896, RESELLER
|
||||
pubmatic.com, 156078, RESELLER, 5d62403b186f2ace
|
||||
advertising.com, 25218, RESELLER #video, US
|
||||
beachfront.com, 9065, RESELLER
|
||||
contextweb.com, 559969, RESELLER, 89ff185a4c4e857c
|
||||
indexexchange.com, 189455, RESELLER, 50b1c356f2c5c8fc
|
||||
advertising.com, 28320, RESELLER
|
||||
richaudience.com, NtMZGaQQTT, RESELLER
|
||||
adform.com, 1942, RESELLER
|
||||
adform.com, 1941, RESELLER
|
||||
adtech.com, 4687, RESELLER
|
||||
aerserv.com, 2750, RESELLER, 2ce496b9f80eb9fa
|
||||
aol.com, 27093, RESELLER
|
||||
aol.com, 46658, RESELLER
|
||||
aolcloud.net, 4687, RESELLER
|
||||
appnexus.com, 2928, RESELLER, f5ab79cb980f11d1
|
||||
contextweb.com, 560520, RESELLER, 89ff185a4c4e857c
|
||||
google.com, pub-9115524111147081, RESELLER, f08c47fec0942fa0
|
||||
google.com, pub-4673227357197067, RESELLER, f08c47fec0942fa0
|
||||
indexexchange.com, 179394, RESELLER, 50b1c356f2c5c8fc
|
||||
lijit.com, 249425, RESELLER, fafdf38b16bf6b2b
|
||||
cpmstar.com, 49818, RESELLER
|
||||
mobfox.com, 74240, RESELLER
|
||||
mobfox.com, 45499, RESELLER
|
||||
openx.com, 539625136, RESELLER, 6a698e2ec38604c6
|
||||
smaato.com, 1100037086, RESELLER
|
||||
smaato.com, 1100000579, RESELLER
|
||||
sovrn.com, 249425, RESELLER, fafdf38b16bf6b2b
|
||||
openx.com, 541079309, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 541166421, RESELLER, 6a698e2ec38604c6
|
||||
contextweb.com, 562263, RESELLER, 89ff185a4c4e857c
|
||||
districtm.io, 102015, RESELLER, 3fd707be9c4527c3
|
||||
lkqd.net, 304, RESELLER, 59c49fa9598a0117
|
||||
lkqd.com, 304, RESELLER, 59c49fa9598a0117
|
||||
advertising.com, 2694, RESELLER
|
||||
google.com, pub-5781531207509232, RESELLER, f08c47fec0942fa0
|
||||
appnexus.com, 806, RESELLER, f5ab79cb980f11d1
|
||||
freewheel.tv, 211121, RESELLER
|
||||
freewheel.tv, 211129, RESELLER
|
||||
indexexchange.com, 183921, RESELLER, 50b1c356f2c5c8fc
|
||||
openx.com, 540134228, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540634629, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 156715, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 13762, RESELLER, 0bfd66d529a55807
|
||||
smartadserver.com, 3490, RESELLER
|
||||
springserve.com, 550, RESELLER, a24eb641fc82e93d
|
||||
beachfront.com, 4969, RESELLER, e2541279e8e2ca4d
|
||||
advertising.com, 26282, RESELLER
|
||||
pubmatic.com, 157310, RESELLER, 5d62403b186f2ace
|
||||
rhythmone.com, 2968119028, RESELLER, a670c89d4a324e47
|
||||
contextweb.com, 561910, RESELLER, 89ff185a4c4e857c
|
||||
openx.com, 540226160, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540255318, RESELLER, 6a698e2ec38604c6
|
||||
ssp.ynxs.io, 185, RESELLER
|
||||
tremorhub.com, hpwve, RESELLER, 1a4e959a1b50034a
|
||||
telaria.com, hpwve, RESELLER, 1a4e959a1b50034a
|
||||
video.unrulymedia.com, UNRX-PUB-29dad46b-9bec-43c7-b950-c59d09cc8c71, RESELLER
|
||||
video.unrulymedia.com, 985572675, RESELLER
|
||||
rhythmone.com, 2864567592, RESELLER, a670c89d4a324e47
|
||||
vidoomy.com, 51019, RESELLER
|
||||
aol.com, 22762, RESELLER
|
||||
freewheel.tv, 872257, RESELLER
|
||||
openx.com, 540804929, RESELLER, 6a698e2ec38604c6
|
||||
emxdgt.com, 1495, RESELLER, 1e1d41537f7cad7f
|
||||
|
||||
#Rubicon
|
||||
rubiconproject.com, 23042, RESELLER, 0bfd66d529a55807
|
||||
rubiconproject.com, 23044, RESELLER, 0bfd66d529a55807
|
||||
|
||||
|
||||
#AMX
|
||||
|
||||
amxrtb.com, 105199469, RESELLER
|
||||
appnexus.com, 12290, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 11786, RESELLER, f5ab79cb980f11d1
|
||||
indexexchange.com, 191503, RESELLER, 50b1c356f2c5c8fc
|
||||
lijit.com, 260380, RESELLER, fafdf38b16bf6b2b
|
||||
sovrn.com, 260380, RESELLER, fafdf38b16bf6b2b
|
||||
pubmatic.com, 158355, RESELLER, 5d62403b186f2ace
|
||||
appnexus.com, 9393, RESELLER, f5ab79cb980f11d1 #Video #Display
|
||||
appnexus.com, 11924, RESELLER, f5ab79cb980f11d1
|
||||
|
||||
#Kueez
|
||||
kueez.com, fe46d13305ce1b89f18a84c52275b7fe, DIRECT
|
||||
appnexus.com, 8826, RESELLER
|
||||
rubiconproject.com, 16920, RESELLER
|
||||
openx.com, 557564833, RESELLER
|
||||
lijit.com, 407406, RESELLER
|
||||
media.net, 8cu4jtrf9, RESELLER
|
||||
pubmatic.com, 162110, RESELLER
|
||||
sharethrough.com, n98xdzel, RESELLER
|
||||
33across.com, 0010b00002odu4haax, RESELLER
|
||||
yieldmo.com, 3133660606033240149, RESELLER
|
||||
onetag.com, 6e053d779444c00, RESELLER
|
||||
video.unrulymedia.com, 3486482593, RESELLER
|
||||
sonobi.com, 4c4fba1717, RESELLER
|
||||
smartadserver.com, 4288, RESELLER
|
||||
zetaglobal.com, 108, RESELLER
|
||||
improvedigital.com, 2106, RESELLER
|
||||
loopme.com, 11576, RESELLER
|
||||
themediagrid.com, uot45z, RESELLER
|
||||
|
||||
|
||||
#Aniview
|
||||
|
||||
aniview.com, 606c5af8b82e996ca965f498, RESELLER, 78b21b97965ec3f8
|
||||
advertising.com, 23089, RESELLER
|
||||
appnexus.com, 12637, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 9382, RESELLER, f5ab79cb980f11d1
|
||||
synacor.com, 82171, RESELLER, e108f11b2cdf7d5b
|
||||
pubmatic.com, 156344, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 13344, RESELLER, 0bfd66d529a55807
|
||||
indexexchange.com, 191740, RESELLER, 50b1c356f2c5c8fc
|
||||
conversantmedia.com, 100195, DIRECT, 03113cd04947736d
|
||||
appnexus.com, 4052, RESELLER, f5ab79cb980f11d1
|
||||
contextweb.com, 561998, RESELLER, 89ff185a4c4e857c
|
||||
pubmatic.com, 158100, RESELLER, 5d62403b186f2ace
|
||||
yahoo.com, 55771, RESELLER, e1a5b5b6e3255540
|
||||
onetag.com, 57e618150c70d90, DIRECT
|
||||
google.com, pub-3769010358500643, RESELLER, f08c47fec0942fa0
|
||||
video.unrulymedia.com, 3350674472, DIRECT
|
||||
rhythmone.com, 3350674472, DIRECT, a670c89d4a324e47
|
||||
google.com, pub-4586415728471297, RESELLER, f08c47fec0942fa0
|
||||
google.com, pub-3565385483761681, DIRECT, f08c47fec0942fa0
|
||||
google.com, pub-5717092533913515, RESELLER, f08c47fec0942fa0
|
||||
smartadserver.com, 2786, DIRECT
|
||||
improvedigital.com, 1147, DIRECT
|
||||
google.com, pub-2930805104418204, RESELLER, f08c47fec0942fa0
|
||||
google.com, pub-4903453974745530, RESELLER, f08c47fec0942fa0
|
||||
richaudience.com, 1ru8dKmJJV, DIRECT
|
||||
advertising.com, 7574, RESELLER
|
||||
appnexus.com, 8233, RESELLER, f5ab79cb980f11d1
|
||||
pubmatic.com, 81564, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156538, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 13510, RESELLER, 0bfd66d529a55807
|
||||
smartadserver.com, 2640, RESELLER
|
||||
smartadserver.com, 2441, RESELLER
|
||||
yahoo.com, 57857, RESELLER, e1a5b5b6e3255540
|
||||
undertone.com, 4077, DIRECT
|
||||
appnexus.com, 2234, RESELLER, f5ab79cb980f11d1
|
||||
rubiconproject.com, 22412, RESELLER, 0bfd66d529a55807
|
||||
advertising.com, 28650, RESELLER
|
||||
pubmatic.com, 160318, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 160319, RESELLER, 5d62403b186f2ace
|
||||
appnexus.com, 10112, RESELLER, f5ab79cb980f11d1
|
||||
google.com, pub-0679975395820445, RESELLER, f08c47fec0942fa0
|
||||
google.com, pub-9936969251765866, RESELLER, f08c47fec0942fa0
|
||||
|
||||
#Fluct
|
||||
adingo.jp, 25262, RESELLER
|
||||
pubmatic.com, 156313, RESELLER, 5d62403b186f2ace
|
||||
appnexus.com, 7044, RESELLER, f5ab79cb980f11d1
|
||||
pubmatic.com, 158060, RESELLER, 5d62403b186f2ace
|
||||
|
||||
#Conversant
|
||||
conversantmedia.com, 100106, RESELLER, 03113cd04947736d
|
||||
lijit.com, 411121, RESELLER, fafdf38b16bf6b2b #SOVRN
|
||||
admanmedia.com, 2050, RESELLER
|
||||
Appnerve.com, 187287, RESELLER
|
||||
rubiconproject.com, 23644, RESELLER, 0bfd66d529a55807
|
||||
|
||||
|
||||
#OneTag
|
||||
onetag.com, 7683ebe7bee7969, RESELLER
|
||||
onetag.com, 7683ebe7bee7969-OB, RESELLER
|
||||
appnexus.com, 13099, RESELLER, f5ab79cb980f11d1
|
||||
yahoo.com, 58905, RESELLER, e1a5b5b6e3255540
|
||||
rubiconproject.com, 11006, RESELLER, 0bfd66d529a55807
|
||||
smartadserver.com, 4111, RESELLER
|
||||
|
||||
#Media.net
|
||||
media.net, 8CUEHU9Y5, RESELLER
|
||||
openx.com, 537100188, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 159463, RESELLER, 5d62403b186f2ace
|
||||
emxdgt.com, 1759, RESELLER, 1e1d41537f7cad7f
|
||||
google.com, pub-7439041255533808, RESELLER, f08c47fec0942fa0
|
||||
rubiconproject.com, 19396, RESELLER, 0bfd66d529a55807
|
||||
onetag.com, 5d49f482552c9b6, RESELLER
|
||||
sonobi.com, 83729e979b, RESELLER
|
||||
33across.com, 0010b00002cGp2AAAS, RESELLER, bbea06d9c4d2853c
|
||||
rhythmone.com, 3611299104, RESELLER, a670c89d4a324e47
|
||||
districtm.io, 100600, RESELLER
|
||||
lemmatechnologies.com, 399, RESELLER, 7829010c5bebd1fb #LEMMA
|
||||
e-planning.net,ec771b05828a67fa,RESELLER,c1ba615865ed87b2
|
||||
google.com, pub-9685734445476814, RESELLER, f08c47fec0942fa0
|
||||
|
||||
#EMX Digital
|
||||
emxdgt.com, 2345, RESELLER, 1e1d41537f7cad7f
|
||||
|
||||
|
||||
#The MediaGrid
|
||||
themediagrid.com, B8ZEVT, RESELLER, 35d5010d7789b49d
|
||||
themediagrid.com, 3W8S2K, RESELLER, 35d5010d7789b49d
|
||||
|
||||
#triplelift
|
||||
triplelift.com, 12900, RESELLER, 6c33edb13117fd86
|
||||
triplelift.com, 12900-EB, DIRECT, 6c33edb13117fd86
|
||||
triplelift.com, 13897, DIRECT, 6c33edb13117fd86
|
||||
|
||||
#Sharethrough
|
||||
|
||||
sharethrough.com, buaxQzOE, RESELLER, d53b998a7bd4ecd2
|
||||
sharethrough.com, jvyAFD6e, DIRECT, d53b998a7bd4ecd2
|
||||
pubmatic.com, 156557, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 18694, RESELLER, 0bfd66d529a55807
|
||||
openx.com, 540274407, RESELLER, 6a698e2ec38604c6
|
||||
33across.com, 0013300001kQj2HAAS, RESELLER, bbea06d9c4d2853c
|
||||
smaato.com, 1100047713, RESELLER, 07bcf65f187117b4
|
||||
yahoo.com, 59531, RESELLER, e1a5b5b6e3255540
|
||||
smartadserver.com, 4342, RESELLER
|
||||
smartadserver.com, 4012, RESELLER
|
||||
|
||||
|
||||
#V 15.01.2024 PH
|
||||
|
||||
#------------------------------------------------------------------------------------------------------
|
||||
adagio.io, 1090, DIRECT # Adagio_0_6
|
||||
rubiconproject.com, 19116, RESELLER, 0bfd66d529a55807 # Adagio_0_6
|
||||
pubmatic.com, 159110, RESELLER, 5d62403b186f2ace # Adagio_0_6
|
||||
improvedigital.com, 1790, RESELLER # Adagio_0_6
|
||||
indexexchange.com, 194558, RESELLER # Adagio_0_6
|
||||
richaudience.com, 1BTOoaD22a, DIRECT # Adagio_0_6
|
||||
33across.com, 0015a00002oUk4aAAC, DIRECT, bbea06d9c4d2853c # Adagio_0_6
|
||||
appnexus.com, 10239, RESELLER, f5ab79cb980f11d1 # Adagio_0_6
|
||||
rubiconproject.com, 16414, RESELLER, 0bfd66d529a55807 # Adagio_0_6
|
||||
lijit.com, 367236, RESELLER, fafdf38b16bf6b2b # Adagio_0_6
|
||||
e-planning.net, 83c06e81531537f4, RESELLER, c1ba615865ed87b2 # Adagio_0_6
|
||||
amxrtb.com, 105199358, DIRECT # AdaptMX_1_6&7
|
||||
indexexchange.com, 191503, RESELLER # AdaptMX_1_6&7
|
||||
appnexus.com, 11786, RESELLER # AdaptMX_1_6&7
|
||||
appnexus.com, 12290, RESELLER # AdaptMX_1_6&7
|
||||
pubmatic.com, 158355, RESELLER, 5d62403b186f2ace # AdaptMX_1_6&7
|
||||
advertising.com, 28305, RESELLER # AdaptMX_1_6&7
|
||||
rubiconproject.com, 23844, RESELLER, 0bfd66d529a55807 # AdaptMX_1_6&7
|
||||
openx.com, 559680764, RESELLER, 6a698e2ec38604c6 # AdaptMX_1_6&7
|
||||
adform.com, 2767, RESELLER # Adform_0_6&7
|
||||
adyoulike.com, c1314a52de718f3c214c00173d2994f9, DIRECT # AdYouLike_0_6
|
||||
pubmatic.com, 160925, RESELLER, 5d62403b186f2ace # AdYouLike_0_6
|
||||
rubiconproject.com, 20736, RESELLER, 0bfd66d529a55807 # AdYouLike_0_6
|
||||
appnexus.com, 7664, RESELLER # AdYouLike_0_6
|
||||
aps.amazon.com,70247b00-ff8f-4016-b3ab-8344daf96e09,DIRECT # Amazon_3_6&7
|
||||
ad-generation.jp,12474,RESELLER # Amazon_3_6&7
|
||||
aniview.com, 5f2063121d82c82557194737, RESELLER, 78b21b97965ec3f8 # Aniview
|
||||
aniview.com, 643f8e74688b10f72307cc24, DIRECT, 78b21b97965ec3f8 # Aniview
|
||||
google.com, pub-6346866704322274, RESELLER, f08c47fec0942fa0 # Aniview
|
||||
pubmatic.com, 160993, RESELLER, 5d62403b186f2ace # Aniview
|
||||
rubiconproject.com, 13918, RESELLER, 0bfd66d529a55807 # Aniview
|
||||
google.com, pub-5717092533913515, RESELLER, f08c47fec0942fa0 # Aniview
|
||||
gannett.com, 22652678936, RESELLER # Aniview
|
||||
richaudience.com, 1ru8dKmJJV, RESELLER # Aniview
|
||||
appnexus.com, 12637, RESELLER, f5ab79cb980f11d1 # Aniview
|
||||
google.com, pub-3565385483761681, RESELLER, f08c47fec0942fa0 # Aniview
|
||||
sharethrough.com, zLsEa05k, RESELLER, d53b998a7bd4ecd2 # Aniview
|
||||
aps.amazon.com, 1ad7261b-91ea-4b6f-b9e9-b83522205b75, RESELLER # Aniview
|
||||
pubmatic.com, 161335, RESELLER, 5d62403b186f2ace # Aniview
|
||||
google.com, pub-7734005103835923, RESELLER, f08c47fec0942fa0 # Aniview
|
||||
openx.com, 559611024, RESELLER, 6a698e2ec38604c6 # Aniview
|
||||
yieldlab.net, 495507, DIRECT # Aniview
|
||||
blockthrough.com, 5643766199222272, DIRECT # Blockthrough
|
||||
appnexus.com, 6979, RESELLER # Blockthrough
|
||||
indexexchange.com, 194341, RESELLER, 50b1c356f2c5c8fc # Blockthrough
|
||||
pubmatic.com, 160377, RESELLER, 5d62403b186f2ace # Blockthrough
|
||||
rubiconproject.com, 23718, RESELLER, 0bfd66d529a55807 # Blockthrough
|
||||
onetag.com, 75804861b76a852, DIRECT # Blockthrough
|
||||
amxrtb.com, 105199664, DIRECT # Blockthrough
|
||||
criteo.com, B-062405, DIRECT, 9fac4a4a87c2a44f # Criteo_0_6&7
|
||||
themediagrid.com, CVQXOH, DIRECT, 35d5010d7789b49d # Criteo_0_6&7
|
||||
cpmstar.com, 53615, DIRECT # CPMSTAR
|
||||
rhythmone.com,1838093862,DIRECT,a670c89d4a324e47 # CPMSTAR
|
||||
video.unrulymedia.com, 1838093862, DIRECT # CPMSTAR
|
||||
pubmatic.com, 160251, DIRECT, 5d62403b186f2ace # CPMSTAR
|
||||
pubmatic.com, 161595, DIRECT, 5d62403b186f2ace # CPMSTAR
|
||||
rubiconproject.com, 23330, DIRECT, 0bfd66d529a55807 # CPMSTAR
|
||||
conversantmedia.com, 41150, DIRECT, 03113cd04947736d # Epsilon
|
||||
adingo.jp, 24379, DIRECT # Fluct_1_6&7
|
||||
freewheel.tv, 211121, DIRECT # Freewheel_0_7
|
||||
freewheel.tv, 211129, RESELLER # Freewheel_0_7
|
||||
google.com, pub-5781531207509232, RESELLER, f08c47fec0942fa0 # Google_AdX_6&7
|
||||
google.com, pub-2553634189837243, RESELLER, f08c47fec0942fa0 # Google_AdX_6&7
|
||||
gumgum.com, 13385, RESELLER, ffdef49475d318a9 # GumGum_JP_0_9_6
|
||||
gumgum.com, 14302, RESELLER, ffdef49475d318a9 # GumGum_JP_0_9_6
|
||||
improvedigital.com, 1012, DIRECT # Improve_0_6&7
|
||||
improvedigital.com, 1640, RESELLER # Improve_1_6
|
||||
improvedigital.com, 2114, RESELLER # Improve_kids_1_6&7
|
||||
indexexchange.com, 183921, DIRECT, 50b1c356f2c5c8fc # Index Exchange_0_6&7
|
||||
indexexchange.com, 188416, DIRECT, 50b1c356f2c5c8fc # Index Exchange_1_6&7
|
||||
indexexchange.com, 193067, DIRECT, 50b1c356f2c5c8fc # Index Exchange_2_6&7
|
||||
indexexchange.com, 194127, DIRECT, 50b1c356f2c5c8fc # Index Exchange_7&4_6&7
|
||||
indexexchange.com, 205972, RESELLER, 50b1c356f2c5c8fc # Index Exchange_Oz
|
||||
indexexchange.com, 206870, RESELLER, 50b1c356f2c5c8fc # Index_EasyConnect
|
||||
iion.io, 10133, DIRECT # iion
|
||||
kargo.com, 8688, DIRECT # Kargo_0_6
|
||||
rubiconproject.com, 17902, RESELLER, 0bfd66d529a55807 # Magnite_1_6&7
|
||||
rubiconproject.com, 13762, RESELLER, 0bfd66d529a55807 # Magnite_0&2_6&7
|
||||
telaria.com,hpwve,RESELLER,1a4e959a1b50034a # Magnite_Streaming
|
||||
tremorhub.com,hpwve,RESELLER,1a4e959a1b50034a # Magnite_Streaming
|
||||
media.net, 8CU8ARTF8, DIRECT # Media.net
|
||||
Media.net, 8CU5786QK, DIRECT # Media.net
|
||||
themediagrid.com, LTW57M, DIRECT, 35d5010d7789b49d # MediaGrid_2_6&7
|
||||
minutemedia.com, 01gerz6y43ck, RESELLER # MinuteMedia_0_6
|
||||
pubmatic.com, 161683, RESELLER, 5d62403b186f2ace # MinuteMedia_0_6
|
||||
appnexus.com, 8381, RESELLER # MinuteMedia_0_6
|
||||
triplelift.com, 6030, RESELLER, 6c33edb13117fd86 # MinuteMedia_0_6
|
||||
33across.com, 0013300001jlr99AAA, RESELLER, bbea06d9c4d2853c # MinuteMedia_0_6
|
||||
nobid.io, 22629800915, DIRECT # Nobid_0_6
|
||||
sonobi.com, 7ad1b9f952, RESELLER, d1a215d9eb5aee9e # Nobid_0_6
|
||||
xandr.com, 12701, RESELLER, f5ab79cb980f11d1 # Nobid_0_6
|
||||
lijit.com, 273657, DIRECT, fafdf38b16bf6b2b # Nobid_0_6
|
||||
onetag.com, 694e68b73971b58, DIRECT # Nobid_0_6
|
||||
yahoo.com, 57872, RESELLER # Nobid_0_6
|
||||
sharethrough.com, UvcAx8IL, DIRECT, d53b998a7bd4ecd2 # Nobid_0_6
|
||||
ogury.com, 086233d2-e8a8-44fc-907b-f0752e1c85de, DIRECT # Ogury_0_6
|
||||
appnexus.com, 11470, RESELLER # Ogury_0_6
|
||||
openx.com, 537144009, RESELLER, 6a698e2ec38604c6 # OpenX_0_6
|
||||
openx.com, 540134228, RESELLER, 6a698e2ec38604c6 # OpenX_0_7
|
||||
openx.com, 540368327, RESELLER, 6a698e2ec38604c6 # OpenX_1_6&7
|
||||
openx.com, 542378302, RESELLER, 6a698e2ec38604c6 # OpenX_2_6&7
|
||||
the-ozone-project.com, ozoneven0005, DIRECT # Ozone_0_6
|
||||
appnexus.com, 9979, RESELLER # Ozone_0_6
|
||||
openx.com, 540731760, RESELLER, 6a698e2ec38604c6 # Ozone_0_6
|
||||
adform.com, 2657, RESELLER, 9f5210a2f0999e32 # Ozone_0_6
|
||||
pubmatic.com, 160557, RESELLER, 5d62403b186f2ace # Ozone_0_6
|
||||
themediagrid.com, WF71T3, DIRECT, 35d5010d7789b49d # Ozone_0_6
|
||||
pgamssp.com, 634dc90283fff00f005151f2, DIRECT # PGAM_0_7
|
||||
freewheel.tv, 1489202, RESELLER # PGAM_0_7
|
||||
freewheel.tv, 1488706, RESELLER # PGAM_0_7
|
||||
video.unrulymedia.com, 5921144960123684292, RESELLER # PGAM_0_7
|
||||
appnexus.com, 9291, RESELLER # PGAM_0_7
|
||||
pubmatic.com, 162623, RESELLER, 5d62403b186f2ace # PGAM_0_7
|
||||
primis.tech, 31136, DIRECT, b6b21d256ef43532 # Primis
|
||||
pubmatic.com, 156595, RESELLER, 5d62403b186f2ace # Primis
|
||||
google.com, pub-1320774679920841, RESELLER, f08c47fec0942fa0 # Primis
|
||||
openx.com, 540258065, RESELLER, 6a698e2ec38604c6 # Primis
|
||||
rubiconproject.com, 20130, RESELLER, 0bfd66d529a55807 # Primis
|
||||
freewheel.tv, 19133, RESELLER, 74e8e47458f74754 # Primis
|
||||
smartadserver.com, 3436, RESELLER, 060d053dcf45cbf3 # Primis
|
||||
indexexchange.com, 191923, RESELLER, 50b1c356f2c5c8fc # Primis
|
||||
adform.com, 2078, RESELLER # Primis
|
||||
Media.net, 8CU695QH7, RESELLER # Primis
|
||||
video.unrulymedia.com, 2338962694, RESELLER # Primis
|
||||
sharethrough.com, flUyJowI, RESELLER, d53b998a7bd4ecd2 # Primis
|
||||
triplelift.com, 8210, RESELLER, 6c33edb13117fd86 # Primis
|
||||
yahoo.com, 59260, RESELLER # Primis
|
||||
pubmatic.com, 159234, RESELLER, 5d62403b186f2ace # PubMatic_0_6&7
|
||||
pubmatic.com, 158940, RESELLER, 5d62403b186f2ace # PubMatic_1_6&7
|
||||
pubmatic.com, 160552, RESELLER, 5d62403b186f2ace # PubMatic_4_7
|
||||
pubmatic.com, 159401, RESELLER, 5d62403b186f2ace # PubMatic_2_6&7
|
||||
pubmatic.com, 163598, RESELLER, 5d62403b186f2ace # Pubmatic_OW
|
||||
richaudience.com, 1XvIoD5o0S, DIRECT # Rich Audience_0_6&7
|
||||
risecodes.com, 5fa94677b2db6a00015b22a9, DIRECT # Rise
|
||||
pubmatic.com, 160295, RESELLER, 5d62403b186f2ace # Rise
|
||||
xandr.com, 14082, RESELLER # Rise
|
||||
rubiconproject.com, 23876, RESELLER, 0bfd66d529a55807 # Rise
|
||||
media.net, 8CUQ6928Q, RESELLER # Rise_Temp
|
||||
sharethrough.com, 5926d422, RESELLER, d53b998a7bd4ecd2 # Rise_Temp
|
||||
sharethrough.com, 31c129df, DIRECT, d53b998a7bd4ecd2 # Sharethrough_0_6&7
|
||||
sharethrough.com, Ip2TfKpa, DIRECT, d53b998a7bd4ecd2 # Sharethrough_1_6&7
|
||||
smartadserver.com, 2161, RESELLER # Showheroes_7_8
|
||||
appnexus.com, 8833, RESELLER, f5ab79cb980f11d1 # Showheroes_7_8
|
||||
smartadserver.com, 3668, RESELLER # Showheroes_7_8
|
||||
freewheel.tv, 1003361, DIRECT # Showheroes_7_8
|
||||
pubmatic.com, 156695, DIRECT, 5d62403b186f2ace # Showheroes_7_8
|
||||
showheroes.com, 6829, RESELLER # Showheroes_7_8
|
||||
smartadserver.com, 3490, DIRECT # Smart AdServer_0&1&2_6&7
|
||||
smartadserver.com, 3490-OB, DIRECT, 060d053dcf45cbf3 # Smart AdServer_0&1&2_6&7
|
||||
smartadserver.com, 4016, DIRECT # Smart AdServer_0&1&2_6&7
|
||||
smartadserver.com, 4074, DIRECT # Smart AdServer_0&1&2_6&7
|
||||
smaato.com, 1100055690, DIRECT, 07bcf65f187117b4 # Smaato
|
||||
smaato.com, 1100004890, DIRECT, 07bcf65f187117b4 # Smaato
|
||||
sonobi.com, 116da9d98c, DIRECT, d1a215d9eb5aee9e # Sonobi_0_6&7
|
||||
sonobi.com, e017850301, DIRECT, d1a215d9eb5aee9e # Sonobi_4_7
|
||||
sovrn.com, 237754, DIRECT, fafdf38b16bf6b2b # Sovrn_0&1&2_6&7
|
||||
lijit.com, 237754, DIRECT, fafdf38b16bf6b2b # Sovrn_0&1&2_6&7
|
||||
lijit.com, 237754-eb, DIRECT, fafdf38b16bf6b2b # Sovrn_1_6&7
|
||||
taboola.com,1422403,DIRECT,c228e6794e811952 # Taboola_6_8
|
||||
triplelift.com, 6059, DIRECT, 6c33edb13117fd86 # Triplelift_0&2_6&7
|
||||
triplelift.com, 6059-EB, DIRECT, 6c33edb13117fd86 # Triplelift_0&2_6&7
|
||||
video.unrulymedia.com, 985572675, DIRECT # Unruly_0&2_7
|
||||
rhythmone.com, 2864567592, DIRECT, a670c89d4a324e47 # Unruly_0&2_7
|
||||
xandr.com, 13799, RESELLER # Unruly
|
||||
sharethrough.com, 6qlnf8SY, RESELLER, d53b998a7bd4ecd2 # Unruly
|
||||
vidazoo.com, 655c85dc63ceeb606a0f365f, DIRECT, b6ada874b4d7d0b2 # Vidazoo
|
||||
pubmatic.com, 159988, RESELLER, 5d62403b186f2ace # Vidazoo
|
||||
rubiconproject.com, 17130, RESELLER, 0bfd66d529a55807 # Vidazoo
|
||||
pubmatic.com, 156512, DIRECT # Wunderkind
|
||||
indexexchange.com, 183753, DIRECT # Wunderkind
|
||||
wunderkind.co, 6438, DIRECT # Wunderkind
|
||||
wunderkind.co, 6449, DIRECT # Wunderkind
|
||||
criteo.com, B-068503, DIRECT # Wunderkind
|
||||
appnexus.com, 806, DIRECT, f5ab79cb980f11d1 # Xandr_0&2_6&7
|
||||
appnexus.com,1908,RESELLER,f5ab79cb980f11d1 # Xandr_0&2_6&7
|
||||
|
||||
|
||||
#Equativ
|
||||
|
||||
smartadserver.com, 4571, RESELLER, 060d053dcf45cbf3
|
||||
smartadserver.com, 4571-OB, RESELLER, 060d053dcf45cbf3
|
||||
smartadserver.com, 4016, RESELLER, 060d053dcf45cbf3 #Global
|
||||
smartadserver.com, 4012, RESELLER, 060d053dcf45cbf3 #EUR
|
||||
smartadserver.com, 4071, RESELLER, 060d053dcf45cbf3 #USD
|
||||
smartadserver.com, 4073, RESELLER, 060d053dcf45cbf3 #BRL
|
||||
smartadserver.com, 4074, RESELLER, 060d053dcf45cbf3 #MXN
|
||||
smartadserver.com, 4247, RESELLER, 060d053dcf45cbf3 #CAD
|
||||
smartadserver.com, 4228, RESELLER, 060d053dcf45cbf3 #USD_CTV
|
||||
pubmatic.com, 156439, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 154037, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 16114, RESELLER, 0bfd66d529a55807
|
||||
openx.com, 537149888, RESELLER, 6a698e2ec38604c6
|
||||
appnexus.com, 3703, RESELLER, f5ab79cb980f11d1
|
||||
loopme.com, 5679, RESELLER, 6c8d5f95897a5a3b
|
||||
xad.com, 958, RESELLER, 81cbf0a75a5e0e9a
|
||||
video.unrulymedia.com, 2564526802, RESELLER
|
||||
smaato.com, 1100044045, RESELLER, 07bcf65f187117b4
|
||||
pubnative.net, 1006576, RESELLER, d641df8625486a7b
|
||||
verve.com, 15503, RESELLER, 0c8f5958fc2d6270
|
||||
adyoulike.com, b4bf4fdd9b0b915f746f6747ff432bde, RESELLER, 4ad745ead2958bf7
|
||||
axonix.com, 57264, RESELLER
|
||||
admanmedia.com, 43, RESELLER
|
||||
sharethrough.com, OAW69Fon, RESELLER, d53b998a7bd4ecd2
|
||||
contextweb.com, 560288, RESELLER, 89ff185a4c4e857c
|
||||
|
||||
#nobid
|
||||
|
||||
nobid.io, 22931676975, DIRECT
|
||||
xandr.com, 11429, RESELLER, f5ab79cb980f11d1
|
||||
sharethrough.com, aRE1degH, RESELLER, d53b998a7bd4ecd2
|
||||
sonobi.com, 7ad1b9f952, RESELLER, d1a215d9eb5aee9e
|
||||
sharethrough.com, UvcAx8IL, RESELLER, d53b998a7bd4ecd2
|
||||
amxrtb.com, 105199579, RESELLER
|
||||
yahoo.com,49648,RESELLER
|
||||
rubiconproject.com, 24434, RESELLER, 0bfd66d529a55807
|
||||
minutemedia.com, 01gerz67grgj, RESELLER
|
||||
pubmatic.com, 161683, RESELLER, 5d62403b186f2ace
|
||||
appnexus.com, 8381, RESELLER, f5ab79cb980f11d1
|
||||
triplelift.com, 6030, RESELLER, 6c33edb13117fd86
|
||||
sonobi.com, 37fbaf262c, RESELLER, d1a215d9eb5aee9e
|
||||
openx.com, 540780517, RESELLER, 6a698e2ec38604c6
|
||||
rubiconproject.com, 17598, RESELLER, 0bfd66d529a55807
|
||||
indexexchange.com, 196326, RESELLER, 50b1c356f2c5c8fc
|
||||
yahoo.com, 59407, RESELLER, e1a5b5b6e3255540
|
||||
sharethrough.com, xz7QjFBY, RESELLER, d53b998a7bd4ecd2
|
||||
inmobi.com,8f261ace12c3486ba2e0d2011cd97976,RESELLER,83e75a7ae333ca9d
|
||||
risecodes.com, 63ea59eef828de0001cf1773, RESELLER
|
||||
inmobi.com, 9e311c7a68e94888aac7fbb4272381e2, RESELLER, 83e75a7ae333ca9d
|
||||
video.unrulymedia.com, 1352466146, RESELLER
|
||||
yahoo.com, 59261, RESELLER, e1a5b5b6e3255540
|
||||
gumgum.com, 13926, RESELLER, ffdef49475d318a9
|
||||
onetag.com, 694e68b73971b58, RESELLER
|
||||
lijit.com, 273657, RESELLER, fafdf38b16bf6b2b
|
||||
sovrn.com, 273657, RESELLER, fafdf38b16bf6b2b
|
||||
mediafuse.com, 389, RESELLER
|
||||
appnexus.com, 9538, RESELLER, f5ab79cb980f11d1
|
||||
yahoo.com, 57872, RESELLER
|
||||
video.unrulymedia.com, 2997140015, RESELLER
|
||||
indexexchange.com, 182257, RESELLER, 50b1c356f2c5c8fc
|
||||
152media.info,152M374,RESELLER
|
||||
appnexus.com, 3153, RESELLER, f5ab79cb980f11d1
|
||||
#media.net_serverside_displayvideo
|
||||
media.net, 8CUV34PJ4, DIRECT
|
||||
sharethrough.com, koRtppYA, RESELLER, d53b998a7bd4ecd2
|
||||
video.unrulymedia.com, 699546687, RESELLER
|
||||
lijit.com, 264726, RESELLER, fafdf38b16bf6b2b
|
||||
onetag.com, 765b4e6bb9c8438, RESELLER
|
||||
amxrtb.com, 105199663, RESELLER
|
||||
yieldmo.com, 2954622693783052507, RESELLER
|
||||
loopme.com, 11556, RESELLER, 6c8d5f95897a5a3b
|
||||
Contextweb.com, 562963, RESELLER, 89ff185a4c4e857c
|
||||
zeta.com, 591, RESELLER
|
||||
disqus.com, 591, RESELLER
|
||||
admanmedia.com, 953, RESELLER
|
||||
smartadserver.com, 4106, RESELLER, 060d053dcf45cbf3
|
||||
imds.tv, 82302, RESELLER, ae6c32151e71f19d
|
||||
improvedigital.com, 2073, RESELLER
|
||||
betweendigital.com, 44808, RESELLER
|
||||
adyoulike.com, 53264963677efeda057eef7db2cb305f, RESELLER
|
||||
freewheel.tv,1577878,RESELLER
|
||||
freewheel.tv,1577888,RESELLER
|
||||
dxkulture.com, 9533, DIRECT, 259726033fc4df0c
|
||||
dxkulture.com, 0098, DIRECT, 259726033fc4df0c
|
||||
adswizz.com,dxkulture,DIRECT
|
||||
adswizz.com,651,DIRECT
|
||||
pubmatic.com,164751,RESELLER,5d62403b186f2ace
|
||||
rubiconproject.com,26094,DIRECT,0bfd66d529a55807
|
||||
zetaglobal.net,790,DIRECT
|
||||
ssp.disqus.com,790,DIRECT
|
||||
video.unrulymedia.com,946176315,RESELLER
|
||||
video.unrulymedia.com, 347774562, RESELLER
|
||||
rubiconproject.com, 15268, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 159277, RESELLER
|
||||
|
||||
#AdaptMX
|
||||
|
||||
amxrtb.com, 105199723, DIRECT
|
||||
appnexus.com, 12290, RESELLER
|
||||
pubmatic.com, 161527, RESELLER
|
||||
rubiconproject.com, 23844, RESELLER
|
||||
|
||||
|
||||
|
||||
# Adagio
|
||||
adagio.io, 1361, RESELLER
|
||||
# Adagio - Magnite
|
||||
rubiconproject.com, 19116, RESELLER, 0bfd66d529a55807
|
||||
# Adagio - Pubmatic
|
||||
pubmatic.com, 159110, RESELLER, 5d62403b186f2ace
|
||||
# Adagio - Improve Digital
|
||||
improvedigital.com, 1790, RESELLER
|
||||
# Adagio - Onetag
|
||||
onetag.com, 6b859b96c564fbe, RESELLER
|
||||
appnexus.com, 13099, RESELLER
|
||||
pubmatic.com, 161593, RESELLER, 5d62403b186f2ace
|
||||
# Adagio - Index Exchange
|
||||
indexexchange.com, 194558, RESELLER
|
||||
# Adagio - 33Across
|
||||
33across.com, 0015a00002oUk4aAAC, RESELLER, bbea06d9c4d2853c
|
||||
yahoo.com, 57289, RESELLER, e1a5b5b6e3255540
|
||||
appnexus.com, 10239, RESELLER, f5ab79cb980f11d1
|
||||
rubiconproject.com, 16414, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 156423, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 21642, RESELLER, 0bfd66d529a55807
|
||||
conversantmedia.com, 100141, RESELLER
|
||||
indexexchange.com, 191973, RESELLER, 50b1c356f2c5c8fc
|
||||
triplelift.com, 12503, RESELLER, 6c33edb13117fd86
|
||||
insticator.com, 4ec3ed85-2830-4174-9f7f-f545620598b9, RESELLER
|
||||
sharethrough.com, Q9IzHdvp, RESELLER, d53b998a7bd4ecd2
|
||||
admanmedia.com, 2216, RESELLER
|
||||
connectad.io, 456, RESELLER, 85ac85a30c93b3e5
|
||||
# Adagio - Equativ
|
||||
smartadserver.com, 3554, RESELLER
|
||||
# Adagio - Sovrn
|
||||
lijit.com, 367236, RESELLER, fafdf38b16bf6b2b
|
||||
# Adagio - Freewheel
|
||||
freewheel.tv, 1568036, RESELLER
|
||||
freewheel.tv, 1568041, RESELLER
|
||||
# Adagio - OpenX
|
||||
openx.com, 558899373, RESELLER, 6a698e2ec38604c6
|
||||
# Adagio - Triplelift
|
||||
triplelift.com, 13482, RESELLER, 6c33edb13117fd86
|
||||
# Adagio - E-Planning
|
||||
e-planning.net, 83c06e81531537f4, RESELLER, c1ba615865ed87b2
|
||||
pubmatic.com, 156631, RESELLER, 5d62403b186f2ace
|
||||
openx.com, 541031350, RESELLER, 6a698e2ec38604c6
|
||||
rubiconproject.com, 12186, RESELLER, 0bfd66d529a55807
|
||||
# Adagio - Nexxen
|
||||
video.unrulymedia.com, 5672421953199218469, RESELLER
|
||||
|
||||
#Freewheel
|
||||
|
||||
freewheel.tv, 1598995, RESELLER
|
||||
freewheel.tv, 1599004, RESELLER
|
||||
|
||||
|
||||
#Pgam
|
||||
|
||||
pgamssp.com, 64661fa49d522e327b0a8b84, DIRECT
|
||||
freewheel.tv, 1489202, RESELLER
|
||||
freewheel.tv, 1488706, RESELLER
|
||||
rubiconproject.com, 24852, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 162623, RESELLER, 5d62403b186f2ace
|
||||
video.unrulymedia.com, 5921144960123684292, RESELLER
|
||||
appnexus.com, 9291, RESELLER, f5ab79cb980f11d1
|
||||
|
||||
|
||||
#Sonobi
|
||||
|
||||
sonobi.com, 3ee2ca3952, RESELLER, d1a215d9eb5aee9e
|
||||
|
||||
|
||||
#Rich Audience
|
||||
|
||||
richaudience.com, kWVs0vbyki, RESELLER
|
||||
appnexus.com, 2928, DIRECT, f5ab79cb980f11d1
|
||||
smartadserver.com, 1999, RESELLER, 060d053dcf45cbf3
|
||||
|
||||
#Ozone
|
||||
|
||||
the-ozone-project.com, OZONEAIP0001, DIRECT
|
||||
appnexus.com, 9979, RESELLER, f5ab79cb980f11d1
|
||||
openx.com, 540731760, RESELLER, 6a698e2ec38604c6
|
||||
adform.com, 2657, RESELLER, 9f5210a2f0999e32
|
||||
pubmatic.com, 160557, RESELLER, 5d62403b186f2ace
|
||||
indexexchange.com, 206233, RESELLER, 50b1c356f2c5c8fc
|
||||
themediagrid.com, 1J3ZI6, DIRECT, 35d5010d7789b49d
|
||||
themediagrid.com, WF71T3, DIRECT, 35d5010d7789b49d
|
||||
|
||||
# OptiDigital
|
||||
optidigital.com,p345,RESELLER
|
||||
pubmatic.com,158939,RESELLER,5d62403b186f2ace
|
||||
rubiconproject.com,20336,RESELLER,0bfd66d529a55807
|
||||
smartadserver.com,3379,RESELLER,060d053dcf45cbf3
|
||||
criteo.com,B-060926,RESELLER,9fac4a4a87c2a44f
|
||||
themediagrid.com,3ETIX5,RESELLER,35d5010d7789b49d
|
||||
triplelift.com,8183,RESELLER,6c33edb13117fd86
|
||||
appnexus.com,12190,RESELLER,f5ab79cb980f11d1
|
||||
onetag.com,806eabb849d0326,RESELLER
|
||||
rtbhouse.com,mSu1piUSmB9TF4AQDGk4,RESELLER
|
||||
33across.com,001Pg00000HMy0YIAT,RESELLER,bbea06d9c4d2853c
|
||||
e-planning.net,a76893b96338e7e9,RESELLER,c1ba615865ed87b2
|
||||
appnexus.com,15941,RESELLER,f5ab79cb980f11d1
|
||||
video.unrulymedia.com,731539260,RESELLER
|
||||
|
||||
#Rise
|
||||
risecodes.com, 643813aab7212c00011c3f28, DIRECT
|
||||
pubmatic.com, 160295, RESELLER, 5d62403b186f2ace
|
||||
xandr.com, 14082, RESELLER
|
||||
rubiconproject.com, 23876, RESELLER, 0bfd66d529a55807
|
||||
sharethrough.com, 5926d422, RESELLER, d53b998a7bd4ecd2
|
||||
media.net, 8CUQ6928Q, RESELLER
|
||||
sonobi.com, 4a289cdd79, RESELLER, d1a215d9eb5aee9e
|
||||
video.unrulymedia.com, 335119963, RESELLER
|
||||
contextweb.com,562615,RESELLER,89ff185a4c4e857c
|
||||
onetag.com, 69f48c2160c8113, RESELLER
|
||||
33across.com, 0010b00002Xbn7QAAR, RESELLER, bbea06d9c4d2853c
|
||||
yieldmo.com, 2754490424016969782, RESELLER
|
||||
openx.com, 537140488, RESELLER, 6a698e2ec38604c6
|
||||
lijit.com, 405318, RESELLER, fafdf38b16bf6b2b
|
||||
themediagrid.com, 4DQHAP, RESELLER, 35d5010d7789b49d
|
||||
loopme.com, 11362, RESELLER, 6c8d5f95897a5a3b
|
||||
amxrtb.com, 105199691, RESELLER
|
||||
smartadserver.com, 4284, RESELLER
|
||||
adform.com, 3119, RESELLER, 9f5210a2f0999e32
|
||||
smaato.com, 1100057444, RESELLER, 07bcf65f187117b4
|
||||
adyoulike.com, 78afbc34fac571736717317117dfa247, RESELLER
|
||||
|
||||
#Block
|
||||
blockthrough.com, 5130683165442048, DIRECT
|
||||
pubmatic.com, 160377, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 23718, RESELLER, 0bfd66d529a55807
|
||||
appnexus.com, 6979, RESELLER
|
||||
lijit.com, 251666, RESELLER, fafdf38b16bf6b2b
|
||||
lijit.com, 251666-eb, RESELLER, fafdf38b16bf6b2b
|
||||
video.unrulymedia.com, 2444764291, RESELLER
|
||||
contextweb.com, 558511, RESELLER
|
||||
krushmedia.com, AJxF6R572a9M6CaTvK, RESELLER
|
||||
criteo.com, 8990, RESELLER
|
||||
smartadserver.com, 4485, RESELLER, 060d053dcf45cbf3
|
||||
smartadserver.com, 4485-OB, RESELLER, 060d053dcf45cbf3
|
||||
Contextweb.com, 562926, RESELLER, 89ff185a4c4e857c
|
||||
|
||||
# VT Amazon TAM
|
||||
|
||||
aps.amazon.com,70247b00-ff8f-4016-b3ab-8344daf96e09,DIRECT
|
||||
indexexchange.com, 193067, DIRECT, 50b1c356f2c5c8fc
|
||||
triplelift.com, 6059, DIRECT, 6c33edb13117fd86
|
||||
sharethrough.com, 31c129df, DIRECT, d53b998a7bd4ecd2
|
||||
appnexus.com, 806, DIRECT, f5ab79cb980f11d1
|
||||
risecodes.com, 5fa94677b2db6a00015b22a9, DIRECT
|
||||
minutemedia.com, 01gerz6y43ck, RESELLER
|
||||
themediagrid.com, LTW57M, DIRECT, 35d5010d7789b49d
|
||||
vidazoo.com, 655c85dc63ceeb606a0f365f, DIRECT, b6ada874b4d7d0b2
|
||||
smartadserver.com, 3490, DIRECT
|
||||
|
||||
##################################
|
||||
# AdinPlay.com ads.txt - 2025-04-16
|
||||
##################################
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg id="emoji" viewBox="0 0 72 72" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="color">
|
||||
<rect x="5" y="17" width="62" height="38" fill="#5c9e31"/>
|
||||
<rect x="6" y="18" width="18" height="18" fill="#fff" fill-rule="evenodd" stroke-width="0" paint-order="normal"/>
|
||||
<path transform="matrix(.9199 0 0 .9196 1.096 1.101)" fill="#5c9e31" fill-rule="evenodd" stroke="#5c9e31" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.087" d="m15.11 21.88 1.551 4.147 4.423 0.1933-3.465 2.756 1.183 4.266-3.692-2.443-3.692 2.443 1.183-4.266-3.465-2.756 4.423-0.1933z" paint-order="normal"/>
|
||||
</g>
|
||||
<g id="line">
|
||||
<rect x="5" y="17" width="62" height="38" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 788 B |
|
After Width: | Height: | Size: 26 KiB |
@@ -1,112 +1,314 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150px" height="75px" viewBox="0 0 150 75" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(23.529412%,23.137255%,43.137255%);fill-opacity:1;" d="M -0.0585938 -0.0585938 C 18.941406 -0.0585938 37.941406 -0.0585938 56.941406 -0.0585938 C 56.941406 1.867188 56.941406 3.789062 56.941406 5.710938 C 56.941406 7.632812 56.941406 9.558594 56.941406 11.480469 C 56.941406 13.402344 56.941406 15.328125 56.941406 17.25 C 56.941406 19.171875 56.941406 21.097656 56.941406 23.019531 C 56.941406 24.941406 56.941406 26.867188 56.941406 28.789062 C 56.941406 30.710938 56.941406 32.632812 56.941406 34.558594 C 56.941406 36.480469 56.941406 38.402344 56.941406 40.328125 C 37.941406 40.328125 18.941406 40.328125 -0.0585938 40.328125 C -0.0585938 26.867188 -0.0585938 13.402344 -0.0585938 -0.0585938 Z M -0.0585938 -0.0585938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.411767%,13.333334%,20.392157%);fill-opacity:1;" d="M 56.941406 -0.0585938 C 87.902344 -0.0585938 118.867188 -0.0585938 149.828125 -0.0585938 C 146.082031 1.871094 142.3125 3.777344 138.519531 5.652344 C 111.328125 5.710938 84.132812 5.730469 56.941406 5.710938 C 56.941406 3.789062 56.941406 1.867188 56.941406 -0.0585938 Z M 56.941406 -0.0585938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(99.607843%,99.607843%,99.607843%);fill-opacity:1;" d="M 149.828125 -0.0585938 C 149.863281 -0.0585938 149.902344 -0.0585938 149.941406 -0.0585938 C 149.941406 2.75 149.941406 5.558594 149.941406 8.367188 C 138.964844 13.796875 128.003906 19.257812 117.058594 24.75 C 116.945312 24.804688 116.832031 24.863281 116.710938 24.921875 C 127.789062 24.980469 138.867188 25 149.941406 24.980469 C 149.941406 26.632812 149.941406 28.289062 149.941406 29.941406 C 129.902344 29.921875 109.867188 29.941406 89.828125 30 C 86.785156 31.519531 83.746094 33.039062 80.710938 34.558594 C 72.789062 34.558594 64.867188 34.558594 56.941406 34.558594 C 56.941406 32.632812 56.941406 30.710938 56.941406 28.789062 C 68.710938 28.808594 80.480469 28.789062 92.25 28.730469 C 96.042969 26.816406 99.851562 24.929688 103.671875 23.078125 C 88.097656 23.019531 72.519531 23 56.941406 23.019531 C 56.941406 21.097656 56.941406 19.171875 56.941406 17.25 C 76.441406 17.269531 95.941406 17.25 115.441406 17.191406 C 119.210938 15.308594 122.980469 13.421875 126.75 11.539062 C 103.480469 11.480469 80.210938 11.460938 56.941406 11.480469 C 56.941406 9.558594 56.941406 7.632812 56.941406 5.710938 C 84.132812 5.730469 111.328125 5.710938 138.519531 5.652344 C 142.3125 3.777344 146.082031 1.871094 149.828125 -0.0585938 Z M 149.828125 -0.0585938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.078432%,97.254902%);fill-opacity:1;" d="M 5.25 3.058594 C 5.71875 3.246094 6.21875 3.363281 6.75 3.402344 C 6.367188 3.636719 6.019531 3.925781 5.710938 4.269531 C 5.921875 4.78125 6.054688 5.300781 6.117188 5.828125 C 5.722656 5.472656 5.300781 5.164062 4.847656 4.902344 C 4.394531 5.101562 3.992188 5.371094 3.632812 5.710938 C 3.609375 5.21875 3.726562 4.738281 3.980469 4.269531 C 3.617188 3.953125 3.230469 3.664062 2.828125 3.402344 C 3.328125 3.328125 3.828125 3.25 4.328125 3.171875 C 4.625 1.289062 4.929688 1.25 5.25 3.058594 Z M 5.25 3.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.470588%,97.647059%);fill-opacity:1;" d="M 14.828125 3.171875 C 15.289062 3.25 15.75 3.328125 16.210938 3.402344 C 15.792969 3.632812 15.449219 3.9375 15.171875 4.328125 C 15.355469 4.777344 15.453125 5.238281 15.460938 5.710938 C 15.109375 5.394531 14.722656 5.125 14.308594 4.902344 C 13.847656 5.113281 13.425781 5.382812 13.039062 5.710938 C 13.164062 5.183594 13.238281 4.644531 13.269531 4.097656 C 12.957031 3.839844 12.628906 3.609375 12.289062 3.402344 C 12.789062 3.328125 13.289062 3.25 13.789062 3.171875 C 13.882812 2.644531 14.054688 2.144531 14.308594 1.671875 C 14.472656 2.191406 14.644531 2.691406 14.828125 3.171875 Z M 14.828125 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 43.097656 3.171875 C 43.597656 3.25 44.097656 3.328125 44.597656 3.402344 C 44.253906 3.609375 43.929688 3.839844 43.617188 4.097656 C 43.644531 4.644531 43.722656 5.183594 43.847656 5.710938 C 43.46875 5.398438 43.0625 5.128906 42.632812 4.902344 C 42.1875 5.101562 41.78125 5.371094 41.421875 5.710938 C 41.5 5.171875 41.578125 4.632812 41.652344 4.097656 C 41.3125 3.878906 40.988281 3.648438 40.671875 3.402344 C 41.132812 3.328125 41.597656 3.25 42.058594 3.171875 C 42.214844 2.71875 42.390625 2.257812 42.578125 1.789062 C 42.851562 2.210938 43.023438 2.671875 43.097656 3.171875 Z M 43.097656 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 52.558594 3.171875 C 53.058594 3.25 53.558594 3.328125 54.058594 3.402344 C 53.65625 3.664062 53.269531 3.953125 52.902344 4.269531 C 53.136719 4.730469 53.269531 5.210938 53.308594 5.710938 C 52.921875 5.382812 52.5 5.113281 52.039062 4.902344 C 51.585938 5.164062 51.160156 5.472656 50.769531 5.828125 C 50.828125 5.300781 50.964844 4.78125 51.171875 4.269531 C 50.871094 3.925781 50.523438 3.636719 50.132812 3.402344 C 50.664062 3.363281 51.164062 3.246094 51.632812 3.058594 C 51.953125 1.25 52.261719 1.289062 52.558594 3.171875 Z M 52.558594 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 24.289062 3.171875 C 24.75 3.25 25.210938 3.328125 25.671875 3.402344 C 25.359375 3.648438 25.03125 3.878906 24.691406 4.097656 C 24.769531 4.632812 24.847656 5.171875 24.921875 5.710938 C 24.5625 5.371094 24.160156 5.101562 23.710938 4.902344 C 23.28125 5.128906 22.878906 5.398438 22.5 5.710938 C 22.578125 5.171875 22.652344 4.632812 22.730469 4.097656 C 22.417969 3.839844 22.089844 3.609375 21.75 3.402344 C 22.210938 3.328125 22.671875 3.25 23.132812 3.171875 C 23.347656 2.691406 23.539062 2.191406 23.710938 1.671875 C 23.921875 2.179688 24.113281 2.679688 24.289062 3.171875 Z M 24.289062 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 33.632812 3.171875 C 34.132812 3.25 34.632812 3.328125 35.132812 3.402344 C 34.792969 3.609375 34.46875 3.839844 34.152344 4.097656 C 34.230469 4.632812 34.308594 5.171875 34.382812 5.710938 C 34.007812 5.398438 33.601562 5.128906 33.171875 4.902344 C 32.742188 5.128906 32.339844 5.398438 31.960938 5.710938 C 32.039062 5.171875 32.117188 4.632812 32.191406 4.097656 C 31.878906 3.839844 31.550781 3.609375 31.210938 3.402344 C 31.671875 3.328125 32.132812 3.25 32.597656 3.171875 C 32.753906 2.707031 32.945312 2.246094 33.171875 1.789062 C 33.394531 2.226562 33.550781 2.6875 33.632812 3.171875 Z M 33.632812 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(68.235296%,68.235296%,76.47059%);fill-opacity:1;" d="M 4.328125 3.171875 C 3.828125 3.25 3.328125 3.328125 2.828125 3.402344 C 2.765625 3.398438 2.726562 3.359375 2.710938 3.289062 C 3.246094 3.175781 3.78125 3.136719 4.328125 3.171875 Z M 4.328125 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(70.588237%,70.588237%,78.039217%);fill-opacity:1;" d="M 5.25 3.058594 C 5.816406 3.148438 6.394531 3.207031 6.980469 3.230469 C 6.917969 3.3125 6.839844 3.371094 6.75 3.402344 C 6.21875 3.363281 5.71875 3.246094 5.25 3.058594 Z M 5.25 3.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(67.450982%,67.450982%,75.686276%);fill-opacity:1;" d="M 13.789062 3.171875 C 13.289062 3.25 12.789062 3.328125 12.289062 3.402344 C 12.199219 3.371094 12.121094 3.3125 12.058594 3.230469 C 12.632812 3.171875 13.210938 3.152344 13.789062 3.171875 Z M 13.789062 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.01961%,69.01961%,76.862746%);fill-opacity:1;" d="M 14.828125 3.171875 C 15.367188 3.152344 15.90625 3.171875 16.441406 3.230469 C 16.378906 3.3125 16.300781 3.371094 16.210938 3.402344 C 15.75 3.328125 15.289062 3.25 14.828125 3.171875 Z M 14.828125 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(67.450982%,67.058825%,75.686276%);fill-opacity:1;" d="M 23.132812 3.171875 C 22.671875 3.25 22.210938 3.328125 21.75 3.402344 C 21.660156 3.371094 21.582031 3.3125 21.519531 3.230469 C 22.054688 3.171875 22.59375 3.152344 23.132812 3.171875 Z M 23.132812 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(68.235296%,68.235296%,76.47059%);fill-opacity:1;" d="M 24.289062 3.171875 C 24.828125 3.152344 25.367188 3.171875 25.902344 3.230469 C 25.839844 3.3125 25.765625 3.371094 25.671875 3.402344 C 25.210938 3.328125 24.75 3.25 24.289062 3.171875 Z M 24.289062 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(67.843139%,67.843139%,76.078433%);fill-opacity:1;" d="M 32.597656 3.171875 C 32.132812 3.25 31.671875 3.328125 31.210938 3.402344 C 31.121094 3.371094 31.042969 3.3125 30.980469 3.230469 C 31.519531 3.171875 32.054688 3.152344 32.597656 3.171875 Z M 32.597656 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(68.627453%,68.235296%,76.47059%);fill-opacity:1;" d="M 33.632812 3.171875 C 34.210938 3.152344 34.789062 3.171875 35.367188 3.230469 C 35.300781 3.3125 35.226562 3.371094 35.132812 3.402344 C 34.632812 3.328125 34.132812 3.25 33.632812 3.171875 Z M 33.632812 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(68.627453%,68.627453%,76.862746%);fill-opacity:1;" d="M 42.058594 3.171875 C 41.597656 3.25 41.132812 3.328125 40.671875 3.402344 C 40.582031 3.371094 40.503906 3.3125 40.441406 3.230469 C 40.980469 3.171875 41.519531 3.152344 42.058594 3.171875 Z M 42.058594 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(67.843139%,67.843139%,76.078433%);fill-opacity:1;" d="M 43.097656 3.171875 C 43.675781 3.152344 44.25 3.171875 44.828125 3.230469 C 44.765625 3.3125 44.6875 3.371094 44.597656 3.402344 C 44.097656 3.328125 43.597656 3.25 43.097656 3.171875 Z M 43.097656 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(70.588237%,70.588237%,78.039217%);fill-opacity:1;" d="M 51.632812 3.058594 C 51.164062 3.246094 50.664062 3.363281 50.132812 3.402344 C 50.042969 3.371094 49.964844 3.3125 49.902344 3.230469 C 50.488281 3.207031 51.066406 3.148438 51.632812 3.058594 Z M 51.632812 3.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(68.627453%,68.627453%,76.47059%);fill-opacity:1;" d="M 52.558594 3.171875 C 53.101562 3.136719 53.640625 3.175781 54.171875 3.289062 C 54.160156 3.359375 54.121094 3.398438 54.058594 3.402344 C 53.558594 3.328125 53.058594 3.25 52.558594 3.171875 Z M 52.558594 3.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.294118%,96.470588%);fill-opacity:1;" d="M 7.558594 7.441406 C 8.058594 7.367188 8.558594 7.289062 9.058594 7.210938 C 9.152344 6.679688 9.324219 6.179688 9.578125 5.710938 C 9.769531 6.199219 9.90625 6.699219 9.980469 7.210938 C 10.558594 7.191406 11.136719 7.210938 11.710938 7.269531 C 11.234375 7.582031 10.8125 7.949219 10.441406 8.367188 C 10.625 8.816406 10.722656 9.277344 10.730469 9.75 C 10.375 9.433594 9.992188 9.164062 9.578125 8.941406 C 9.160156 9.1875 8.753906 9.457031 8.367188 9.75 C 8.34375 9.253906 8.457031 8.773438 8.710938 8.308594 C 8.339844 7.996094 7.957031 7.707031 7.558594 7.441406 Z M 7.558594 7.441406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.294118%,96.470588%);fill-opacity:1;" d="M 17.019531 7.441406 C 17.519531 7.367188 18.019531 7.289062 18.519531 7.210938 C 18.613281 6.679688 18.785156 6.179688 19.039062 5.710938 C 19.226562 6.199219 19.363281 6.699219 19.441406 7.210938 C 20.019531 7.191406 20.597656 7.210938 21.171875 7.269531 C 20.699219 7.582031 20.273438 7.949219 19.902344 8.367188 C 20.085938 8.816406 20.183594 9.277344 20.191406 9.75 C 19.824219 9.453125 19.441406 9.183594 19.039062 8.941406 C 18.578125 9.152344 18.15625 9.421875 17.769531 9.75 C 17.882812 9.21875 17.960938 8.679688 18 8.132812 C 17.6875 7.878906 17.359375 7.648438 17.019531 7.441406 Z M 17.019531 7.441406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.686275%,96.862745%);fill-opacity:1;" d="M 47.828125 7.210938 C 48.328125 7.289062 48.828125 7.367188 49.328125 7.441406 C 48.929688 7.707031 48.542969 7.996094 48.171875 8.308594 C 48.402344 8.769531 48.539062 9.25 48.578125 9.75 C 48.191406 9.421875 47.769531 9.152344 47.308594 8.941406 C 46.855469 9.203125 46.429688 9.511719 46.039062 9.867188 C 46.132812 9.367188 46.269531 8.867188 46.441406 8.367188 C 46.070312 7.949219 45.648438 7.582031 45.171875 7.269531 C 45.75 7.210938 46.324219 7.191406 46.902344 7.210938 C 46.980469 6.699219 47.113281 6.199219 47.308594 5.710938 C 47.558594 6.179688 47.734375 6.679688 47.828125 7.210938 Z M 47.828125 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.647059%);fill-opacity:1;" d="M 29.019531 7.210938 C 29.480469 7.289062 29.941406 7.367188 30.402344 7.441406 C 29.988281 7.671875 29.640625 7.976562 29.367188 8.367188 C 29.546875 8.816406 29.644531 9.277344 29.652344 9.75 C 29.289062 9.453125 28.902344 9.183594 28.5 8.941406 C 28.039062 9.152344 27.617188 9.421875 27.230469 9.75 C 27.308594 9.210938 27.382812 8.671875 27.460938 8.132812 C 27.121094 7.917969 26.792969 7.6875 26.480469 7.441406 C 26.941406 7.367188 27.402344 7.289062 27.867188 7.210938 C 28.054688 6.761719 28.246094 6.300781 28.441406 5.828125 C 28.636719 6.300781 28.828125 6.761719 29.019531 7.210938 Z M 29.019531 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.647059%);fill-opacity:1;" d="M 38.367188 7.210938 C 38.867188 7.289062 39.367188 7.367188 39.867188 7.441406 C 39.550781 7.6875 39.226562 7.917969 38.882812 8.132812 C 38.914062 8.683594 38.992188 9.222656 39.117188 9.75 C 38.730469 9.421875 38.304688 9.152344 37.847656 8.941406 C 37.441406 9.183594 37.058594 9.453125 36.691406 9.75 C 36.703125 9.277344 36.796875 8.816406 36.980469 8.367188 C 36.707031 7.976562 36.359375 7.671875 35.941406 7.441406 C 36.402344 7.367188 36.867188 7.289062 37.328125 7.210938 C 37.472656 6.742188 37.664062 6.277344 37.902344 5.828125 C 38.128906 6.265625 38.28125 6.726562 38.367188 7.210938 Z M 38.367188 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(58.431375%,58.039218%,69.01961%);fill-opacity:1;" d="M 9.058594 7.210938 C 8.558594 7.289062 8.058594 7.367188 7.558594 7.441406 C 7.464844 7.410156 7.390625 7.351562 7.328125 7.269531 C 7.902344 7.210938 8.480469 7.191406 9.058594 7.210938 Z M 9.058594 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(59.215689%,58.823532%,69.803923%);fill-opacity:1;" d="M 18.519531 7.210938 C 18.019531 7.289062 17.519531 7.367188 17.019531 7.441406 C 16.929688 7.410156 16.851562 7.351562 16.789062 7.269531 C 17.363281 7.210938 17.941406 7.191406 18.519531 7.210938 Z M 18.519531 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(58.823532%,58.431375%,69.411767%);fill-opacity:1;" d="M 27.867188 7.210938 C 27.402344 7.289062 26.941406 7.367188 26.480469 7.441406 C 26.390625 7.410156 26.3125 7.351562 26.25 7.269531 C 26.789062 7.210938 27.324219 7.191406 27.867188 7.210938 Z M 27.867188 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(59.215689%,58.823532%,69.803923%);fill-opacity:1;" d="M 29.019531 7.210938 C 29.558594 7.191406 30.097656 7.210938 30.632812 7.269531 C 30.570312 7.351562 30.496094 7.410156 30.402344 7.441406 C 29.941406 7.367188 29.480469 7.289062 29.019531 7.210938 Z M 29.019531 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(59.607846%,59.215689%,70.19608%);fill-opacity:1;" d="M 37.328125 7.210938 C 36.867188 7.289062 36.402344 7.367188 35.941406 7.441406 C 35.851562 7.410156 35.773438 7.351562 35.710938 7.269531 C 36.25 7.210938 36.785156 7.191406 37.328125 7.210938 Z M 37.328125 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(59.607846%,59.215689%,69.803923%);fill-opacity:1;" d="M 38.367188 7.210938 C 38.945312 7.191406 39.519531 7.210938 40.097656 7.269531 C 40.035156 7.351562 39.957031 7.410156 39.867188 7.441406 C 39.367188 7.367188 38.867188 7.289062 38.367188 7.210938 Z M 38.367188 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(58.823532%,58.431375%,69.411767%);fill-opacity:1;" d="M 47.828125 7.210938 C 48.40625 7.191406 48.980469 7.210938 49.558594 7.269531 C 49.496094 7.351562 49.417969 7.410156 49.328125 7.441406 C 48.828125 7.367188 48.328125 7.289062 47.828125 7.210938 Z M 47.828125 7.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0.392157%,14.117648%,49.019608%);fill-opacity:1;" d="M 149.941406 8.367188 C 149.941406 13.867188 149.941406 19.367188 149.941406 24.867188 C 138.960938 24.902344 128 24.867188 117.058594 24.75 C 128.003906 19.257812 138.964844 13.796875 149.941406 8.367188 Z M 149.941406 8.367188 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 5.367188 11.25 C 5.867188 11.328125 6.367188 11.402344 6.867188 11.480469 C 6.410156 11.726562 6.023438 12.054688 5.710938 12.460938 C 5.898438 12.941406 6.03125 13.421875 6.117188 13.902344 C 5.722656 13.550781 5.300781 13.242188 4.847656 12.980469 C 4.429688 13.226562 4.023438 13.496094 3.632812 13.789062 C 3.613281 13.292969 3.726562 12.8125 3.980469 12.347656 C 3.609375 12.03125 3.226562 11.746094 2.828125 11.480469 C 3.328125 11.402344 3.828125 11.328125 4.328125 11.25 C 4.464844 10.734375 4.640625 10.234375 4.847656 9.75 C 5.011719 10.265625 5.183594 10.765625 5.367188 11.25 Z M 5.367188 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 12.289062 11.480469 C 12.789062 11.402344 13.289062 11.328125 13.789062 11.25 C 13.882812 10.71875 14.054688 10.21875 14.308594 9.75 C 14.480469 10.273438 14.65625 10.792969 14.828125 11.308594 C 15.328125 11.347656 15.828125 11.382812 16.328125 11.421875 C 15.910156 11.726562 15.527344 12.050781 15.171875 12.402344 C 15.355469 12.855469 15.453125 13.316406 15.460938 13.789062 C 15.09375 13.488281 14.710938 13.222656 14.308594 12.980469 C 13.890625 13.226562 13.484375 13.496094 13.097656 13.789062 C 13.074219 13.292969 13.1875 12.8125 13.441406 12.347656 C 13.070312 12.03125 12.6875 11.746094 12.289062 11.480469 Z M 12.289062 11.480469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 43.097656 11.25 C 43.597656 11.328125 44.097656 11.402344 44.597656 11.480469 C 44.199219 11.746094 43.8125 12.03125 43.441406 12.347656 C 43.671875 12.808594 43.808594 13.289062 43.847656 13.789062 C 43.421875 13.515625 43 13.25 42.578125 12.980469 C 42.175781 13.222656 41.789062 13.488281 41.421875 13.789062 C 41.433594 13.316406 41.527344 12.855469 41.710938 12.402344 C 41.402344 11.996094 41.015625 11.671875 40.558594 11.421875 C 41.058594 11.382812 41.558594 11.347656 42.058594 11.308594 C 42.207031 10.820312 42.378906 10.339844 42.578125 9.867188 C 42.851562 10.285156 43.023438 10.75 43.097656 11.25 Z M 43.097656 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 52.558594 11.25 C 53.058594 11.328125 53.558594 11.402344 54.058594 11.480469 C 53.660156 11.746094 53.273438 12.03125 52.902344 12.347656 C 53.15625 12.8125 53.273438 13.292969 53.25 13.789062 C 52.859375 13.496094 52.457031 13.226562 52.039062 12.980469 C 51.585938 13.242188 51.160156 13.550781 50.769531 13.902344 C 50.863281 13.40625 51 12.90625 51.171875 12.402344 C 50.835938 12.042969 50.453125 11.734375 50.019531 11.480469 C 50.519531 11.402344 51.019531 11.328125 51.519531 11.25 C 51.699219 10.765625 51.871094 10.265625 52.039062 9.75 C 52.246094 10.234375 52.417969 10.734375 52.558594 11.25 Z M 52.558594 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.470588%,97.647059%);fill-opacity:1;" d="M 21.75 11.480469 C 22.25 11.402344 22.75 11.328125 23.25 11.25 C 23.335938 10.765625 23.488281 10.304688 23.710938 9.867188 C 23.914062 10.34375 24.109375 10.824219 24.289062 11.308594 C 24.789062 11.347656 25.289062 11.382812 25.789062 11.421875 C 25.332031 11.671875 24.945312 11.996094 24.632812 12.402344 C 24.816406 12.855469 24.914062 13.316406 24.921875 13.789062 C 24.550781 13.476562 24.144531 13.207031 23.710938 12.980469 C 23.328125 13.25 22.941406 13.519531 22.558594 13.789062 C 22.519531 13.730469 22.480469 13.671875 22.441406 13.617188 C 22.585938 13.21875 22.699219 12.816406 22.789062 12.402344 C 22.511719 12.015625 22.167969 11.707031 21.75 11.480469 Z M 21.75 11.480469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 33.058594 9.867188 C 33.402344 10.285156 33.59375 10.785156 33.632812 11.367188 C 34.175781 11.347656 34.710938 11.367188 35.25 11.421875 C 34.792969 11.671875 34.40625 11.996094 34.097656 12.402344 C 34.230469 12.867188 34.328125 13.328125 34.382812 13.789062 C 34.011719 13.476562 33.605469 13.207031 33.171875 12.980469 C 32.738281 13.207031 32.335938 13.476562 31.960938 13.789062 C 31.96875 13.316406 32.066406 12.855469 32.25 12.402344 C 31.9375 11.996094 31.554688 11.671875 31.097656 11.421875 C 31.597656 11.382812 32.097656 11.347656 32.597656 11.308594 C 32.808594 10.847656 32.960938 10.363281 33.058594 9.867188 Z M 33.058594 9.867188 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(54.11765%,53.725493%,65.882355%);fill-opacity:1;" d="M 4.328125 11.25 C 3.828125 11.328125 3.328125 11.402344 2.828125 11.480469 C 2.734375 11.449219 2.660156 11.390625 2.597656 11.308594 C 3.171875 11.25 3.75 11.230469 4.328125 11.25 Z M 4.328125 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(52.941179%,52.549022%,65.098041%);fill-opacity:1;" d="M 5.367188 11.25 C 5.910156 11.210938 6.449219 11.25 6.980469 11.367188 C 6.964844 11.433594 6.929688 11.472656 6.867188 11.480469 C 6.367188 11.402344 5.867188 11.328125 5.367188 11.25 Z M 5.367188 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(54.901963%,54.509807%,66.274512%);fill-opacity:1;" d="M 13.789062 11.25 C 13.289062 11.328125 12.789062 11.402344 12.289062 11.480469 C 12.199219 11.449219 12.121094 11.390625 12.058594 11.308594 C 12.632812 11.25 13.210938 11.230469 13.789062 11.25 Z M 13.789062 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(55.686277%,55.29412%,67.058825%);fill-opacity:1;" d="M 23.25 11.25 C 22.75 11.328125 22.25 11.402344 21.75 11.480469 C 21.660156 11.449219 21.582031 11.390625 21.519531 11.308594 C 22.09375 11.25 22.671875 11.230469 23.25 11.25 Z M 23.25 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(55.29412%,54.901963%,66.666669%);fill-opacity:1;" d="M 43.097656 11.25 C 43.675781 11.230469 44.25 11.25 44.828125 11.308594 C 44.765625 11.390625 44.6875 11.449219 44.597656 11.480469 C 44.097656 11.402344 43.597656 11.328125 43.097656 11.25 Z M 43.097656 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(52.941179%,52.549022%,65.098041%);fill-opacity:1;" d="M 51.519531 11.25 C 51.019531 11.328125 50.519531 11.402344 50.019531 11.480469 C 49.957031 11.472656 49.917969 11.433594 49.902344 11.367188 C 50.4375 11.25 50.976562 11.210938 51.519531 11.25 Z M 51.519531 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(54.509807%,54.11765%,65.882355%);fill-opacity:1;" d="M 52.558594 11.25 C 53.136719 11.230469 53.710938 11.25 54.289062 11.308594 C 54.226562 11.390625 54.148438 11.449219 54.058594 11.480469 C 53.558594 11.402344 53.058594 11.328125 52.558594 11.25 Z M 52.558594 11.25 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.411767%,13.333334%,20.392157%);fill-opacity:1;" d="M 56.941406 11.480469 C 80.210938 11.460938 103.480469 11.480469 126.75 11.539062 C 122.980469 13.421875 119.210938 15.308594 115.441406 17.191406 C 95.941406 17.25 76.441406 17.269531 56.941406 17.25 C 56.941406 15.328125 56.941406 13.402344 56.941406 11.480469 Z M 56.941406 11.480469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 10.097656 15.289062 C 10.597656 15.367188 11.097656 15.441406 11.597656 15.519531 C 11.140625 15.765625 10.753906 16.09375 10.441406 16.5 C 10.628906 16.980469 10.761719 17.460938 10.847656 17.941406 C 10.453125 17.589844 10.03125 17.28125 9.578125 17.019531 C 9.105469 17.285156 8.664062 17.589844 8.25 17.941406 C 8.308594 17.433594 8.464844 16.914062 8.710938 16.382812 C 8.308594 16.046875 7.886719 15.742188 7.441406 15.460938 C 7.980469 15.402344 8.519531 15.382812 9.058594 15.402344 C 9.160156 14.839844 9.332031 14.300781 9.578125 13.789062 C 9.742188 14.304688 9.914062 14.804688 10.097656 15.289062 Z M 10.097656 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 45.289062 15.519531 C 45.789062 15.441406 46.289062 15.367188 46.789062 15.289062 C 46.96875 14.804688 47.140625 14.304688 47.308594 13.789062 C 47.550781 14.300781 47.722656 14.839844 47.828125 15.402344 C 48.367188 15.382812 48.90625 15.402344 49.441406 15.460938 C 49 15.742188 48.574219 16.046875 48.171875 16.382812 C 48.425781 16.851562 48.542969 17.332031 48.519531 17.828125 C 48.132812 17.558594 47.75 17.289062 47.367188 17.019531 C 46.875 17.257812 46.433594 17.566406 46.039062 17.941406 C 46.121094 17.460938 46.257812 16.980469 46.441406 16.5 C 46.128906 16.09375 45.746094 15.765625 45.289062 15.519531 Z M 45.289062 15.519531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 18.867188 13.902344 C 18.980469 13.898438 19.058594 13.957031 19.097656 14.078125 C 19.226562 14.511719 19.382812 14.933594 19.558594 15.347656 C 20.058594 15.382812 20.558594 15.421875 21.058594 15.460938 C 20.691406 15.75 20.328125 16.039062 19.960938 16.328125 C 20.0625 16.820312 20.140625 17.320312 20.191406 17.828125 C 19.816406 17.515625 19.414062 17.246094 18.980469 17.019531 C 18.597656 17.289062 18.210938 17.558594 17.828125 17.828125 C 17.789062 17.769531 17.75 17.710938 17.710938 17.652344 C 17.953125 17.1875 18.03125 16.707031 17.941406 16.210938 C 17.597656 15.960938 17.25 15.710938 16.902344 15.460938 C 17.441406 15.402344 17.980469 15.382812 18.519531 15.402344 C 18.609375 14.898438 18.726562 14.398438 18.867188 13.902344 Z M 18.867188 13.902344 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 28.902344 15.289062 C 29.441406 15.367188 29.980469 15.441406 30.519531 15.519531 C 30.085938 15.773438 29.703125 16.082031 29.367188 16.441406 C 29.535156 16.894531 29.632812 17.359375 29.652344 17.828125 C 29.238281 17.570312 28.835938 17.300781 28.441406 17.019531 C 28.058594 17.289062 27.671875 17.558594 27.289062 17.828125 C 27.25 17.769531 27.210938 17.710938 27.171875 17.652344 C 27.28125 17.246094 27.394531 16.84375 27.519531 16.441406 C 27.222656 16.023438 26.839844 15.71875 26.367188 15.519531 C 26.902344 15.441406 27.441406 15.367188 27.980469 15.289062 C 28.289062 13.441406 28.597656 13.441406 28.902344 15.289062 Z M 28.902344 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.647059%);fill-opacity:1;" d="M 38.367188 15.289062 C 38.902344 15.367188 39.441406 15.441406 39.980469 15.519531 C 39.476562 15.710938 39.09375 16.039062 38.828125 16.5 C 38.917969 16.890625 39.035156 17.277344 39.171875 17.652344 C 39.132812 17.710938 39.097656 17.769531 39.058594 17.828125 C 38.671875 17.558594 38.289062 17.289062 37.902344 17.019531 C 37.511719 17.300781 37.105469 17.570312 36.691406 17.828125 C 36.703125 17.355469 36.796875 16.894531 36.980469 16.441406 C 36.625 16.089844 36.242188 15.761719 35.828125 15.460938 C 36.328125 15.421875 36.828125 15.382812 37.328125 15.347656 C 37.507812 14.863281 37.699219 14.378906 37.902344 13.902344 C 38.128906 14.34375 38.28125 14.804688 38.367188 15.289062 Z M 38.367188 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(43.921569%,43.529412%,58.431375%);fill-opacity:1;" d="M 10.097656 15.289062 C 10.640625 15.25 11.179688 15.289062 11.710938 15.402344 C 11.695312 15.472656 11.660156 15.511719 11.597656 15.519531 C 11.097656 15.441406 10.597656 15.367188 10.097656 15.289062 Z M 10.097656 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(44.313726%,43.921569%,58.823532%);fill-opacity:1;" d="M 27.980469 15.289062 C 27.441406 15.367188 26.902344 15.441406 26.367188 15.519531 C 26.300781 15.511719 26.265625 15.472656 26.25 15.402344 C 26.820312 15.289062 27.398438 15.25 27.980469 15.289062 Z M 27.980469 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(44.313726%,43.921569%,58.823532%);fill-opacity:1;" d="M 28.902344 15.289062 C 29.484375 15.25 30.0625 15.289062 30.632812 15.402344 C 30.621094 15.472656 30.582031 15.511719 30.519531 15.519531 C 29.980469 15.441406 29.441406 15.367188 28.902344 15.289062 Z M 28.902344 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(43.529412%,43.137255%,58.039218%);fill-opacity:1;" d="M 38.367188 15.289062 C 38.949219 15.25 39.523438 15.289062 40.097656 15.402344 C 40.082031 15.472656 40.042969 15.511719 39.980469 15.519531 C 39.441406 15.441406 38.902344 15.367188 38.367188 15.289062 Z M 38.367188 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(43.529412%,43.137255%,58.039218%);fill-opacity:1;" d="M 46.789062 15.289062 C 46.289062 15.367188 45.789062 15.441406 45.289062 15.519531 C 45.226562 15.511719 45.1875 15.472656 45.171875 15.402344 C 45.707031 15.289062 46.246094 15.25 46.789062 15.289062 Z M 46.789062 15.289062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.647059%);fill-opacity:1;" d="M 4.789062 17.941406 C 5.035156 18.390625 5.226562 18.871094 5.367188 19.382812 C 5.867188 19.421875 6.367188 19.460938 6.867188 19.5 C 6.4375 19.8125 6.054688 20.15625 5.710938 20.539062 C 5.898438 21.015625 6.03125 21.496094 6.117188 21.980469 C 5.722656 21.625 5.300781 21.320312 4.847656 21.058594 C 4.410156 21.300781 4.007812 21.589844 3.632812 21.921875 C 3.558594 22 3.480469 22 3.402344 21.921875 C 3.597656 21.421875 3.789062 20.921875 3.980469 20.421875 C 3.578125 20.085938 3.15625 19.78125 2.710938 19.5 C 3.25 19.441406 3.785156 19.421875 4.328125 19.441406 C 4.433594 18.925781 4.589844 18.425781 4.789062 17.941406 Z M 4.789062 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.470588%,97.647059%);fill-opacity:1;" d="M 51.980469 17.941406 C 52.28125 18.386719 52.476562 18.886719 52.558594 19.441406 C 53.097656 19.421875 53.636719 19.441406 54.171875 19.5 C 53.730469 19.78125 53.304688 20.085938 52.902344 20.421875 C 53.15625 20.890625 53.273438 21.371094 53.25 21.867188 C 52.867188 21.597656 52.480469 21.328125 52.097656 21.058594 C 51.644531 21.351562 51.203125 21.660156 50.769531 21.980469 C 50.851562 21.496094 50.988281 21.015625 51.171875 20.539062 C 50.84375 20.140625 50.460938 19.792969 50.019531 19.5 C 50.519531 19.460938 51.019531 19.421875 51.519531 19.382812 C 51.683594 18.910156 51.839844 18.425781 51.980469 17.941406 Z M 51.980469 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 14.132812 17.941406 C 14.277344 17.953125 14.375 18.027344 14.421875 18.171875 C 14.511719 18.59375 14.648438 19 14.828125 19.382812 C 15.328125 19.421875 15.828125 19.460938 16.328125 19.5 C 15.886719 19.792969 15.503906 20.140625 15.171875 20.539062 C 15.359375 21.015625 15.492188 21.496094 15.578125 21.980469 C 15.144531 21.660156 14.703125 21.351562 14.25 21.058594 C 13.828125 21.367188 13.402344 21.671875 12.980469 21.980469 C 13.027344 21.488281 13.183594 20.988281 13.441406 20.480469 C 13.066406 20.097656 12.640625 19.773438 12.171875 19.5 C 12.710938 19.441406 13.25 19.421875 13.789062 19.441406 C 13.921875 18.945312 14.039062 18.445312 14.132812 17.941406 Z M 14.132812 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 23.597656 17.941406 C 23.941406 18.359375 24.132812 18.859375 24.171875 19.441406 C 24.714844 19.421875 25.25 19.441406 25.789062 19.5 C 25.421875 19.789062 25.058594 20.078125 24.691406 20.367188 C 24.738281 20.808594 24.832031 21.253906 24.980469 21.691406 C 24.941406 21.75 24.902344 21.808594 24.867188 21.867188 C 24.480469 21.597656 24.097656 21.328125 23.710938 21.058594 C 23.269531 21.335938 22.84375 21.644531 22.441406 21.980469 C 22.402344 21.960938 22.367188 21.941406 22.328125 21.921875 C 22.628906 21.390625 22.742188 20.832031 22.671875 20.25 C 22.3125 20.023438 21.964844 19.773438 21.632812 19.5 C 22.171875 19.441406 22.710938 19.421875 23.25 19.441406 C 23.339844 18.9375 23.457031 18.4375 23.597656 17.941406 Z M 23.597656 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 33.058594 17.941406 C 33.402344 18.359375 33.59375 18.859375 33.632812 19.441406 C 34.175781 19.421875 34.710938 19.441406 35.25 19.5 C 34.882812 19.789062 34.519531 20.078125 34.152344 20.367188 C 34.152344 20.820312 34.246094 21.265625 34.441406 21.691406 C 34.402344 21.75 34.367188 21.808594 34.328125 21.867188 C 33.941406 21.597656 33.558594 21.328125 33.171875 21.058594 C 32.789062 21.328125 32.402344 21.597656 32.019531 21.867188 C 31.980469 21.789062 31.941406 21.710938 31.902344 21.632812 C 32.0625 21.21875 32.160156 20.792969 32.191406 20.367188 C 31.828125 20.078125 31.460938 19.789062 31.097656 19.5 C 31.632812 19.441406 32.171875 19.421875 32.710938 19.441406 C 32.804688 18.9375 32.917969 18.4375 33.058594 17.941406 Z M 33.058594 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 42.519531 17.941406 C 42.867188 18.367188 43.058594 18.867188 43.097656 19.441406 C 43.636719 19.421875 44.175781 19.441406 44.710938 19.5 C 44.285156 19.828125 43.859375 20.15625 43.441406 20.480469 C 43.707031 20.925781 43.824219 21.386719 43.789062 21.867188 C 43.402344 21.597656 43.019531 21.328125 42.632812 21.058594 C 42.183594 21.351562 41.738281 21.660156 41.308594 21.980469 C 41.390625 21.496094 41.527344 21.015625 41.710938 20.539062 C 41.382812 20.140625 40.996094 19.792969 40.558594 19.5 C 41.058594 19.460938 41.558594 19.421875 42.058594 19.382812 C 42.269531 18.921875 42.421875 18.441406 42.519531 17.941406 Z M 42.519531 17.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.647059%);fill-opacity:1;" d="M 9.519531 21.980469 C 9.71875 22.445312 9.914062 22.925781 10.097656 23.421875 C 10.597656 23.460938 11.097656 23.5 11.597656 23.539062 C 11.167969 23.851562 10.785156 24.195312 10.441406 24.578125 C 10.628906 25.054688 10.761719 25.535156 10.847656 26.019531 C 10.414062 25.699219 9.972656 25.390625 9.519531 25.097656 C 9.089844 25.472656 8.628906 25.761719 8.132812 25.960938 C 8.316406 25.476562 8.507812 24.996094 8.710938 24.519531 C 8.292969 24.195312 7.871094 23.867188 7.441406 23.539062 C 7.980469 23.480469 8.519531 23.460938 9.058594 23.480469 C 9.164062 22.964844 9.320312 22.464844 9.519531 21.980469 Z M 9.519531 21.980469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 18.867188 21.980469 C 19.210938 22.398438 19.402344 22.898438 19.441406 23.480469 C 19.980469 23.460938 20.519531 23.480469 21.058594 23.539062 C 20.691406 23.828125 20.328125 24.117188 19.960938 24.402344 C 19.996094 24.832031 20.089844 25.253906 20.25 25.671875 C 20.210938 25.75 20.171875 25.828125 20.132812 25.902344 C 19.75 25.632812 19.367188 25.367188 18.980469 25.097656 C 18.558594 25.402344 18.132812 25.710938 17.710938 26.019531 C 17.671875 26 17.632812 25.980469 17.597656 25.960938 C 17.851562 25.46875 17.984375 24.949219 18 24.402344 C 17.632812 24.117188 17.269531 23.828125 16.902344 23.539062 C 17.441406 23.480469 17.980469 23.460938 18.519531 23.480469 C 18.617188 22.976562 18.730469 22.476562 18.867188 21.980469 Z M 18.867188 21.980469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.470588%,97.647059%);fill-opacity:1;" d="M 28.328125 21.980469 C 28.671875 22.398438 28.863281 22.898438 28.902344 23.480469 C 29.445312 23.460938 29.980469 23.480469 30.519531 23.539062 C 30.152344 23.828125 29.789062 24.117188 29.421875 24.402344 C 29.421875 24.859375 29.515625 25.300781 29.710938 25.730469 C 29.671875 25.789062 29.632812 25.847656 29.597656 25.902344 C 29.210938 25.632812 28.828125 25.367188 28.441406 25.097656 C 28.019531 25.402344 27.597656 25.710938 27.171875 26.019531 C 27.132812 26 27.097656 25.980469 27.058594 25.960938 C 27.3125 25.46875 27.445312 24.949219 27.460938 24.402344 C 27.097656 24.117188 26.730469 23.828125 26.367188 23.539062 C 26.902344 23.480469 27.441406 23.460938 27.980469 23.480469 C 28.074219 22.976562 28.1875 22.476562 28.328125 21.980469 Z M 28.328125 21.980469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 37.789062 21.980469 C 37.902344 21.976562 37.980469 22.035156 38.019531 22.152344 C 38.179688 22.585938 38.296875 23.027344 38.367188 23.480469 C 38.90625 23.460938 39.445312 23.480469 39.980469 23.539062 C 39.617188 23.828125 39.25 24.117188 38.882812 24.402344 C 38.882812 24.859375 38.976562 25.300781 39.171875 25.730469 C 39.132812 25.789062 39.097656 25.847656 39.058594 25.902344 C 38.671875 25.632812 38.289062 25.367188 37.902344 25.097656 C 37.519531 25.367188 37.132812 25.632812 36.75 25.902344 C 36.710938 25.828125 36.671875 25.75 36.632812 25.671875 C 36.792969 25.253906 36.890625 24.832031 36.921875 24.402344 C 36.558594 24.117188 36.191406 23.828125 35.828125 23.539062 C 36.363281 23.480469 36.902344 23.460938 37.441406 23.480469 C 37.535156 22.976562 37.648438 22.476562 37.789062 21.980469 Z M 37.789062 21.980469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 47.25 21.980469 C 47.550781 22.425781 47.746094 22.925781 47.828125 23.480469 C 48.367188 23.460938 48.90625 23.480469 49.441406 23.539062 C 49.015625 23.867188 48.589844 24.195312 48.171875 24.519531 C 48.4375 24.964844 48.554688 25.425781 48.519531 25.902344 C 48.132812 25.632812 47.75 25.367188 47.367188 25.097656 C 46.914062 25.390625 46.46875 25.699219 46.039062 26.019531 C 46.121094 25.535156 46.257812 25.054688 46.441406 24.578125 C 46.097656 24.195312 45.714844 23.851562 45.289062 23.539062 C 45.789062 23.5 46.289062 23.460938 46.789062 23.421875 C 47 22.960938 47.152344 22.480469 47.25 21.980469 Z M 47.25 21.980469 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.411767%,13.333334%,20.392157%);fill-opacity:1;" d="M 56.941406 23.019531 C 72.519531 23 88.097656 23.019531 103.671875 23.078125 C 99.851562 24.929688 96.042969 26.816406 92.25 28.730469 C 80.480469 28.789062 68.710938 28.808594 56.941406 28.789062 C 56.941406 26.867188 56.941406 24.941406 56.941406 23.019531 Z M 56.941406 23.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(33.333334%,42.745098%,65.882355%);fill-opacity:1;" d="M 117.058594 24.75 C 128 24.867188 138.960938 24.902344 149.941406 24.867188 C 149.941406 24.902344 149.941406 24.941406 149.941406 24.980469 C 138.867188 25 127.789062 24.980469 116.710938 24.921875 C 116.832031 24.863281 116.945312 24.804688 117.058594 24.75 Z M 117.058594 24.75 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 4.789062 26.019531 C 5.023438 26.472656 5.214844 26.953125 5.367188 27.460938 C 5.902344 27.5 6.441406 27.539062 6.980469 27.578125 C 6.566406 27.851562 6.164062 28.140625 5.769531 28.441406 C 5.816406 28.957031 5.953125 29.457031 6.171875 29.941406 C 6.132812 29.980469 6.097656 30.019531 6.058594 30.058594 C 5.65625 29.722656 5.230469 29.414062 4.789062 29.132812 C 4.367188 29.421875 3.964844 29.726562 3.578125 30.058594 C 3.621094 29.542969 3.753906 29.042969 3.980469 28.558594 C 3.5625 28.230469 3.140625 27.90625 2.710938 27.578125 C 3.25 27.519531 3.785156 27.5 4.328125 27.519531 C 4.433594 27.003906 4.589844 26.503906 4.789062 26.019531 Z M 4.789062 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 14.132812 26.019531 C 14.25 26.015625 14.328125 26.074219 14.367188 26.191406 C 14.496094 26.625 14.652344 27.050781 14.828125 27.460938 C 15.367188 27.5 15.902344 27.539062 16.441406 27.578125 C 16.007812 27.820312 15.601562 28.109375 15.230469 28.441406 C 15.261719 28.871094 15.359375 29.292969 15.519531 29.710938 C 15.480469 29.789062 15.441406 29.867188 15.402344 29.941406 C 15.019531 29.671875 14.632812 29.402344 14.25 29.132812 C 13.828125 29.421875 13.425781 29.726562 13.039062 30.058594 C 13.039062 29.53125 13.175781 29.03125 13.441406 28.558594 C 13.019531 28.230469 12.597656 27.902344 12.171875 27.578125 C 12.710938 27.519531 13.25 27.5 13.789062 27.519531 C 13.925781 27.023438 14.042969 26.523438 14.132812 26.019531 Z M 14.132812 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 23.597656 26.019531 C 23.941406 26.4375 24.132812 26.9375 24.171875 27.519531 C 24.75 27.5 25.328125 27.519531 25.902344 27.578125 C 25.46875 27.820312 25.0625 28.109375 24.691406 28.441406 C 24.707031 28.988281 24.839844 29.507812 25.097656 30 C 25.058594 30.019531 25.019531 30.039062 24.980469 30.058594 C 24.558594 29.75 24.132812 29.441406 23.710938 29.132812 C 23.3125 29.402344 22.925781 29.6875 22.558594 30 C 22.480469 30.078125 22.402344 30.078125 22.328125 30 C 22.582031 29.507812 22.714844 28.988281 22.730469 28.441406 C 22.367188 28.152344 22 27.867188 21.632812 27.578125 C 22.171875 27.519531 22.710938 27.5 23.25 27.519531 C 23.339844 27.015625 23.457031 26.515625 23.597656 26.019531 Z M 23.597656 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 33.058594 26.019531 C 33.402344 26.4375 33.59375 26.9375 33.632812 27.519531 C 34.175781 27.5 34.710938 27.519531 35.25 27.578125 C 34.882812 27.867188 34.519531 28.152344 34.152344 28.441406 C 34.152344 28.898438 34.246094 29.339844 34.441406 29.769531 C 34.402344 29.828125 34.367188 29.882812 34.328125 29.941406 C 33.941406 29.671875 33.558594 29.402344 33.171875 29.132812 C 32.75 29.441406 32.328125 29.75 31.902344 30.058594 C 31.867188 30.039062 31.828125 30.019531 31.789062 30 C 32.042969 29.507812 32.179688 28.988281 32.191406 28.441406 C 31.828125 28.152344 31.460938 27.867188 31.097656 27.578125 C 31.632812 27.519531 32.171875 27.5 32.710938 27.519531 C 32.804688 27.015625 32.917969 26.515625 33.058594 26.019531 Z M 33.058594 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 42.519531 26.019531 C 42.820312 26.460938 43.015625 26.960938 43.097656 27.519531 C 43.636719 27.5 44.175781 27.519531 44.710938 27.578125 C 44.289062 27.902344 43.867188 28.230469 43.441406 28.558594 C 43.644531 29.035156 43.839844 29.515625 44.019531 30 C 43.523438 29.800781 43.0625 29.511719 42.632812 29.132812 C 42.234375 29.402344 41.847656 29.6875 41.480469 30 C 41.386719 30.078125 41.308594 30.058594 41.25 29.941406 C 41.46875 29.457031 41.605469 28.957031 41.652344 28.441406 C 41.28125 28.109375 40.878906 27.820312 40.441406 27.578125 C 40.980469 27.539062 41.519531 27.5 42.058594 27.460938 C 42.269531 27 42.421875 26.519531 42.519531 26.019531 Z M 42.519531 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.862745%,96.862745%,97.647059%);fill-opacity:1;" d="M 51.980469 26.019531 C 52.28125 26.460938 52.476562 26.960938 52.558594 27.519531 C 53.097656 27.5 53.636719 27.519531 54.171875 27.578125 C 53.75 27.902344 53.328125 28.230469 52.902344 28.558594 C 53.125 29.042969 53.257812 29.542969 53.308594 30.058594 C 52.921875 29.726562 52.515625 29.421875 52.097656 29.132812 C 51.691406 29.394531 51.304688 29.683594 50.941406 30 C 50.847656 30.078125 50.769531 30.058594 50.710938 29.941406 C 50.933594 29.457031 51.066406 28.957031 51.117188 28.441406 C 50.742188 28.109375 50.339844 27.820312 49.902344 27.578125 C 50.441406 27.539062 50.980469 27.5 51.519531 27.460938 C 51.699219 26.988281 51.851562 26.507812 51.980469 26.019531 Z M 51.980469 26.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(81.176472%,7.843138%,16.862746%);fill-opacity:1;" d="M 149.941406 29.941406 C 149.941406 34.941406 149.941406 39.941406 149.941406 44.941406 C 127.441406 44.941406 104.941406 44.941406 82.441406 44.941406 C 82.441406 54.941406 82.441406 64.941406 82.441406 74.941406 C 77.441406 74.941406 72.441406 74.941406 67.441406 74.941406 C 67.441406 64.941406 67.441406 54.941406 67.441406 44.941406 C 64.941406 44.960938 62.441406 44.941406 59.941406 44.882812 C 62.929688 43.371094 65.929688 41.890625 68.941406 40.441406 C 72.902344 38.539062 76.824219 36.578125 80.710938 34.558594 C 83.746094 33.039062 86.785156 31.519531 89.828125 30 C 109.867188 29.941406 129.902344 29.921875 149.941406 29.941406 Z M 149.941406 29.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,96.862745%);fill-opacity:1;" d="M 9.519531 30.058594 C 9.71875 30.523438 9.914062 31.003906 10.097656 31.5 C 10.632812 31.539062 11.171875 31.578125 11.710938 31.617188 C 11.296875 31.890625 10.894531 32.179688 10.5 32.480469 C 10.546875 32.996094 10.683594 33.496094 10.902344 33.980469 C 10.867188 34.019531 10.828125 34.058594 10.789062 34.097656 C 10.367188 33.789062 9.941406 33.480469 9.519531 33.171875 C 9.097656 33.457031 8.695312 33.765625 8.308594 34.097656 C 8.351562 33.578125 8.484375 33.078125 8.710938 32.597656 C 8.289062 32.269531 7.867188 31.941406 7.441406 31.617188 C 7.980469 31.558594 8.519531 31.539062 9.058594 31.558594 C 9.164062 31.042969 9.320312 30.542969 9.519531 30.058594 Z M 9.519531 30.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,97.254902%);fill-opacity:1;" d="M 18.867188 30.058594 C 19.210938 30.476562 19.402344 30.976562 19.441406 31.558594 C 20.019531 31.539062 20.597656 31.558594 21.171875 31.617188 C 20.757812 31.890625 20.355469 32.179688 19.960938 32.480469 C 19.976562 33.023438 20.113281 33.542969 20.367188 34.039062 C 20.328125 34.058594 20.289062 34.078125 20.25 34.097656 C 19.828125 33.789062 19.402344 33.480469 18.980469 33.171875 C 18.558594 33.457031 18.15625 33.765625 17.769531 34.097656 C 17.773438 33.570312 17.90625 33.066406 18.171875 32.597656 C 17.734375 32.292969 17.308594 31.964844 16.902344 31.617188 C 17.441406 31.558594 17.980469 31.539062 18.519531 31.558594 C 18.660156 31.0625 18.773438 30.5625 18.867188 30.058594 Z M 18.867188 30.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,96.862745%);fill-opacity:1;" d="M 28.328125 30.058594 C 28.671875 30.476562 28.863281 30.976562 28.902344 31.558594 C 29.445312 31.539062 29.980469 31.558594 30.519531 31.617188 C 30.152344 31.902344 29.789062 32.191406 29.421875 32.480469 C 29.4375 33.023438 29.570312 33.542969 29.828125 34.039062 C 29.789062 34.058594 29.75 34.078125 29.710938 34.097656 C 29.289062 33.789062 28.867188 33.480469 28.441406 33.171875 C 28.011719 33.550781 27.550781 33.839844 27.058594 34.039062 C 27.3125 33.542969 27.445312 33.023438 27.460938 32.480469 C 27.097656 32.191406 26.730469 31.902344 26.367188 31.617188 C 26.902344 31.558594 27.441406 31.539062 27.980469 31.558594 C 28.074219 31.050781 28.1875 30.550781 28.328125 30.058594 Z M 28.328125 30.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.470588%,96.470588%,97.254902%);fill-opacity:1;" d="M 37.789062 30.171875 C 38.113281 30.566406 38.304688 31.027344 38.367188 31.558594 C 38.90625 31.539062 39.445312 31.558594 39.980469 31.617188 C 39.617188 31.902344 39.25 32.191406 38.882812 32.480469 C 38.960938 33.019531 39.039062 33.558594 39.117188 34.097656 C 38.726562 33.765625 38.324219 33.457031 37.902344 33.171875 C 37.503906 33.4375 37.117188 33.726562 36.75 34.039062 C 36.671875 34.117188 36.597656 34.117188 36.519531 34.039062 C 36.773438 33.542969 36.910156 33.023438 36.921875 32.480469 C 36.550781 32.148438 36.148438 31.859375 35.710938 31.617188 C 36.289062 31.558594 36.863281 31.539062 37.441406 31.558594 C 37.511719 31.085938 37.625 30.621094 37.789062 30.171875 Z M 37.789062 30.171875 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,96.862745%);fill-opacity:1;" d="M 47.25 30.058594 C 47.550781 30.5 47.746094 31 47.828125 31.558594 C 48.367188 31.539062 48.90625 31.558594 49.441406 31.617188 C 49.035156 31.964844 48.613281 32.292969 48.171875 32.597656 C 48.4375 33.070312 48.570312 33.570312 48.578125 34.097656 C 48.191406 33.765625 47.785156 33.457031 47.367188 33.171875 C 46.964844 33.4375 46.578125 33.726562 46.210938 34.039062 C 46.117188 34.117188 46.039062 34.097656 45.980469 33.980469 C 46.199219 33.496094 46.335938 32.996094 46.382812 32.480469 C 45.992188 32.179688 45.585938 31.890625 45.171875 31.617188 C 45.710938 31.578125 46.25 31.539062 46.789062 31.5 C 47 31.039062 47.152344 30.558594 47.25 30.058594 Z M 47.25 30.058594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,95.686275%,96.862745%);fill-opacity:1;" d="M 4.789062 34.097656 C 4.988281 34.5625 5.183594 35.042969 5.367188 35.539062 C 5.902344 35.578125 6.441406 35.617188 6.980469 35.652344 C 6.566406 35.929688 6.164062 36.214844 5.769531 36.519531 C 5.816406 37.03125 5.953125 37.53125 6.171875 38.019531 C 6.132812 38.058594 6.097656 38.097656 6.058594 38.132812 C 5.636719 37.847656 5.234375 37.542969 4.847656 37.210938 C 4.421875 37.519531 4 37.828125 3.578125 38.132812 C 3.613281 37.636719 3.75 37.15625 3.980469 36.691406 C 3.558594 36.347656 3.136719 36.003906 2.710938 35.652344 C 3.25 35.597656 3.785156 35.578125 4.328125 35.597656 C 4.433594 35.082031 4.589844 34.582031 4.789062 34.097656 Z M 4.789062 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,97.254902%);fill-opacity:1;" d="M 14.25 34.097656 C 14.492188 34.558594 14.648438 35.058594 14.710938 35.597656 C 15.289062 35.578125 15.867188 35.597656 16.441406 35.652344 C 16.027344 35.929688 15.625 36.214844 15.230469 36.519531 C 15.246094 37.0625 15.382812 37.582031 15.632812 38.078125 C 15.597656 38.097656 15.558594 38.117188 15.519531 38.132812 C 15.097656 37.828125 14.671875 37.519531 14.25 37.210938 C 13.828125 37.496094 13.425781 37.804688 13.039062 38.132812 C 13.046875 37.609375 13.179688 37.109375 13.441406 36.632812 C 13.003906 36.328125 12.578125 36.003906 12.171875 35.652344 C 12.710938 35.597656 13.25 35.578125 13.789062 35.597656 C 13.894531 35.082031 14.050781 34.582031 14.25 34.097656 Z M 14.25 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.686275%,96.862745%);fill-opacity:1;" d="M 23.597656 34.097656 C 23.941406 34.515625 24.132812 35.015625 24.171875 35.597656 C 24.75 35.578125 25.328125 35.597656 25.902344 35.652344 C 25.488281 35.929688 25.085938 36.214844 24.691406 36.519531 C 24.707031 37.0625 24.839844 37.582031 25.097656 38.078125 C 24.601562 37.878906 24.140625 37.589844 23.710938 37.210938 C 23.292969 37.496094 22.886719 37.804688 22.5 38.132812 C 22.578125 37.597656 22.652344 37.058594 22.730469 36.519531 C 22.367188 36.230469 22 35.941406 21.632812 35.652344 C 22.171875 35.597656 22.710938 35.578125 23.25 35.597656 C 23.390625 35.101562 23.503906 34.601562 23.597656 34.097656 Z M 23.597656 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.686275%,96.862745%);fill-opacity:1;" d="M 33.058594 34.097656 C 33.359375 34.53125 33.550781 35.03125 33.632812 35.597656 C 34.175781 35.578125 34.710938 35.597656 35.25 35.652344 C 34.894531 35.957031 34.53125 36.246094 34.152344 36.519531 C 34.230469 37.058594 34.308594 37.597656 34.382812 38.132812 C 33.996094 37.804688 33.59375 37.496094 33.171875 37.210938 C 32.742188 37.589844 32.28125 37.878906 31.789062 38.078125 C 32.042969 37.582031 32.179688 37.0625 32.191406 36.519531 C 31.796875 36.214844 31.394531 35.929688 30.980469 35.652344 C 31.554688 35.597656 32.132812 35.578125 32.710938 35.597656 C 32.804688 35.089844 32.917969 34.589844 33.058594 34.097656 Z M 33.058594 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(96.078432%,96.078432%,96.862745%);fill-opacity:1;" d="M 42.519531 34.097656 C 42.820312 34.539062 43.015625 35.039062 43.097656 35.597656 C 43.636719 35.578125 44.175781 35.597656 44.710938 35.652344 C 44.347656 35.941406 43.980469 36.230469 43.617188 36.519531 C 43.691406 37.058594 43.769531 37.597656 43.847656 38.132812 C 43.457031 37.804688 43.054688 37.496094 42.632812 37.210938 C 42.207031 37.589844 41.742188 37.878906 41.25 38.078125 C 41.449219 37.632812 41.601562 37.171875 41.710938 36.691406 C 41.363281 36.265625 40.941406 35.921875 40.441406 35.652344 C 41.019531 35.597656 41.59375 35.578125 42.171875 35.597656 C 42.265625 35.089844 42.378906 34.589844 42.519531 34.097656 Z M 42.519531 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(95.686275%,95.686275%,96.862745%);fill-opacity:1;" d="M 51.980469 34.097656 C 52.28125 34.539062 52.476562 35.039062 52.558594 35.597656 C 53.097656 35.578125 53.636719 35.597656 54.171875 35.652344 C 53.746094 36.003906 53.324219 36.347656 52.902344 36.691406 C 53.136719 37.15625 53.269531 37.636719 53.308594 38.132812 C 52.929688 37.820312 52.523438 37.550781 52.097656 37.328125 C 51.667969 37.503906 51.28125 37.753906 50.941406 38.078125 C 50.847656 38.15625 50.769531 38.136719 50.710938 38.019531 C 50.933594 37.53125 51.066406 37.03125 51.117188 36.519531 C 50.722656 36.214844 50.316406 35.929688 49.902344 35.652344 C 50.441406 35.617188 50.980469 35.578125 51.519531 35.539062 C 51.730469 35.078125 51.886719 34.597656 51.980469 34.097656 Z M 51.980469 34.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.803923%,13.333334%,20.392157%);fill-opacity:1;" d="M 56.941406 34.558594 C 64.867188 34.558594 72.789062 34.558594 80.710938 34.558594 C 76.824219 36.578125 72.902344 38.539062 68.941406 40.441406 C 64.960938 40.328125 60.960938 40.289062 56.941406 40.328125 C 56.941406 38.402344 56.941406 36.480469 56.941406 34.558594 Z M 56.941406 34.558594 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(99.607843%,99.607843%,99.607843%);fill-opacity:1;" d="M -0.0585938 40.328125 C 18.941406 40.328125 37.941406 40.328125 56.941406 40.328125 C 60.960938 40.289062 64.960938 40.328125 68.941406 40.441406 C 65.929688 41.890625 62.929688 43.371094 59.941406 44.882812 C 62.441406 44.941406 64.941406 44.960938 67.441406 44.941406 C 67.441406 54.941406 67.441406 64.941406 67.441406 74.941406 C 65.789062 74.941406 64.132812 74.941406 62.480469 74.941406 C 62.519531 67.328125 62.480469 59.710938 62.367188 52.097656 C 62.296875 52.109375 62.257812 52.148438 62.25 52.210938 C 47.058594 59.730469 31.90625 67.308594 16.789062 74.941406 C 14.941406 74.941406 13.097656 74.941406 11.25 74.941406 C 27.726562 66.644531 44.226562 58.375 60.75 50.132812 C 60.863281 50.078125 60.976562 50.019531 61.097656 49.960938 C 57.421875 49.941406 53.769531 49.882812 50.132812 49.789062 C 52.554688 48.578125 54.976562 47.367188 57.402344 46.152344 C 38.25 46.097656 19.097656 46.078125 -0.0585938 46.097656 C -0.0585938 44.171875 -0.0585938 42.25 -0.0585938 40.328125 Z M -0.0585938 40.328125 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(99.607843%,99.607843%,99.607843%);fill-opacity:1;" d="M 149.941406 44.941406 C 149.941406 46.597656 149.941406 48.25 149.941406 49.902344 C 138.867188 49.882812 127.789062 49.902344 116.710938 49.960938 C 116.832031 50.019531 116.945312 50.078125 117.058594 50.132812 C 128.003906 55.628906 138.964844 61.089844 149.941406 66.519531 C 149.941406 67.441406 149.941406 68.367188 149.941406 69.289062 C 137.019531 62.867188 124.097656 56.441406 111.171875 50.019531 C 107.460938 49.886719 103.730469 49.867188 99.980469 49.960938 C 100.097656 50.019531 100.214844 50.078125 100.328125 50.132812 C 116.847656 58.375 133.347656 66.644531 149.828125 74.941406 C 144.25 74.941406 138.671875 74.941406 133.097656 74.941406 C 117.984375 67.308594 102.828125 59.730469 87.632812 52.210938 C 87.628906 52.148438 87.589844 52.109375 87.519531 52.097656 C 87.402344 59.710938 87.367188 67.328125 87.402344 74.941406 C 85.75 74.941406 84.097656 74.941406 82.441406 74.941406 C 82.441406 64.941406 82.441406 54.941406 82.441406 44.941406 C 104.941406 44.941406 127.441406 44.941406 149.941406 44.941406 Z M 149.941406 44.941406 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.803923%,13.333334%,20.392157%);fill-opacity:1;" d="M -0.0585938 46.097656 C 19.097656 46.078125 38.25 46.097656 57.402344 46.152344 C 54.976562 47.367188 52.554688 48.578125 50.132812 49.789062 C 49.996094 49.839844 49.878906 49.914062 49.789062 50.019531 C 48.542969 50.699219 47.273438 51.355469 45.980469 51.980469 C 30.652344 51.867188 15.308594 51.828125 -0.0585938 51.867188 C -0.0585938 49.941406 -0.0585938 48.019531 -0.0585938 46.097656 Z M -0.0585938 46.097656 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(87.058824%,38.431373%,44.705883%);fill-opacity:1;" d="M 50.132812 49.789062 C 53.769531 49.882812 57.421875 49.941406 61.097656 49.960938 C 60.976562 50.019531 60.863281 50.078125 60.75 50.132812 C 57.117188 50.019531 53.460938 49.980469 49.789062 50.019531 C 49.878906 49.914062 49.996094 49.839844 50.132812 49.789062 Z M 50.132812 49.789062 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(87.450981%,38.431373%,44.705883%);fill-opacity:1;" d="M 111.171875 50.019531 C 107.539062 49.980469 103.921875 50.019531 100.328125 50.132812 C 100.214844 50.078125 100.097656 50.019531 99.980469 49.960938 C 103.730469 49.867188 107.460938 49.886719 111.171875 50.019531 Z M 111.171875 50.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(33.333334%,42.745098%,65.882355%);fill-opacity:1;" d="M 149.941406 49.902344 C 149.941406 49.941406 149.941406 49.980469 149.941406 50.019531 C 138.960938 49.980469 128 50.019531 117.058594 50.132812 C 116.945312 50.078125 116.832031 50.019531 116.710938 49.960938 C 127.789062 49.902344 138.867188 49.882812 149.941406 49.902344 Z M 149.941406 49.902344 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(81.176472%,8.235294%,16.862746%);fill-opacity:1;" d="M 49.789062 50.019531 C 53.460938 49.980469 57.117188 50.019531 60.75 50.132812 C 44.226562 58.375 27.726562 66.644531 11.25 74.941406 C 7.558594 74.941406 3.867188 74.941406 0.171875 74.941406 C 3.941406 73.019531 7.710938 71.097656 11.480469 69.171875 C 15.273438 67.257812 19.082031 65.371094 22.902344 63.519531 C 26.808594 61.585938 30.695312 59.625 34.558594 57.632812 C 38.351562 55.71875 42.160156 53.835938 45.980469 51.980469 C 47.273438 51.355469 48.542969 50.699219 49.789062 50.019531 Z M 49.789062 50.019531 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(81.176472%,8.627451%,17.254902%);fill-opacity:1;" d="M 100.328125 50.132812 C 103.921875 50.019531 107.539062 49.980469 111.171875 50.019531 C 124.097656 56.441406 137.019531 62.867188 149.941406 69.289062 C 149.941406 71.171875 149.941406 73.058594 149.941406 74.941406 C 149.902344 74.941406 149.863281 74.941406 149.828125 74.941406 C 133.347656 66.644531 116.847656 58.375 100.328125 50.132812 Z M 100.328125 50.132812 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0.392157%,14.117648%,49.019608%);fill-opacity:1;" d="M 117.058594 50.132812 C 128 50.019531 138.960938 49.980469 149.941406 50.019531 C 149.941406 55.519531 149.941406 61.019531 149.941406 66.519531 C 138.964844 61.089844 128.003906 55.628906 117.058594 50.132812 Z M 117.058594 50.132812 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(99.607843%,99.607843%,99.607843%);fill-opacity:1;" d="M -0.0585938 51.867188 C 15.308594 51.828125 30.652344 51.867188 45.980469 51.980469 C 42.160156 53.835938 38.351562 55.71875 34.558594 57.632812 C 23.019531 57.632812 11.480469 57.632812 -0.0585938 57.632812 C -0.0585938 55.710938 -0.0585938 53.789062 -0.0585938 51.867188 Z M -0.0585938 51.867188 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0.392157%,14.117648%,49.019608%);fill-opacity:1;" d="M 62.25 52.210938 C 62.367188 59.769531 62.402344 67.347656 62.367188 74.941406 C 47.171875 74.941406 31.980469 74.941406 16.789062 74.941406 C 31.90625 67.308594 47.058594 59.730469 62.25 52.210938 Z M 62.25 52.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(33.333334%,42.745098%,65.882355%);fill-opacity:1;" d="M 62.25 52.210938 C 62.257812 52.148438 62.296875 52.109375 62.367188 52.097656 C 62.480469 59.710938 62.519531 67.328125 62.480469 74.941406 C 62.441406 74.941406 62.402344 74.941406 62.367188 74.941406 C 62.402344 67.347656 62.367188 59.769531 62.25 52.210938 Z M 62.25 52.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(33.333334%,42.745098%,65.882355%);fill-opacity:1;" d="M 87.632812 52.210938 C 87.519531 59.769531 87.480469 67.347656 87.519531 74.941406 C 87.480469 74.941406 87.441406 74.941406 87.402344 74.941406 C 87.367188 67.328125 87.402344 59.710938 87.519531 52.097656 C 87.589844 52.109375 87.628906 52.148438 87.632812 52.210938 Z M 87.632812 52.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0.392157%,14.117648%,49.019608%);fill-opacity:1;" d="M 87.632812 52.210938 C 102.828125 59.730469 117.984375 67.308594 133.097656 74.941406 C 117.902344 74.941406 102.710938 74.941406 87.519531 74.941406 C 87.480469 67.347656 87.519531 59.769531 87.632812 52.210938 Z M 87.632812 52.210938 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.803923%,13.333334%,20.392157%);fill-opacity:1;" d="M -0.0585938 57.632812 C 11.480469 57.632812 23.019531 57.632812 34.558594 57.632812 C 30.695312 59.625 26.808594 61.585938 22.902344 63.519531 C 15.269531 63.402344 7.617188 63.367188 -0.0585938 63.402344 C -0.0585938 61.480469 -0.0585938 59.558594 -0.0585938 57.632812 Z M -0.0585938 57.632812 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(99.607843%,99.607843%,99.607843%);fill-opacity:1;" d="M -0.0585938 63.402344 C 7.617188 63.367188 15.269531 63.402344 22.902344 63.519531 C 19.082031 65.371094 15.273438 67.257812 11.480469 69.171875 C 7.632812 69.171875 3.789062 69.171875 -0.0585938 69.171875 C -0.0585938 67.25 -0.0585938 65.328125 -0.0585938 63.402344 Z M -0.0585938 63.402344 "/>
|
||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(69.803923%,13.725491%,20.784314%);fill-opacity:1;" d="M -0.0585938 69.171875 C 3.789062 69.171875 7.632812 69.171875 11.480469 69.171875 C 7.710938 71.097656 3.941406 73.019531 0.171875 74.941406 C 0.0976562 74.941406 0.0195312 74.941406 -0.0585938 74.941406 C -0.0585938 73.019531 -0.0585938 71.097656 -0.0585938 69.171875 Z M -0.0585938 69.171875 "/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg id="layer" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 72 72">
|
||||
<!-- Generator: Adobe Illustrator 29.4.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 152) -->
|
||||
<defs>
|
||||
<style>
|
||||
.st0 {
|
||||
fill: #b4b4c7;
|
||||
}
|
||||
|
||||
.st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7, .st8, .st9, .st10, .st11, .st12, .st13, .st14, .st15, .st16, .st17, .st18, .st19, .st20, .st21, .st22, .st23, .st24, .st25, .st26, .st27, .st28, .st29, .st30, .st31, .st32, .st33, .st34, .st35, .st36, .st37, .st38, .st39, .st40, .st41, .st42, .st43, .st44 {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.st1 {
|
||||
fill: #f6f6f9;
|
||||
}
|
||||
|
||||
.st2 {
|
||||
fill: #de6272;
|
||||
}
|
||||
|
||||
.st3 {
|
||||
fill: #3c3b6e;
|
||||
}
|
||||
|
||||
.st4 {
|
||||
fill: #f7f7f9;
|
||||
}
|
||||
|
||||
.st5 {
|
||||
fill: #01247d;
|
||||
}
|
||||
|
||||
.st6 {
|
||||
fill: #8e8dab;
|
||||
}
|
||||
|
||||
.st7 {
|
||||
fill: #cf162c;
|
||||
}
|
||||
|
||||
.st8 {
|
||||
fill: #f4f3f6;
|
||||
}
|
||||
|
||||
.st9 {
|
||||
fill: #afafc3;
|
||||
}
|
||||
|
||||
.st10 {
|
||||
fill: #8d8caa;
|
||||
}
|
||||
|
||||
.st11 {
|
||||
fill: #f7f6f9;
|
||||
}
|
||||
|
||||
.st12 {
|
||||
fill: #fefefe;
|
||||
}
|
||||
|
||||
.st45 {
|
||||
fill: #d22f27;
|
||||
}
|
||||
|
||||
.st13 {
|
||||
fill: #9897b3;
|
||||
}
|
||||
|
||||
.st14 {
|
||||
fill: #8b8aa8;
|
||||
}
|
||||
|
||||
.st15 {
|
||||
fill: #cf152b;
|
||||
}
|
||||
|
||||
.st16 {
|
||||
fill: #afafc4;
|
||||
}
|
||||
|
||||
.st46 {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.st17 {
|
||||
fill: #f5f5f8;
|
||||
}
|
||||
|
||||
.st18 {
|
||||
fill: #f5f4f7;
|
||||
}
|
||||
|
||||
.st19 {
|
||||
fill: #aeaec3;
|
||||
}
|
||||
|
||||
.st20 {
|
||||
fill: #acacc1;
|
||||
}
|
||||
|
||||
.st21 {
|
||||
fill: #6f6e94;
|
||||
}
|
||||
|
||||
.st22 {
|
||||
fill: #b12234;
|
||||
}
|
||||
|
||||
.st23 {
|
||||
fill: #b22335;
|
||||
}
|
||||
|
||||
.st24 {
|
||||
fill: #556da8;
|
||||
}
|
||||
|
||||
.st25 {
|
||||
fill: #8786a6;
|
||||
}
|
||||
|
||||
.st26 {
|
||||
fill: #acabc1;
|
||||
}
|
||||
|
||||
.st27 {
|
||||
fill: #f6f6f8;
|
||||
}
|
||||
|
||||
.st28 {
|
||||
fill: #f4f4f7;
|
||||
}
|
||||
|
||||
.st29 {
|
||||
fill: #cf142b;
|
||||
}
|
||||
|
||||
.st30 {
|
||||
fill: #afaec3;
|
||||
}
|
||||
|
||||
.st31 {
|
||||
fill: #717096;
|
||||
}
|
||||
|
||||
.st32 {
|
||||
fill: #adadc2;
|
||||
}
|
||||
|
||||
.st33 {
|
||||
fill: #f6f5f8;
|
||||
}
|
||||
|
||||
.st34 {
|
||||
fill: #df6272;
|
||||
}
|
||||
|
||||
.st35 {
|
||||
fill: #9594b0;
|
||||
}
|
||||
|
||||
.st36 {
|
||||
fill: #8c8ba9;
|
||||
}
|
||||
|
||||
.st37 {
|
||||
fill: #9796b2;
|
||||
}
|
||||
|
||||
.st38 {
|
||||
fill: #9897b2;
|
||||
}
|
||||
|
||||
.st39 {
|
||||
fill: #8a89a8;
|
||||
}
|
||||
|
||||
.st40 {
|
||||
fill: #9695b1;
|
||||
}
|
||||
|
||||
.st41 {
|
||||
fill: #b0b0c4;
|
||||
}
|
||||
|
||||
.st42 {
|
||||
fill: #706f95;
|
||||
}
|
||||
|
||||
.st43 {
|
||||
fill: #b22234;
|
||||
}
|
||||
|
||||
.st44 {
|
||||
fill: #f5f5f7;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<circle id="_日本のイースターエッグ" data-name="日本のイースターエッグ" class="st45" cx="36" cy="36.2" r="9"/>
|
||||
<g id="surface1">
|
||||
<path class="st3" d="M5.3,17.4h23.5v20.2H5.3v-20.2Z"/>
|
||||
<path class="st22" d="M28.8,17.4h38.2c-1.5,1-3.1,1.9-4.7,2.9-11.2,0-22.4,0-33.6,0v-2.9Z"/>
|
||||
<path class="st12" d="M67,17.4h0v4.2c-4.5,2.7-9,5.4-13.5,8.2,0,0,0,0-.1,0,4.6,0,9.1,0,13.7,0v2.5c-8.3,0-16.5,0-24.8,0-1.3.8-2.5,1.5-3.8,2.3h-9.8v-2.9c4.8,0,9.7,0,14.5,0,1.6-1,3.1-1.9,4.7-2.8-6.4,0-12.8,0-19.2,0v-2.9c8,0,16.1,0,24.1,0,1.6-.9,3.1-1.9,4.7-2.8-9.6,0-19.2,0-28.7,0v-2.9c11.2,0,22.4,0,33.6,0,1.6-.9,3.1-1.9,4.7-2.9Z"/>
|
||||
<path class="st33" d="M7.5,19c.2,0,.4.2.6.2-.2.1-.3.3-.4.4,0,.3.1.5.2.8-.2-.2-.3-.3-.5-.5-.2,0-.4.2-.5.4,0-.2,0-.5.1-.7-.1-.2-.3-.3-.5-.4.2,0,.4,0,.6-.1.1-.9.2-1,.4,0Z"/>
|
||||
<path class="st11" d="M11.5,19c.2,0,.4,0,.6.1-.2.1-.3.3-.4.5,0,.2.1.5.1.7-.1-.2-.3-.3-.5-.4-.2.1-.4.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3.2,0,.4,0,.6-.1,0-.3.1-.5.2-.7,0,.3.1.5.2.7Z"/>
|
||||
<path class="st4" d="M23.1,19c.2,0,.4,0,.6.1-.1.1-.3.2-.4.3,0,.3,0,.5,0,.8-.2-.2-.3-.3-.5-.4-.2,0-.4.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3.2,0,.4,0,.6-.1,0-.2.1-.5.2-.7.1.2.2.4.2.7Z"/>
|
||||
<path class="st27" d="M27,19c.2,0,.4,0,.6.1-.2.1-.3.3-.5.4,0,.2.2.5.2.7-.2-.2-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.3,0-.5.2-.8-.1-.2-.3-.3-.4-.4.2,0,.4,0,.6-.2.1-.9.3-.9.4,0Z"/>
|
||||
<path class="st27" d="M15.3,19c.2,0,.4,0,.6.1-.1.1-.3.2-.4.3,0,.3,0,.5,0,.8-.1-.2-.3-.3-.5-.4-.2.1-.3.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3.2,0,.4,0,.6-.1,0-.2.2-.5.2-.7,0,.3.2.5.2.7Z"/>
|
||||
<path class="st4" d="M19.2,19c.2,0,.4,0,.6.1-.1.1-.3.2-.4.3,0,.3,0,.5,0,.8-.2-.2-.3-.3-.5-.4-.2.1-.3.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3.2,0,.4,0,.6-.1,0-.2.1-.5.2-.7,0,.2.2.4.2.7Z"/>
|
||||
<path class="st19" d="M7.1,19c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st0" d="M7.5,19c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.2Z"/>
|
||||
<path class="st20" d="M11,19c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st41" d="M11.5,19c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st26" d="M14.9,19c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st19" d="M15.3,19c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st32" d="M18.8,19c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st30" d="M19.2,19c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st16" d="M22.7,19c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st32" d="M23.1,19c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st0" d="M26.6,19c-.2,0-.4.2-.6.2,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st9" d="M27,19c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st8" d="M8.5,21.2c.2,0,.4,0,.6-.1,0-.3.1-.5.2-.7,0,.2.1.5.2.7.2,0,.5,0,.7,0-.2.2-.4.3-.5.5,0,.2.1.5.1.7-.1-.2-.3-.3-.5-.4-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.2-.2-.3-.3-.5-.4Z"/>
|
||||
<path class="st8" d="M12.4,21.2c.2,0,.4,0,.6-.1,0-.3.1-.5.2-.7,0,.2.1.5.2.7.2,0,.5,0,.7,0-.2.2-.4.3-.5.5,0,.2.1.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3Z"/>
|
||||
<path class="st28" d="M25,21c.2,0,.4,0,.6.1-.2.1-.3.3-.5.4,0,.2.2.5.2.7-.2-.2-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.2-.2-.3-.4-.5-.5.2,0,.5,0,.7,0,0-.3,0-.5.2-.7.1.2.2.5.2.7Z"/>
|
||||
<path class="st1" d="M17.3,21c.2,0,.4,0,.6.1-.2.1-.3.3-.4.5,0,.2.1.5.1.7-.1-.1-.3-.3-.5-.4-.2.1-.4.2-.5.4,0-.3,0-.5,0-.8-.1-.1-.3-.2-.4-.3.2,0,.4,0,.6-.1,0-.2.2-.5.2-.7,0,.2.2.5.2.7Z"/>
|
||||
<path class="st1" d="M21.1,21c.2,0,.4,0,.6.1-.1.1-.3.2-.4.3,0,.3,0,.5,0,.8-.2-.2-.3-.3-.5-.4-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.1-.2-.3-.3-.4-.5.2,0,.4,0,.6-.1,0-.2.1-.5.2-.7,0,.2.2.4.2.7Z"/>
|
||||
<path class="st35" d="M9.1,21c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st37" d="M13,21c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st40" d="M16.8,21c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st37" d="M17.3,21c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st13" d="M20.7,21c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st38" d="M21.1,21c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st40" d="M25,21c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st5" d="M67.1,21.6v8.2c-4.5,0-9,0-13.5,0,4.5-2.7,9-5.5,13.5-8.2Z"/>
|
||||
<path class="st4" d="M7.6,23.1c.2,0,.4,0,.6.1-.2.1-.3.3-.5.5,0,.2.1.5.2.7-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.2-.2-.3-.3-.5-.4.2,0,.4,0,.6-.1,0-.3.1-.5.2-.7,0,.3.1.5.2.7Z"/>
|
||||
<path class="st27" d="M10.4,23.2c.2,0,.4,0,.6-.1,0-.3.1-.5.2-.7,0,.3.1.5.2.8.2,0,.4,0,.6,0-.2.2-.3.3-.5.5,0,.2.1.5.1.7-.2-.2-.3-.3-.5-.4-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.2-.2-.3-.3-.5-.4Z"/>
|
||||
<path class="st4" d="M23.1,23.1c.2,0,.4,0,.6.1-.2.1-.3.3-.5.4,0,.2.2.5.2.7-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.1-.2-.3-.4-.5-.5.2,0,.4,0,.6,0,0-.2.1-.5.2-.7.1.2.2.4.2.7Z"/>
|
||||
<path class="st4" d="M27,23.1c.2,0,.4,0,.6.1-.2.1-.3.3-.5.4.1.2.2.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.1-.2-.3-.3-.5-.5.2,0,.4,0,.6-.1,0-.2.1-.5.2-.7,0,.2.2.5.2.7Z"/>
|
||||
<path class="st11" d="M14.3,23.2c.2,0,.4,0,.6-.1,0-.2,0-.5.2-.7,0,.2.2.5.2.7.2,0,.4,0,.6,0-.2.1-.3.3-.5.5,0,.2.1.5.1.7-.2-.2-.3-.3-.5-.4-.2.1-.3.3-.5.4,0,0,0,0,0,0,0-.2.1-.4.1-.6-.1-.2-.3-.3-.4-.5Z"/>
|
||||
<path class="st4" d="M19,22.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.5,0,.2,0,.5.1.7-.2-.2-.3-.3-.5-.4-.2.1-.3.2-.5.4,0-.2,0-.5.1-.7-.1-.2-.3-.4-.5-.5.2,0,.4,0,.6,0,0-.2.1-.5.2-.7Z"/>
|
||||
<path class="st39" d="M7.1,23.1c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st25" d="M7.6,23.1c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st36" d="M11,23.1c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st6" d="M14.9,23.1c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st10" d="M23.1,23.1c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st25" d="M26.6,23.1c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st14" d="M27,23.1c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st22" d="M28.8,23.2c9.6,0,19.2,0,28.7,0-1.6.9-3.1,1.9-4.7,2.8-8,0-16.1,0-24.1,0v-2.9Z"/>
|
||||
<path class="st27" d="M9.5,25.1c.2,0,.4,0,.6.1-.2.1-.3.3-.5.5,0,.2.1.5.2.7-.2-.2-.3-.3-.5-.5-.2.1-.4.3-.5.5,0-.3,0-.5.2-.8-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.8,0,.3.1.5.2.7Z"/>
|
||||
<path class="st27" d="M24,25.2c.2,0,.4,0,.6-.1,0-.2.1-.5.2-.7,0,.3.2.5.2.8.2,0,.4,0,.7,0-.2.1-.4.3-.5.5.1.2.2.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.1-.2-.3-.4-.5-.5Z"/>
|
||||
<path class="st4" d="M13.1,24.4s0,0,0,0c0,.2.1.4.2.6.2,0,.4,0,.6,0-.2.1-.3.3-.5.4,0,.2,0,.5,0,.7-.2-.2-.3-.3-.5-.4-.2.1-.3.3-.5.4h0c0-.3.1-.6,0-.8-.1-.1-.3-.2-.4-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M17.2,25.1c.2,0,.4,0,.7.1-.2.1-.3.3-.5.5,0,.2.1.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4h0c0-.3,0-.5.1-.7-.1-.2-.3-.4-.5-.5.2,0,.4,0,.7-.1.1-.9.3-.9.4,0Z"/>
|
||||
<path class="st1" d="M21.1,25.1c.2,0,.4,0,.7.1-.2,0-.4.3-.5.5,0,.2,0,.4.1.6,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4,0-.2,0-.5.1-.7-.1-.2-.3-.3-.5-.5.2,0,.4,0,.6,0,0-.2.2-.5.2-.7,0,.2.2.5.2.7Z"/>
|
||||
<path class="st42" d="M9.5,25.1c.2,0,.4,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.6-.1Z"/>
|
||||
<path class="st31" d="M16.9,25.1c-.2,0-.4,0-.7.1,0,0,0,0,0,0,.2,0,.5,0,.7,0Z"/>
|
||||
<path class="st31" d="M17.2,25.1c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.7-.1Z"/>
|
||||
<path class="st21" d="M21.1,25.1c.2,0,.5,0,.7,0,0,0,0,0,0,0-.2,0-.4,0-.7-.1Z"/>
|
||||
<path class="st21" d="M24.6,25.1c-.2,0-.4,0-.6.1,0,0,0,0,0,0,.2,0,.4,0,.7,0Z"/>
|
||||
<path class="st1" d="M7.3,26.4c.1.2.2.5.2.7h.6c-.2.2-.3.4-.5.6,0,.2.1.5.2.7-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.4,0,0,0,0,0,0,0-.2.2-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st11" d="M26.8,26.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.4.3-.5.5.1.2.2.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.1-.2-.3-.4-.5-.5h.6c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st27" d="M11.2,26.4c0,0,0,0,.1.1,0,.2,0,.4.2.6h.6c-.2.2-.3.4-.5.6,0,.2.1.5.2.7-.2-.2-.4-.3-.5-.5-.2.2-.3.3-.5.5,0-.2,0-.5.2-.7-.2-.2-.3-.4-.5-.5.2,0,.4,0,.7,0,0-.2.1-.5.1-.7Z"/>
|
||||
<path class="st27" d="M15.1,26.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0,0,0,0,0,0,.1-.3.2-.5.1-.8-.1-.1-.3-.2-.4-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M19,26.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4h0c0-.3.1-.5.1-.7-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st4" d="M22.9,26.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.4.3-.5.5.1.2.2.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.1-.2-.3-.4-.5-.5h.6c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st1" d="M9.3,28.4c0,.2.2.5.2.7h.6c-.2.2-.3.4-.5.6,0,.2.1.5.2.7-.2-.2-.4-.3-.5-.5-.2.2-.4.3-.6.4,0-.2.2-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st27" d="M13.1,28.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.6,0,0,0,0,0,.1-.2-.1-.3-.3-.5-.4-.2.2-.3.3-.5.5,0,0,0,0,0,0,.1-.2.2-.5.2-.8-.2-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st11" d="M17,28.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.2-.3.3-.5.5,0,0,0,0,0,0,.1-.2.2-.5.2-.8-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M20.9,28.4s0,0,0,0c0,.2.1.4.1.7.2,0,.4,0,.7,0-.1.1-.3.3-.5.4,0,.2,0,.4.1.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4,0,0,0,0,0-.1,0-.2.1-.4.1-.6-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st4" d="M24.8,28.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.4.3-.5.5.1.2.2.5.1.7-.2-.1-.3-.3-.5-.4-.2.1-.4.3-.5.5,0-.2,0-.5.2-.7-.1-.2-.3-.4-.5-.5h.6c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st22" d="M28.8,28.9c6.4,0,12.8,0,19.2,0-1.6.9-3.1,1.9-4.7,2.8-4.8,0-9.7,0-14.5,0v-2.9Z"/>
|
||||
<path class="st24" d="M53.6,29.8c4.5,0,9,0,13.5,0h0c-4.6,0-9.1,0-13.7,0,0,0,0,0,.1,0Z"/>
|
||||
<path class="st4" d="M7.3,30.4c0,.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.7,0,0,0,0,0,0-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.5,0-.3,0-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st4" d="M11.2,30.4s0,0,0,0c0,.2.1.4.2.6.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.6,0,0,0,0,0,.1-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.5,0-.3,0-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.2.1-.5.1-.7Z"/>
|
||||
<path class="st27" d="M15.1,30.4c.1.2.2.5.2.7.2,0,.5,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.8h0c-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.4,0,0,0,0,0,0,.1-.2.2-.5.2-.8-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M19,30.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.2,0,.4.1.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.4-.2.2-.3.3-.5.5,0,0,0,0,0,0,.1-.2.2-.5.2-.8-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M22.9,30.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.3.3-.5.5,0,.2.2.5.2.7-.2,0-.4-.2-.6-.4-.2.1-.3.3-.5.4,0,0,0,0,0,0,0-.2.1-.5.2-.7-.2-.2-.3-.3-.5-.4h.7c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st4" d="M26.8,30.4c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.3.3-.5.5,0,.2.1.5.2.7-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.4,0,0,0,0,0,0,0-.2.1-.5.2-.7-.2-.2-.3-.3-.5-.4h.7c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st29" d="M67.1,32.4v7.5h-27.8v15h-6.2v-15c-1,0-2.1,0-3.1,0,1.2-.8,2.5-1.5,3.7-2.2,1.6-.9,3.2-1.9,4.8-2.9,1.2-.8,2.5-1.5,3.8-2.3,8.3,0,16.5,0,24.8,0Z"/>
|
||||
<path class="st44" d="M9.3,32.5c0,.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.7,0,0,0,0,0,0-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.5,0-.3,0-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st17" d="M13.1,32.5c.1.2.2.5.2.7.2,0,.5,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.8h0c-.2-.1-.3-.3-.5-.4-.2.1-.3.3-.5.5,0-.3,0-.5.2-.7-.2-.2-.4-.3-.5-.5.2,0,.4,0,.7,0,0-.2.1-.5.1-.7Z"/>
|
||||
<path class="st44" d="M17,32.5c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.8h0c-.2-.1-.3-.3-.5-.4-.2.2-.4.3-.6.4.1-.2.2-.5.2-.8-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st27" d="M20.9,32.5c.1.2.2.4.2.7.2,0,.4,0,.7,0-.1.1-.3.3-.5.4v.8c0-.2-.2-.3-.4-.5-.2.1-.3.3-.5.4,0,0,0,0,0,0,.1-.2.2-.5.2-.8-.2-.2-.3-.3-.5-.4.2,0,.5,0,.7,0,0-.2,0-.5.1-.7Z"/>
|
||||
<path class="st44" d="M24.8,32.5c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.3.3-.5.5.1.2.2.5.2.7-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.4,0,0,0,0,0,0,0-.2.1-.5.2-.7-.2-.2-.3-.3-.5-.4h.7c0-.3.1-.5.2-.8Z"/>
|
||||
<path class="st18" d="M7.3,34.5c0,.2.2.5.2.7.2,0,.4,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.7,0,0,0,0,0,0-.2-.1-.3-.3-.5-.5-.2.2-.3.3-.5.5,0-.2,0-.5.2-.7-.2-.2-.3-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st17" d="M11.2,34.5c0,.2.2.5.2.7.2,0,.5,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.8,0,0,0,0,0,0-.2-.2-.3-.3-.5-.5-.2.1-.3.3-.5.5,0-.3,0-.5.2-.7-.2-.2-.4-.3-.5-.5.2,0,.4,0,.7,0,0-.3.1-.5.2-.7Z"/>
|
||||
<path class="st28" d="M15.1,34.5c.1.2.2.5.2.7.2,0,.5,0,.7,0-.2.1-.3.3-.5.4,0,.3,0,.5.2.8-.2,0-.4-.2-.6-.4-.2.1-.3.3-.5.5,0-.3,0-.5,0-.8-.1-.1-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.2.1-.5.1-.7Z"/>
|
||||
<path class="st28" d="M19,34.5c.1.2.2.5.2.7.2,0,.4,0,.7,0-.1.2-.3.3-.5.4,0,.3,0,.5,0,.8-.2-.2-.3-.3-.5-.5-.2.2-.4.3-.6.4.1-.2.2-.5.2-.8-.2-.2-.3-.3-.5-.4.2,0,.5,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st44" d="M22.9,34.5c.1.2.2.5.2.7.2,0,.4,0,.7,0-.1.1-.3.3-.5.4,0,.3,0,.5,0,.8-.2-.2-.3-.3-.5-.5-.2.2-.4.3-.6.4,0-.2.1-.5.2-.7-.1-.2-.3-.4-.5-.5.2,0,.5,0,.7,0,0-.3,0-.5.1-.7Z"/>
|
||||
<path class="st28" d="M26.8,34.5c.1.2.2.5.2.7.2,0,.4,0,.7,0-.2.2-.3.3-.5.5,0,.2.2.5.2.7-.2-.2-.3-.3-.5-.4-.2,0-.3.2-.5.4,0,0,0,0,0,0,0-.2.1-.5.2-.7-.2-.2-.3-.3-.5-.4.2,0,.4,0,.7,0,0-.2.2-.5.2-.7Z"/>
|
||||
<path class="st43" d="M28.8,34.7h9.8c-1.6,1-3.2,2-4.8,2.9-1.6,0-3.3,0-4.9,0v-2.9Z"/>
|
||||
<path class="st12" d="M5.3,37.6h23.5c1.7,0,3.3,0,4.9,0-1.2.7-2.5,1.5-3.7,2.2,1,0,2.1,0,3.1,0v15h-2c0-3.8,0-7.6,0-11.4,0,0,0,0,0,0-6.3,3.8-12.5,7.5-18.7,11.3h-2.3c6.8-4.1,13.6-8.3,20.4-12.4,0,0,0,0,.1,0-1.5,0-3,0-4.5,0,1-.6,2-1.2,3-1.8-7.9,0-15.8,0-23.7,0v-2.9Z"/>
|
||||
<path class="st12" d="M67.1,39.9v2.5c-4.6,0-9.1,0-13.7,0,0,0,0,0,.1,0,4.5,2.7,9,5.5,13.5,8.2v1.4c-5.3-3.2-10.6-6.4-16-9.6-1.5,0-3.1,0-4.6,0,0,0,0,0,.1,0,6.8,4.1,13.6,8.2,20.4,12.4h-6.9c-6.2-3.8-12.5-7.6-18.7-11.3,0,0,0,0,0,0,0,3.8,0,7.6,0,11.4h-2v-15h27.8Z"/>
|
||||
<path class="st43" d="M5.3,40.5c7.9,0,15.8,0,23.7,0-1,.6-2,1.2-3,1.8,0,0-.1,0-.1.1-.5.3-1,.7-1.6,1-6.3,0-12.6,0-19,0v-2.9Z"/>
|
||||
<path class="st2" d="M26,42.3c1.5,0,3,0,4.5,0,0,0,0,0-.1,0-1.5,0-3,0-4.5,0,0,0,0,0,.1-.1Z"/>
|
||||
<path class="st34" d="M51.1,42.4c-1.5,0-3,0-4.5,0,0,0,0,0-.1,0,1.5,0,3.1,0,4.6,0Z"/>
|
||||
<path class="st24" d="M67.1,42.4h0c-4.5,0-9,0-13.5.1,0,0,0,0-.1,0,4.6,0,9.1,0,13.7,0Z"/>
|
||||
<path class="st15" d="M25.9,42.4c1.5,0,3,0,4.5,0-6.8,4.1-13.6,8.2-20.4,12.4h-4.6c1.6-1,3.1-1.9,4.7-2.9,1.6-1,3.1-1.9,4.7-2.8,1.6-1,3.2-1.9,4.8-2.9,1.6-1,3.1-1.9,4.7-2.8.5-.3,1.1-.6,1.6-1Z"/>
|
||||
<path class="st7" d="M46.7,42.5c1.5,0,3,0,4.5,0,5.3,3.2,10.6,6.4,16,9.6v2.8h0c-6.8-4.1-13.6-8.3-20.4-12.4Z"/>
|
||||
<path class="st5" d="M53.6,42.5c4.5,0,9,0,13.5,0v8.2c-4.5-2.7-9-5.4-13.5-8.2Z"/>
|
||||
<path class="st12" d="M5.3,43.3c6.3,0,12.6,0,19,0-1.6.9-3.1,1.9-4.7,2.8H5.3v-2.9Z"/>
|
||||
<path class="st5" d="M31,43.5c0,3.8,0,7.6,0,11.3H12.3c6.2-3.8,12.5-7.6,18.7-11.3Z"/>
|
||||
<path class="st24" d="M31,43.5s0,0,0,0c0,3.8,0,7.6,0,11.4h0c0-3.8,0-7.6,0-11.3Z"/>
|
||||
<path class="st24" d="M41.4,43.5c0,3.8,0,7.6,0,11.3h0c0-3.8,0-7.6,0-11.4,0,0,0,0,0,0Z"/>
|
||||
<path class="st5" d="M41.4,43.5c6.3,3.8,12.5,7.5,18.7,11.3h-18.8c0-3.8,0-7.6,0-11.3Z"/>
|
||||
<path class="st43" d="M5.3,46.2h14.3c-1.6,1-3.2,2-4.8,2.9-3.1,0-6.3,0-9.5,0v-2.9Z"/>
|
||||
<path class="st12" d="M5.3,49.1c3.2,0,6.3,0,9.5,0-1.6.9-3.1,1.9-4.7,2.8h-4.8v-2.9Z"/>
|
||||
<path class="st23" d="M5.3,52h4.8c-1.6,1-3.1,1.9-4.7,2.9h0v-2.9Z"/>
|
||||
</g>
|
||||
<path id="path" class="st46" d="M5,17h62v38H5V17Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="svg4" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" viewBox="0 0 800 800">
|
||||
<!-- Generator: Adobe Illustrator 29.3.1, SVG Export Plug-In . SVG Version: 2.1.0 Build 151) -->
|
||||
<defs>
|
||||
<style>
|
||||
.st0 {
|
||||
stroke-width: 125px;
|
||||
}
|
||||
|
||||
.st0, .st1 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
|
||||
.st1 {
|
||||
stroke-dasharray: 98 98;
|
||||
stroke-width: 100px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<sodipodi:namedview id="namedview6" bordercolor="#000000" borderopacity="0.25" inkscape:current-layer="svg4" inkscape:cx="401.69492" inkscape:cy="400" inkscape:deskcolor="#d1d1d1" inkscape:pagecheckerboard="0" inkscape:pageopacity="0.0" inkscape:showpageshadow="2" inkscape:window-height="987" inkscape:window-maximized="1" inkscape:window-width="1536" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="0.295" pagecolor="#ffffff" showgrid="false"/>
|
||||
<circle class="st1" cx="400" cy="400" r="249.7"/>
|
||||
<ellipse class="st0" cx="400" cy="400" rx="159.6" ry="164.9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -28,7 +28,7 @@
|
||||
"ui_pop": "Pop (Популация) - Количеството популация, която притежавате, максималната Ви популация и скоростта, с която тя се увеличава.",
|
||||
"ui_gold": "Gold (Злато) - Количеството злато, което притежавате и скоростта, с която го получавате.",
|
||||
"ui_troops_workers": "Войници и Работници - Количеството разпределени войници и работници. Войниците се използват за атакуване или защитаване срещу атаки. Работниците се използват за генериране на злато. Можете да коригирате количеството войници и работници, използвайки плъзгача.",
|
||||
"ui_attack_ratio": "Съотношение на атака - Количеството войници, които ще се използват при атака. Можете да коригирате съотношението на атака, използвайки плъзгача.",
|
||||
"ui_attack_ratio": "Съотношение на атака - Количеството войници, които ще се използват при атака. Можете да коригирате съотношението на атака, използвайки плъзгача. Притежаването на повече атакуващи войници от тези в защита ще ви накара да загубите по-малко войници при атаката, докато притежаването на по-малко ще увеличи щетите, нанесени на вашите атакуващи войници. Ефектът не надхвърля съотношения 2:1.",
|
||||
"ui_options": "Опции",
|
||||
"ui_options_desc": "Следните елементи могат да бъдат намерени вътре:",
|
||||
"option_pause": "Поставяне/Премахване на пауза на играта - Налични само в самостоятелна игра.",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Изпращане на емоджи до играча.",
|
||||
"info_ally_panel": "Информационно меню за съюзници",
|
||||
"info_ally_desc": "Когато се съюзите с играч, следните иконки стават налични:",
|
||||
"ally_betray": "Предаване на съюзника Ви, прекратявайки съюзничеството. Сега ще имате перманентна иконка, заседнала до името Ви. Има по-малка вероятност ботове да се съюзят с Вас, а играчи ще мислят два пъти преди да го направят.",
|
||||
"ally_betray": "Предаване на съюзника Ви, прекратявайки съюзничеството. Сега ще имате постоянна икона, залепена до името Ви, освен ако самата друга нация не е била предател. Атаките срещу вас ще доведат до по-малко загуби за нападателя до края на играта, по-малко вероятно ще е ботовете да се съюзят с Вас, а играчите ще мислят два пъти преди да го направят.",
|
||||
"ally_donate": "Даряване на част от войниците си на съюзника Ви. Използвано, когато той е с малко войници и бива атакуван или когато му е нужна тази допълнителна сила, за да размаже противника.",
|
||||
"build_menu_title": "Меню за строене",
|
||||
"build_name": "Име",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Пристанище",
|
||||
"build_port_desc": "Автоматично изпраща търговски кораби между пристанищата на вашата страна и други държави (освен ако сте щракнали върху \"спиране на търговията\" върху тях или те са щракнали върху \"спиране на търговията с вас\"), давайки злато и на двете страни. Позволява изграждането на бойни кораби. Може да се строи само близо до вода.",
|
||||
"build_warship": "Боен кораб",
|
||||
"build_warship_desc": "Патрулира в даден район, като превзема търговски кораби и унищожава вражески военни кораби и лодки. Създава се от най-близкото пристанище и патрулира района, в който първо сте щракнали, за да го построите.",
|
||||
"build_warship_desc": "Патрулира в даден район, като превзема търговски кораби и унищожава вражески военни кораби и лодки. Създава се от най-близкото пристанище и патрулира района, в който първо сте щракнали, за да го построите. Можете да контролирате бойните кораби, като щракнете с атака върху тях и след това щракнете с атака върху новата област, към която искате да се преместят.",
|
||||
"build_silo": "Ракетен силоз",
|
||||
"build_silo_desc": "Позволява изстрелване на ракети.",
|
||||
"build_sam": "Противоракетна установка земя-въздух SAM",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Корона - Това е играч номер 1 в класацията",
|
||||
"icon_traitor": "Кръстосани мечове - Предател. Този играч е атакувал съюзник.",
|
||||
"icon_ally": "Ръкостискане - Съюзник. Този играч е Ваш съюзник.",
|
||||
"info_enemy_panel": "Информационно меню за врагове"
|
||||
"info_enemy_panel": "Информационно меню за врагове",
|
||||
"action_emote": "Отваряне на менюто за емоджита"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Самостоятелна Игра",
|
||||
@@ -172,5 +173,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "Всеки срещу всеки (FFA)",
|
||||
"teams": "Отбори"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Изберете език"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "ডিসকর্ডে যোগ দিন!",
|
||||
"create_lobby": "লবি তৈরি করুন",
|
||||
"join_lobby": "লবিতে যোগ দিন",
|
||||
"single_player": "কম্পিউটার মোড",
|
||||
"instructions": "নির্দেশনা",
|
||||
"how_to_play": "খেলার নিয়ম",
|
||||
"wiki": "উইকি"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "হট-কী",
|
||||
"table_key": "Key",
|
||||
"table_action": "কাজ",
|
||||
"action_alt_view": "বিকল্প দৃশ্য (ভূখণ্ড/দেশ)",
|
||||
"action_attack_altclick": "আক্রমণ (যখন বাম ক্লিক মেনু খুলতে সেট করা হয়)",
|
||||
"action_build": "নির্মাণ মেনু খুলুন",
|
||||
"action_center": "ক্যামেরা খেলোয়াড়ে ফোকাস করুন",
|
||||
"action_zoom": "জুম আউট/ইন করুন",
|
||||
"action_move_camera": "ক্যামেরা সরান",
|
||||
"action_ratio_change": "আক্রমণ অনুপাত কমান/বাড়ান",
|
||||
"action_reset_gfx": "গ্রাফিক্স রিসেট করুন",
|
||||
"ui_section": "Game UI",
|
||||
"ui_leaderboard": "লিডারবোর্ড",
|
||||
"ui_leaderboard_desc": "খেলার শীর্ষ খেলোয়াড় এবং তাদের নাম, মালিকানাধীন জমি এবং সোনার শতাংশ দেখায়।",
|
||||
"ui_control": "কন্ট্রোল প্যানেল",
|
||||
"ui_control_desc": "কন্ট্রোল প্যানেলে নিম্নলিখিত উপাদানগুলি থাকে:",
|
||||
"ui_pop": "আপনার কাছে কতগুলি ইউনিট রয়েছে, আপনার সর্বোচ্চ জনসংখ্যা এবং আপনি এগুলি অর্জন করার হার।",
|
||||
"ui_gold": "আপনার কাছে কতটা সোনা রয়েছে এবং আপনি এটি অর্জন করার হার।",
|
||||
"ui_troops_workers": "সৈন্য এবং কর্মী - বরাদ্দকৃত সৈন্য এবং কর্মীদের পরিমাণ। সৈন্যদের ব্যবহার আক্রমণ বা আক্রমণের বিরুদ্ধে প্রতিরক্ষা করার জন্য করা হয়। কর্মীরা সোনা উৎপাদন করতে ব্যবহৃত হয়। আপনি স্লাইডার ব্যবহার করে সৈন্য এবং কর্মীদের সংখ্যা পরিবর্তন করতে পারেন।",
|
||||
"ui_attack_ratio": "আক্রমণ অনুপাত - আক্রমণ করার সময় আপনি যে সৈন্যদের ব্যবহার করবেন তার পরিমাণ। আপনি স্লাইডারের মাধ্যমে আক্রমণ অনুপাত সামঞ্জস্য করতে পারেন। যদি আপনার আক্রমণকারী সৈন্যদের সংখ্যা প্রতিরক্ষাকারী সৈন্যদের থেকে বেশি হয়, তাহলে আক্রমণে আপনার সৈন্যদের ক্ষতি কম হবে, কিন্তু যদি কম হয়, তবে আপনার আক্রমণকারী সৈন্যদের ক্ষতি বৃদ্ধি পাবে। এই প্রভাব 2:1 অনুপাত বেশি হলে থাকে না।",
|
||||
"ui_options": "সেটিংস",
|
||||
"ui_options_desc": "এখানে নিচের উপাদানগুলি পাওয়া যাবে:",
|
||||
"option_pause": "খেলা থামান/চালু করুন - এটি একক প্লেয়ার মোডে উপলব্ধ।",
|
||||
"option_timer": "ঘড়ি - গেম শুরু হওয়ার পর থেকে অতিবাহিত সময়।",
|
||||
"option_exit": "প্রস্থান বাটন।",
|
||||
"option_settings": "সেটিংস - সেটিংস মেনু খুলুন। ভিতরে আপনি বিকল্প ভিউ, ডার্ক মোড, ইমোজি এবং বাম ক্লিকে ক্রিয়া টগল করতে পারেন।",
|
||||
"radial_title": "বৃত্তাকার মেনু",
|
||||
"radial_desc": "ডান ক্লিক (বা মোবাইলে টাচ) বৃত্তাকার মেনু খোলে। সেখান থেকে আপনি:",
|
||||
"radial_build": "নির্মাণ মেনু খুলুন।",
|
||||
"radial_info": "তথ্য মেনু খুলুন।",
|
||||
"radial_boat": "নির্বাচিত স্থানে আক্রমণ করতে একটি নৌকা পাঠান (শুধুমাত্র যদি আপনার জলে অ্যাক্সেস থাকে)।",
|
||||
"radial_close": "মেনু বন্ধ করুন।",
|
||||
"info_title": "তথ্য মেনু",
|
||||
"info_enemy_desc": "এটি নির্বাচিত খেলোয়াড়ের নাম, সোনা, সৈন্য এবং সে বিশ্বাসঘাতক কিনা সে সম্পর্কে তথ্য দেখায়।\nবিশ্বাসঘাতক সেই খেলোয়াড়, যে তার মিত্র খেলোয়াড়কে বিশ্বাসঘাতকতা করে আক্রমণ করেছে।\nনিচের আইকনগুলো নিম্নলিখিত মিথস্ক্রিয়াগুলোর প্রতিনিধিত্ব করে:",
|
||||
"info_target": "খেলোয়াড়ের উপর একটি লক্ষ্য চিহ্ন রাখুন, সকল মিত্রদের জন্য চিহ্নিত করে, আক্রমণ সমন্বয় করতে ব্যবহৃত হয়।",
|
||||
"info_alliance": "খেলোয়াড়কে একটি মিত্র অনুরোধ পাঠান। মিত্ররা সম্পদ এবং সৈন্য ভাগ করে নিতে পারে, কিন্তু একে অপরকে আক্রমণ করতে পারে না।",
|
||||
"info_emoji": "খেলোয়াড়কে একটি ইমোজি পাঠান।",
|
||||
"info_ally_panel": "মিত্র তথ্য প্যানেল",
|
||||
"info_ally_desc": "যখন আপনি একজন খেলোয়াড়ের সাথে মিত্র হন, নিম্নলিখিত নতুন আইকনগুলি উপলব্ধ হয়:",
|
||||
"ally_betray": "আপনার মিত্রকে বিশ্বাসঘাতকতা করে জোট ভেঙে দিন। এখন আপনার নামের পাশে একটি স্থায়ী চিহ্ন থেকে যাবে, যদি না অন্য রাষ্ট্র নিজেই একজন বিশ্বাসঘাতক হয়ে থাকে। গেম শেষ না হওয়া পর্যন্ত আপনার বিরুদ্ধে আক্রমণে প্রতিপক্ষের ক্ষতি কম হবে। বটগুলি আপনার সঙ্গে জোট বাঁধার সম্ভাবনা কমাবে এবং খেলোয়াড়রাও দ্বিতীয়বার ভাববে।",
|
||||
"ally_donate": "আপনার মিত্রকে আপনার কিছু সৈন্য দান করুন। যখন তাদের সৈন্য কম থাকে আক্রমণ করা হয়, বা যখন তাদের শত্রুকে নিষ্পেষণ করার জন্য সেই অতিরিক্ত শক্তি প্রয়োজন হয় তখন ব্যবহৃত হয়।",
|
||||
"build_menu_title": "নির্মাণ মেনু",
|
||||
"build_name": "নাম",
|
||||
"build_icon": "আইকন",
|
||||
"build_desc": "বিবরণ",
|
||||
"build_city": "শহর",
|
||||
"build_city_desc": "আপনার সর্বাধিক জনসংখ্যা বাড়ায়। যখন আপনি আপনার অঞ্চল বাড়াতে পারেন না বা আপনি আপনার জনসংখ্যার সীমাতে পৌঁছতে যাচ্ছেন তখন উপযোগী।",
|
||||
"build_defense": "প্রতিরক্ষা পোস্ট",
|
||||
"build_defense_desc": "আশেপাশের সীমান্তের চারপাশে প্রতিরক্ষা বাড়ায়। শত্রুদের আক্রমণ ধীরগতির এবং আরও বেশি হতাহত হয়।",
|
||||
"build_port": "বন্দর",
|
||||
"build_port_desc": "আপনার দেশের বন্দর এবং অন্যান্য দেশের মধ্যে স্বয়ংক্রিয়ভাবে বাণিজ্য জাহাজ পাঠায় (যদি না আপনি তাদের 'বাণিজ্য বন্ধ করুন' ক্লিক করেন বা তারা আপনার উপর 'বাণিজ্য বন্ধ করুন' ক্লিক করে), উভয় পক্ষকে সোনা দেয়। যুদ্ধজাহাজ নির্মাণের অনুমতি দেয়। শুধুমাত্র জলের কাছে নির্মাণ করা যাবে।",
|
||||
"build_warship": "যুদ্ধজাহাজ",
|
||||
"build_warship_desc": "একটি এলাকায় টহল দেয়, বাণিজ্যিক জাহাজ দখল করে এবং শত্রুর যুদ্ধজাহাজ ও নৌকা ধ্বংস করে। এটি নিকটতম বন্দর থেকে জন্মায় এবং যেই এলাকায় প্রথমে আপনি এটি তৈরির জন্য ক্লিক করেছিলেন, সেখানেই টহল দেয়। আপনি যুদ্ধজাহাজগুলিকে নিয়ন্ত্রণ করতে পারেন—তাদের উপর আক্রমণ-ক্লিক করুন এবং তারপর যে এলাকায় পাঠাতে চান সেখানে আবার আক্রমণ-ক্লিক করুন।",
|
||||
"build_silo": "মিসাইল সাইলো",
|
||||
"build_silo_desc": "মিসাইল প্রক্ষেপণের অনুমতি দেয়।",
|
||||
"build_sam": "এসএএম লঞ্চার",
|
||||
"build_sam_desc": "এর ১০০ পিক্সেল সীমার মধ্যে শত্রু মিসাইল আটকাতে ৭৫% সম্ভাবনা রয়েছে। এসএএম-এর ৭.৫ সেকেন্ডের কুলডাউন রয়েছে এবং এমআইআরভি আটকাতে পারে না।",
|
||||
"build_atom": "পারমাণবিক বোমা",
|
||||
"build_atom_desc": "ছোট বিস্ফোরক বোমা যা অঞ্চল, ভবন, জাহাজ এবং নৌকা ধ্বংস করে। নিকটতম মিসাইল সাইলো থেকে উদ্ভূত হয় এবং আপনি প্রথমে যে এলাকায় নির্মাণ করতে ক্লিক করেছিলেন সেখানে পড়ে।",
|
||||
"build_hydrogen": "হাইড্রোজেন বোমা",
|
||||
"build_hydrogen_desc": "বড় বিস্ফোরক বোমা। নিকটতম মিসাইল সাইলো থেকে উদ্ভূত হয় এবং আপনি প্রথমে যে এলাকায় নির্মাণ করতে ক্লিক করেছিলেন সেখানে পড়ে।",
|
||||
"build_mirv": "এমআইআরভি",
|
||||
"build_mirv_desc": "গেমের সবচেয়ে শক্তিশালী বোমা। ছোট ছোট বোমায় বিভক্ত হয়ে যায় যা অঞ্চলের একটি বিশাল পরিসর আচ্ছাদন করবে। শুধুমাত্র সেই খেলোয়াড়কে ক্ষতি করে যার উপর আপনি প্রথমে নির্মাণের জন্য ক্লিক করেছিলেন। নিকটতম মিসাইল সাইলো থেকে উদ্ভূত হয় এবং আপনি প্রথমে যে এলাকায় নির্মাণ করতে ক্লিক করেছেন সেখানে পড়ে।",
|
||||
"player_icons": "খেলোয়াড় আইকন",
|
||||
"icon_desc": "আপনি যে কিছু ইনগেম আইকন দেখতে পাবেন এবং সেগুলির অর্থ কী তার কিছু উদাহরণ:",
|
||||
"icon_crown": "মুকুট - এটি লিডারবোর্ডে নম্বর ১ খেলোয়াড়",
|
||||
"icon_traitor": "ক্রস করা তলোয়ার - বিশ্বাসঘাতক। এই খেলোয়াড় একজন মিত্রকে আক্রমণ করেছে।",
|
||||
"icon_ally": "হ্যান্ডশেক - মিত্র। এই খেলোয়াড় আপনার মিত্র।",
|
||||
"info_enemy_panel": "শত্রু তথ্য প্যানেল",
|
||||
"action_emote": "ইমোজি মেনু খুলুন"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "কম্পিউটার মোড",
|
||||
"allow_alliances": "মিত্রতা অনুমতি দিন",
|
||||
"options_title": "বিকল্পসমূহ",
|
||||
"bots": "বট: ",
|
||||
"bots_disabled": "নিষ্ক্রিয়",
|
||||
"disable_nations": "জাতি নিষ্ক্রিয় করুন",
|
||||
"instant_build": "তাৎক্ষণিক নির্মাণ",
|
||||
"infinite_gold": "অসীম সোনা",
|
||||
"infinite_troops": "অসীম সৈন্য",
|
||||
"disable_nukes": "পারমাণবিক অস্ত্র নিষ্ক্রিয় করুন",
|
||||
"start": "গেম শুরু করুন"
|
||||
},
|
||||
"map": {
|
||||
"world": "বিশ্ব",
|
||||
"europe": "ইউরোপ",
|
||||
"mena": "মধ্যপ্রাচ্য",
|
||||
"northamerica": "উত্তর আমেরিকা",
|
||||
"oceania": "ওশেনিয়া",
|
||||
"blacksea": "কালো সাগর",
|
||||
"africa": "আফ্রিকা",
|
||||
"asia": "এশিয়া",
|
||||
"mars": "মঙ্গল",
|
||||
"southamerica": "দক্ষিণ আমেরিকা",
|
||||
"britannia": "ব্রিটানিয়া",
|
||||
"gatewaytotheatlantic": "আটলান্টিকের প্রবেশদ্বার",
|
||||
"australia": "অস্ট্রেলিয়া",
|
||||
"random": "যেকোনো",
|
||||
"iceland": "আইসল্যান্ড",
|
||||
"pangaea": "পাঞ্জিয়া",
|
||||
"map": "মানচিত্র",
|
||||
"betweentwoseas": "দুই সমুদ্রের মধ্যবর্তী অঞ্চল",
|
||||
"japan": "জাপান ও তার পার্শ্ববর্তী অঞ্চল",
|
||||
"knownworld": "পরিচিত পৃথিবী"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "ব্যক্তিগত লবিতে যোগ দিন",
|
||||
"enter_id": "লবি আইডি লিখুন",
|
||||
"player": "খেলোয়াড়",
|
||||
"players": "খেলোয়াড়",
|
||||
"join_lobby": "লবিতে যোগ দিন",
|
||||
"checking": "লবি পরীক্ষা করা হচ্ছে...",
|
||||
"not_found": "লবি পাওয়া যায়নি। আইডি পরীক্ষা করুন এবং আবার চেষ্টা করুন।",
|
||||
"error": "একটি ত্রুটি ঘটেছে। আবার চেষ্টা করুন।",
|
||||
"joined_waiting": "সফলভাবে যোগ দেওয়া হয়েছে! গেম শুরু হওয়ার জন্য অপেক্ষা করছে..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "পরবর্তী গেমে যোগ দিন",
|
||||
"waiting": "খেলোয়াড় অপেক্ষমান"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "আপনার নাম লিখুন",
|
||||
"not_string": "ব্যবহারকারী নাম অবশ্যই একটি অক্ষর হতে হবে।",
|
||||
"too_short": "ব্যবহারকারী নাম অবশ্যই কমপক্ষে {min} অক্ষর দীর্ঘ হতে হবে।",
|
||||
"too_long": "ব্যবহারকারী নাম {max} অক্ষরের বেশি হতে পারবে না।",
|
||||
"invalid_chars": "ব্যবহারকারী নামে শুধুমাত্র অক্ষর, সংখ্যা, স্পেস, আন্ডারস্কোর এবং [বর্গাকার ব্র্যাকেট] থাকতে পারে।"
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "ব্যক্তিগত লবি",
|
||||
"options_title": "বিকল্পসমূহ",
|
||||
"bots": "বট: ",
|
||||
"bots_disabled": "নিষ্ক্রিয়",
|
||||
"disable_nations": "জাতি নিষ্ক্রিয় করুন",
|
||||
"instant_build": "তাৎক্ষণিক নির্মাণ",
|
||||
"infinite_gold": "অসীম সোনা",
|
||||
"infinite_troops": "অসীম সৈন্য",
|
||||
"disable_nukes": "পারমাণবিক অস্ত্র নিষ্ক্রিয় করুন",
|
||||
"player": "খেলোয়াড়",
|
||||
"players": "খেলোয়াড়",
|
||||
"waiting": "খেলোয়াড়দের জন্য অপেক্ষা করছে...",
|
||||
"start": "গেম শুরু করুন",
|
||||
"mode": "মোড"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "সহজ",
|
||||
"Balanced": "মাঝারি",
|
||||
"Intense": "কঠিন",
|
||||
"Impossible": "অসম্ভব",
|
||||
"difficulty": "লেভেল"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "খেলা শুরু হচ্ছে...",
|
||||
"desc": "লবি শুরু হতে প্রস্তুত হচ্ছে। অনুগ্রহ করে অপেক্ষা করুন।"
|
||||
},
|
||||
"lang": {
|
||||
"en": "Bengali",
|
||||
"native": "বাংলা",
|
||||
"svg": "bd",
|
||||
"lang_code": "bn"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "সবাই বনাম সবাই",
|
||||
"teams": "দল"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "ভাষা নির্বাচন করুন"
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
"action_build": "Baumenü öffnen",
|
||||
"action_center": "Karte auf Spieler zentrieren",
|
||||
"action_zoom": "Ansicht vergrößern/verkleinern",
|
||||
"action_move_camera": "Karte verschieben",
|
||||
"action_move_camera": "Kamera bewegen",
|
||||
"action_ratio_change": "Angriffsrate verringern/erhöhen",
|
||||
"action_reset_gfx": "Grafik zurücksetzen",
|
||||
"ui_section": "Spieloberfläche",
|
||||
@@ -28,7 +28,7 @@
|
||||
"ui_pop": "Bevölkerung - Die Anzahl der aktuellen Einheiten, die maximale Bevölkerungszahl und die Geschwindigkeit mit der man neue Einheiten bekommst.",
|
||||
"ui_gold": "Gold - Die aktuelle Menge an Gold, und die Geschwindigkeit mit der man Gold bekommt.",
|
||||
"ui_troops_workers": "Truppen und Arbeiter - Die Menge der zugewiesenen Truppen und Arbeiter. Truppen werden zum Angriff oder zur Verteidigung gegen Angriffe eingesetzt. Arbeiter erzeugen Gold. Die Anzahl der Truppen und Arbeiter kann mit dem Schieberegler eingestellt werden.",
|
||||
"ui_attack_ratio": "Angriffsrate - Die Anzahl der Truppen welche für Angriffe verwendet werden. Die Angriffsrate kann über den Schieberegler eingestellt werden.",
|
||||
"ui_attack_ratio": "Angriffsverhältnis - Die Anzahl der Truppen, die beim Angriff verwendet werden, kann mit dem Schieberegler angepasst werden. Je mehr Truppen beim Angriff verwendet werden desto geringer sind die eigenen Verluste. Während weniger Truppen zu größeren Verlusten führen.\nDieser Effekt geht nicht über das Verhältnis von 2:1 hinaus.",
|
||||
"ui_options": "Optionen",
|
||||
"ui_options_desc": "Die folgenden Schaltflächen sind in den Optionen verfügbar:",
|
||||
"option_pause": "Spiel pausieren/fortsetzen - Nur im Einzelspieler möglich.",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Sendet ein Emoji an den Spieler.",
|
||||
"info_ally_panel": "Bündnis Infobereich",
|
||||
"info_ally_desc": "Wenn man sich mit einem Spieler verbündet werden die folgenden Icons sichtbar:",
|
||||
"ally_betray": "Verrät den Verbündeten, was das Bündnis beendet. Hat eine permanente Markierung als Verräter zur Folge. Bots werden seltener Bündnisse mit Verrätern eingehen und menschliche Spieler sich es zweimal überlegen mit einem Verräter verbündet zu sein.",
|
||||
"ally_betray": "Verrät den Verbündeten, was das Bündnis beendet. Hat eine permanente Markierung als Verräter zur Folge, wenn der Verbündete nicht bereits selbst ein Verräter war. Feindliche Angriffe werden bis zum Ende des Spiels größeren Schaden anrichten. Bots werden seltener Bündnisse mit Verrätern eingehen und menschliche Spieler sich es zweimal überlegen mit einem Verräter verbündet zu sein.",
|
||||
"ally_donate": "Teile einige Truppen mit dem verbündeten Spieler. Kann benutzt werden, um einen angegriffenen Verbündeten mit Truppen zu helfen oder diesem bei einem vernichtenden Schlag gegen einen Feind zu unterstützen.",
|
||||
"build_menu_title": "Baumenü",
|
||||
"build_name": "Name",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Hafen",
|
||||
"build_port_desc": "Sendet automatisch Handelsschiffe zwischen eigenen Häfen und denen anderer Länder (außer es wurde bei oder von einem anderen Spieler \"Handel stoppen\" im Infobereich geklickt), welche Gold für beide Seiten einbringen. Ermöglicht den Bau von Kriegsschiffen. Kann nur in der Nähe von Wasser gebaut werden.",
|
||||
"build_warship": "Kriegsschiff",
|
||||
"build_warship_desc": "Patrouilliert einen Bereich, kapert Handelsschiffe und zerstört befeindete Kriegsschiffe sowie Boote. Erscheint beim nächstgelegenen Hafen und patrouilliert anschließend um den Punkt wo es gebaut wurde.",
|
||||
"build_warship_desc": "Patrouilliert in einem Gebiet und kapert Handelsschiffe, zerstört feindliche Kriegsschiffe und Transportschiffe. Erscheint beim nächstgelegenen Hafen und patrouilliert im Gebiet wo es gebaut wurde. Mit einem Klick auf das Kriegsschiff kann es gesteuert und mit einem weiteren Klick in ein anderes Gebiet geschickt werden.",
|
||||
"build_silo": "Raketensilo",
|
||||
"build_silo_desc": "Ermöglicht das Abfeuern von Raketen und Bomben.",
|
||||
"build_sam": "Flugabwehr",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Krone - Dieser Spieler ist auf Platz 1 der Bestenliste.",
|
||||
"icon_traitor": "Gekreuzte Schwerter - Verräter. Dieser Spieler hat einen Verbündeten verraten und angegriffen.",
|
||||
"icon_ally": "Handschlag - Verbündeter. Dieser Spieler ist ein Verbündeter.",
|
||||
"info_enemy_panel": "Gegner-Infobereich"
|
||||
"info_enemy_panel": "Gegner-Infobereich",
|
||||
"action_emote": "Emote-Menü öffnen"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Einzelspieler",
|
||||
@@ -172,5 +173,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "Free for All",
|
||||
"teams": "Teams"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Sprache auswählen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"host_modal": {
|
||||
"title": "Private Lobby",
|
||||
"mode": "Mode",
|
||||
"team_count": "Number of Teams",
|
||||
"options_title": "Options",
|
||||
"bots": "Bots: ",
|
||||
"bots_disabled": "Disabled",
|
||||
@@ -174,5 +175,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "Free for All",
|
||||
"teams": "Teams"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Select Language"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +1,84 @@
|
||||
{
|
||||
"lang": {
|
||||
"en": "Esperanto",
|
||||
"native": "Esperanto",
|
||||
"svg": "eo",
|
||||
"lang_code": "eo"
|
||||
},
|
||||
"main": {
|
||||
"join_discord": "Kunigu la Discord-servilon !",
|
||||
"create_lobby": "Krei salonon",
|
||||
"join_lobby": "Kunigi salonon",
|
||||
"single_player": "Ludi solan",
|
||||
"instructions": "Instruadoj",
|
||||
"how_to_play": "Kiel ludi ?",
|
||||
"single_player": "Sola Ludanto",
|
||||
"instructions": "Instrukcioj",
|
||||
"how_to_play": "Kiel ludi",
|
||||
"wiki": "Vikio"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Agklavoj",
|
||||
"hotkeys": "Rapidklavoj",
|
||||
"table_key": "Klavo",
|
||||
"table_action": "Influo",
|
||||
"action_alt_view": "Alternativa vido (tereno/lando)",
|
||||
"action_attack_altclick": "Ataki (kiam la maldekstra klako estas formi por malfermi la menuon)",
|
||||
"action_build": "Malfermi la konstruan menuon",
|
||||
"action_center": "Reenfokusigi la fotilon",
|
||||
"action_center": "Recentrigi la kameraon sur la ludanto",
|
||||
"action_zoom": "Zomi",
|
||||
"action_move_camera": "Movi la fotilon",
|
||||
"action_move_camera": "Moviĝi kameraon",
|
||||
"action_ratio_change": "Malgrandigi/Pligrandigi la atakan kvocienton",
|
||||
"action_reset_gfx": "Restarigi la grafismoj",
|
||||
"ui_section": "Ludo uzantinterfaco",
|
||||
"ui_leaderboard": "Ordigo",
|
||||
"ui_leaderboard": "Ĉampionejo",
|
||||
"ui_leaderboard_desc": "Afiŝas la plej bonajn ludantojn kun iliaj nomoj, la % de la poseda teritorio kaj la oro.",
|
||||
"ui_control": "Kontrolpanelo",
|
||||
"ui_control_desc": "La kontrolpanelo enhavas la sekvajn elementojn :",
|
||||
"ui_pop": "Pop - La nombro de trupunoj ke vi havas, via maximuma populado kaj la procento kun kiu vi recivas ilin.",
|
||||
"ui_gold": "Oro - La kvanto da oro ke vi havas kaj la procento kun kiu vi recivas ilin.",
|
||||
"ui_control_desc": "La kontrolpanelo enhavas la sekvajn elementojn:",
|
||||
"ui_pop": "Pop - La nombro de trupunoj ke vi havas, via maksimuma populacio kaj la procento kun kiu vi ricevas ilin.",
|
||||
"ui_gold": "La kvanto da oro ke vi havas kaj la procento kun kiu vi ricevas ilin.",
|
||||
"ui_troops_workers": "Trupoj kaj Laboristoj - La nombro da soldatoj kaj laboristoj asignitaj. Trupoj kutimas ataki aŭ defendi. Laboristoj kutimas generi oron. Vi povas ĝustigi la nombron da trupoj kaj laboristoj uzante la glitilon.",
|
||||
"ui_attack_ratio": "Ataka kvociento - La nombro da uzaj soldatoj kiam vi atakas. Vi povas ĝustigi la atakan kvocienton uzante la glitilon",
|
||||
"ui_attack_ratio": "Ataka kvociento - La nombro da uzaj soldatoj kiam vi atakas. Vi povas ĝustigi la atakan kvocienton uzante la glitilon. Havi pli da atakaj trupoj ol la defendaj trupoj malpliigos la perdojn dum atako, dum havi malpli multe pliigos la damaĝon ricevitajn de viaj atakaj trupoj. La efiko ne superas rilatumon de 2:1.",
|
||||
"ui_options": "Opcioj",
|
||||
"ui_options_desc": "La sekvaj elementoj povas esti trovigita interne :",
|
||||
"option_pause": "Paŭzigi/Rekomenci la ludon - Nur elbla en la solan modo",
|
||||
"option_timer": "Kronometro - Pasinta tempo écoulé ekde la luda komenco.",
|
||||
"ui_options_desc": "La sekvaj elementoj povas esti trovigita interne:",
|
||||
"option_pause": "Paŭzigi/Rekomenci la ludon - Nur ebla en la solan modo.",
|
||||
"option_timer": "Kronometro - Pasinta tempo ekde la luda komenco.",
|
||||
"option_exit": "Elira butono",
|
||||
"option_settings": "Parametroj - Malfermi la parametran menuon. Vi povas aktivi la ous pouvez y eblegi la alterna vido, la malhela reĝimo, la emoĝioj kaj la maldekstra alklaku ago.",
|
||||
"option_settings": "Parametroj - Malfermi la parametran menuon. Vi povas aktivi la alterna vido, la malhela reĝimo, la emoĝioj kaj la maldekstra alklako.",
|
||||
"radial_title": "Radia menuo",
|
||||
"radial_desc": "Dekstra klako (aŭ tuŝo sur poŝtelefono) malfermas la radian menuon. De tie, vi povas:",
|
||||
"radial_build": "Malfermi la konstrumenuon.",
|
||||
"radial_info": "Malfermi la informmenuon.",
|
||||
"radial_boat": "Sendi boaton por ataki ĉe la elektita loko (disponebla nur se vi havas aliron al akvo).",
|
||||
"radial_close": "Fermi la menuon."
|
||||
"radial_close": "Fermi la menuon.",
|
||||
"info_title": "Informmenuo",
|
||||
"info_enemy_desc": "Enhavas informojn kiel la nomon de la elektita ludanto, la oron, la trupojn, kaj ĉu la ludanto estas perfidulo. Perfidulo estas ludanto, kiu perfidis kaj atakis alian ludanton kun kiu li estis en alianco. La subaj piktogramoj reprezentas la jenajn interagojn:",
|
||||
"info_target": "Meti celmarkon sur la ludanton, videblan por ĉiuj aliancanoj, uzata por kunordigi atakojn.",
|
||||
"info_alliance": "Sendi aliancpeton al la ludanto. Aliancanoj povas dividi rimedojn kaj trupojn, sed ne povas ataki unu la alian.",
|
||||
"info_emoji": "Sendi emoji al la ludanto."
|
||||
"info_emoji": "Sendi emoĝioj al la ludanto.",
|
||||
"info_ally_panel": "Aliancana informpanelo",
|
||||
"info_ally_desc": "Kiam vi alianciĝas kun ludanto, la jenaj novaj piktogramoj fariĝas disponeblaj:",
|
||||
"ally_betray": "Perfidi aliancanon, finante la aliancon. Vi tiam havos konstantan ikonon apud via nomo. La robotoj malpli verŝajne alianciĝos kun vi, kaj ludantoj, al kiuj vi petos aliancon, pli atente pripensos.",
|
||||
"ally_donate": "Doni parton de viaj trupoj al aliancano. Uzata kiam ili mankas da trupoj kaj estas atakataj, aŭ kiam ili bezonas kroman potencon por venki malamikon."
|
||||
"ally_betray": "Kronometro - Pasinta tempo ekde la luda komenco.",
|
||||
"ally_donate": "Doni parton de viaj trupoj al aliancano. Uzata kiam ili mankas da trupoj kaj estas atakataj, aŭ kiam ili bezonas kroman potencon por venki malamikon.",
|
||||
"build_menu_title": "Konstrua menuo",
|
||||
"build_name": "Nomo",
|
||||
"build_icon": "Ikono",
|
||||
"build_desc": "Priskribo"
|
||||
"build_desc": "Priskribo",
|
||||
"build_city": "Urbo",
|
||||
"build_city_desc": "Utila kiam vi ne povas pligrandigi vian teritorion aŭ kiam vi atingas vian loĝlimon.",
|
||||
"build_city_desc": "Utila kiam vi ne povas pligrandigi vian teritorion aŭ kiam vi atingas vian loĝantlimon.",
|
||||
"build_defense": "Defenda posteno",
|
||||
"build_defense_desc": "Plifortigas la defendojn ĉirkaŭ proksimaj limoj. Malamikaj atakoj fariĝas pli malrapidaj kaj kaŭzas pli da perdoj.",
|
||||
"build_port": "Haveno",
|
||||
"build_port_desc": "Aŭtomate sendas komercajn ŝipojn de viaj havenoj al aliaj landoj (krom se vi elektis 'ĉesi komercon' kun ludanto, aŭ se ili faris same kun vi), donante oron al ambaŭ flankoj. Permesas konstrui militŝipojn. Povas esti konstruita nur proksime de akvo.",
|
||||
"build_port_desc": "Aŭtomate sendas komercŝipojn inter la havenoj de via lando kaj aliaj landoj (krom se vi alklakis \"ĉesi komerco\" kun ili aŭ ili alklakis \"ĉesi komerco\" kun vi), donante oron al ambaŭ flankoj. Permesas konstrui batalŝipojn. Eblas konstrui nur proksime de akvo.",
|
||||
"build_warship": "Militŝipo",
|
||||
"build_warship_desc": "Patrolas en areo, kaptante komercajn ŝipojn kaj detruante militŝipojn kaj malamikajn boatojn. Aperas en la plej proksima haveno kaj patrolas la elektitan areon.",
|
||||
"build_warship_desc": "Patroloj en areo, kaptante komercajn ŝipojn kaj detruante militŝipojn kaj malamikajn boatojn. Aperas en la plej proksima haveno kaj patrolas la elektita areo.",
|
||||
"build_silo": "Misila silo",
|
||||
"build_silo_desc": "Ebligas lanĉi misilojn.",
|
||||
"build_sam": "SAM-lanĉilo",
|
||||
"build_sam_desc": "Havas 75 % da ŝanco interkapti malamikajn misilojn ene de sia 100-piksela atingo. La SAM havas reŝarĝotempon de 7,5 sekundoj kaj ne povas interkapti MIRV-ojn.",
|
||||
"build_sam_desc": "Havas 75 % da ŝanco interkapti malamikajn misilojn ene de sia 100-piksela atingo. La SAM havas reŝarĝa tempon de 7,5 sekundoj kaj ne povas interkapti MIRV-ojn.",
|
||||
"build_atom": "Atombombo",
|
||||
"build_atom_desc": "Eta eksploda bombo kiu detruas teritorion, konstruaĵojn, ŝipojn kaj boatojn. Aperas el la plej proksima Misila silo kaj atingas la elektitan areon.",
|
||||
"build_hydrogen": "Hidrogenbombo",
|
||||
"build_hydrogen_desc": "Granda eksploda bombo. Aperas el la plej proksima Misila silo kaj atingas la elektitan areon.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "La plej potenca bombo en la ludo. Dividiĝas en pli malgrandajn bombojn kiuj kovros vastan teritorion. Damaĝas nur la ludanton, kontraŭ kiu vi celis ĝin. Aperas el la plej proksima Misila silo kaj atingas la elektitan areon."
|
||||
"build_mirv_desc": "La plej potenca bombo en la ludo. Dividiĝas en pli malgrandajn bombojn kiuj kovros vastan teritorion. Damaĝas nur la ludanton, kontraŭ kiu vi celis ĝin. Aperas el la plej proksima Misila silo kaj atingas la elektitan areon.",
|
||||
"player_icons": "Ludantaj Ikonoj",
|
||||
"icon_desc": "Ekzemploj de iuj ludikonoj, kiujn vi renkontos, kaj ilia signifo:",
|
||||
"icon_crown": "Krono - Ĉi tiu ludanto estas numero 1 en la ranglisto.",
|
||||
"icon_desc": "Ekzemploj de iuj ludaj ikonoj, kiujn vi renkontos, kaj ilia signifo:",
|
||||
"icon_crown": "Krono - Ĉi tiu ludanto estas numero 1 en la ranglisto",
|
||||
"icon_traitor": "Krucitaj glavoj - Perfida. Ĉi tiu ludanto atakis aliancanon.",
|
||||
"icon_ally": "Manpremo - Aliancano. Ĉi tiu ludanto estas via aliancano."
|
||||
"icon_ally": "Manpremo - Aliancano. Ĉi tiu ludanto estas via aliancano.",
|
||||
"info_enemy_panel": "Malamiko informpanelo",
|
||||
"action_emote": "Malfermi miensimbolan menuon"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Sola Ludanto",
|
||||
@@ -98,10 +94,9 @@
|
||||
"start": "Komenci la ludon"
|
||||
},
|
||||
"map": {
|
||||
"map": "Mapo",
|
||||
"world": "Mondo",
|
||||
"europe": "Eŭropo",
|
||||
"mena": "MENA",
|
||||
"mena": "Mezoriento kaj Nordafriko",
|
||||
"northamerica": "Nordameriko",
|
||||
"oceania": "Oceanio",
|
||||
"blacksea": "Nigra Maro",
|
||||
@@ -112,8 +107,13 @@
|
||||
"britannia": "Granda Britio",
|
||||
"gatewaytotheatlantic": "Pordo al Atlantiko",
|
||||
"australia": "Aŭstralio",
|
||||
"random": "Hazarda",
|
||||
"iceland": "Islando",
|
||||
"random": "Hazarda"
|
||||
"pangaea": "Pangeo",
|
||||
"map": "Karto",
|
||||
"betweentwoseas": "Inter du maroj",
|
||||
"japan": "Japanio kaj najbaroj",
|
||||
"knownworld": "Konata Mondo"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Aliĝi al privata salono",
|
||||
@@ -124,11 +124,11 @@
|
||||
"checking": "Kontrolado de la salono...",
|
||||
"not_found": "Salono ne trovita. Bonvolu kontroli la ID kaj reprovi.",
|
||||
"error": "Eraro okazis. Bonvolu reprovi.",
|
||||
"joined_waiting": "Sukcese aliĝite! Atendante la komencon de la ludo..."
|
||||
"joined_waiting": "Sukcese aliĝis! Atendante la komencon de la ludo..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "Kunigi la baldaŭa ludo",
|
||||
"waiting": "Atendante ludantoj"
|
||||
"join": "Kunigi la baldaŭan ludon",
|
||||
"waiting": "atendante ludantoj"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "Enigu vian uzantnomon",
|
||||
@@ -143,20 +143,38 @@
|
||||
"bots": "Robotoj :",
|
||||
"bots_disabled": "Malŝaltita",
|
||||
"disable_nations": "Malŝalti naciojn",
|
||||
"instant_build": "Imposta Konstruado",
|
||||
"instant_build": "Tujkonstruaĵo",
|
||||
"infinite_gold": "Senfina oro",
|
||||
"infinite_troops": "Senfinaj trupoj",
|
||||
"disable_nukes": "Malŝalti nukleajn armilojn",
|
||||
"player": "Ludanto",
|
||||
"players": "Ludantoj",
|
||||
"waiting": "Atendante ludantojn...",
|
||||
"start": "Komenci la ludon"
|
||||
"start": "Komenci la ludon",
|
||||
"mode": "Reĝimo"
|
||||
},
|
||||
"difficulty": {
|
||||
"difficulty": "Malfacileco",
|
||||
"Relaxed": "Relaksa",
|
||||
"Relaxed": "Senstreĉa",
|
||||
"Balanced": "Ekvilibriga",
|
||||
"Intense": "Intensa",
|
||||
"Impossible": "Neebla"
|
||||
"Impossible": "Neebla",
|
||||
"difficulty": "Malfacileco"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "Ludo komenciĝas...",
|
||||
"desc": "Preparante por komenci la salonon. Bonvolu atendi."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Esperanto",
|
||||
"native": "Esperanto",
|
||||
"svg": "eo",
|
||||
"lang_code": "eo"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Senpaga por ĉiuj",
|
||||
"teams": "Teamoj"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Elekti lingvon"
|
||||
}
|
||||
}
|
||||
@@ -1,83 +1,67 @@
|
||||
{
|
||||
"lang": {
|
||||
"en": "French",
|
||||
"native": "Français",
|
||||
"svg": "fr",
|
||||
"lang_code": "fr"
|
||||
},
|
||||
"main": {
|
||||
"join_discord": "Rejoignez le Discord !",
|
||||
"create_lobby": "Créer un Salon",
|
||||
"join_lobby": "Rejoindre un Salon",
|
||||
"single_player": "Jouer seul",
|
||||
"join_discord": "Rejoignez le Discord!",
|
||||
"create_lobby": "Créer un salon",
|
||||
"join_lobby": "Rejoindre un salon",
|
||||
"single_player": "Mode solo",
|
||||
"instructions": "Instructions",
|
||||
"how_to_play": "Comment jouer ?",
|
||||
"wiki": "Wiki"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Raccourcis clavier",
|
||||
|
||||
"table_key": "Touche",
|
||||
|
||||
"table_action": "Action",
|
||||
|
||||
"action_alt_view": "Vue alternative (terrain/pays)",
|
||||
"action_attack_altclick": "Attaquer (quand le clic gauche est configuré pour ouvrir le menu)",
|
||||
"action_build": "Ouvrir le menu de construction",
|
||||
"action_center": "Recentrer la caméra",
|
||||
"action_zoom": "Zoom avant/arrière",
|
||||
"action_zoom": "Zoomer/Dézoomer",
|
||||
"action_move_camera": "Déplacer la caméra",
|
||||
"action_ratio_change": "Diminuer/Augmenter le ratio d'attaque",
|
||||
"action_reset_gfx": "Réinitialiser les graphismes",
|
||||
|
||||
"ui_section": "Interface utilisateur du jeu",
|
||||
"ui_section": "IU du jeu",
|
||||
"ui_leaderboard": "Classement",
|
||||
"ui_leaderboard_desc": "Affiche les meilleurs joueurs du jeu avec leurs noms, le % de territoire possédé et l'or.",
|
||||
"ui_leaderboard_desc": "Montre les meilleurs joueurs de la partie, % de territoire possédé et or.",
|
||||
"ui_control": "Panneau de contrôle",
|
||||
"ui_control_desc": "Le panneau de contrôle contient les éléments suivants :",
|
||||
"ui_pop": "Pop - Le nombre d'unités que vous avez, votre population maximale et le taux auquel vous les obtenez.",
|
||||
"ui_gold": "Or - La quantité d'or que vous avez et le taux auquel vous l'obtenez.",
|
||||
"ui_troops_workers": "Troupes et Ouvriers - Le nombre de troupes et d'ouvriers alloués. Les troupes sont utilisées pour attaquer ou se défendre. Les ouvriers sont utilisés pour générer de l'or. Vous pouvez ajuster le nombre de troupes et d'ouvriers en utilisant le curseur.",
|
||||
"ui_attack_ratio": "Ratio d'attaque - Le nombre de troupes qui seront utilisées lorsque vous attaquez. Vous pouvez ajuster le ratio d'attaque en utilisant le curseur.",
|
||||
|
||||
"ui_pop": "Pop - Le nombre d'unités que vous avez, votre population max et la vitesse à laquelle vous les gagnez.",
|
||||
"ui_gold": "Or - La quantité d'or que vous avez et la vitesse à laquelle vous en gagnez.",
|
||||
"ui_troops_workers": "Troupes et Travailleurs - Le nombre de troupes et de travailleurs alloués. Les troupes sont utilisées pour attaquer ou défendre contre les attaques. Les travailleurs sont utilisés pour générer de l'or. Vous pouvez ajuster le nombre de troupes et de travailleurs en utilisant le curseur.",
|
||||
"ui_attack_ratio": "Ratio d'attaque - La quantité de troupes qui seront utilisées lors de votre attaque. Vous pouvez ajuster le ratio d'attaque en utilisant le curseur. Avoir plus de troupes attaquantes que défensives vous fera perdre moins de troupes dans l'attaque, quand en avoir moins va augmenter les dommages infligés à vos troupes attaquantes. L'effet ne dépasse pas le ratio de 2:1.",
|
||||
"ui_options": "Options",
|
||||
"ui_options_desc": "Les éléments suivants peuvent être trouvés à l'intérieur :",
|
||||
"option_pause": "Mettre en pause/Reprendre le jeu - Disponible uniquement en mode solo.",
|
||||
"option_pause": "Mettre en pause/Continuer la partie - Disponible uniquement dans le mode solo.",
|
||||
"option_timer": "Chronomètre - Temps écoulé depuis le début du jeu.",
|
||||
"option_exit": "Bouton de sortie.",
|
||||
"option_settings": "Paramètres - Ouvrir le menu des paramètres. Vous pouvez y activer la Vue Alternative, le Mode Sombre, les Emojis et l'action sur le clic gauche.",
|
||||
|
||||
"option_settings": "Paramètres - Ouvrir le menu des paramètres. Vous pouvez y activer la Vue Alternative, le Mode Sombre, les Émojis et l'action sur le clic gauche.",
|
||||
"radial_title": "Menu radial",
|
||||
"radial_desc": "Un clic droit (ou un toucher sur mobile) ouvre le menu radial. De là, vous pouvez :",
|
||||
"radial_desc": "Un clic droit (ou un appui sur mobile) ouvre le menu radial. De là, vous pouvez :",
|
||||
"radial_build": "Ouvrir le menu de construction.",
|
||||
"radial_info": "Ouvrir le menu d'informations.",
|
||||
"radial_boat": "Envoyer un bateau pour attaquer à l'emplacement sélectionné (disponible uniquement si vous avez accès à l'eau).",
|
||||
"radial_close": "Fermer le menu.",
|
||||
|
||||
"info_title": "Menu d'informations",
|
||||
"info_enemy_desc": "Contient des informations telles que le nom du joueur sélectionné, l'or, les troupes, et si le joueur est un traître. Un traître est un joueur qui a trahi et attaqué un joueur qui était en alliance avec lui. Les icônes ci-dessous représentent les interactions suivantes :",
|
||||
"info_enemy_desc": "Contient des informations telles que le nom du joueur sélectionné, l'or, les troupes et si le joueur est un traître. Un traître est un joueur qui a trahi et attaqué un joueur allié. Les icônes ci-dessous représentent les interactions suivantes :",
|
||||
"info_target": "Placer une marque cible sur le joueur, le marquant pour tous les alliés, utilisée pour coordonner les attaques.",
|
||||
"info_alliance": "Envoyer une demande d'alliance au joueur. Les alliés peuvent partager des ressources et des troupes, mais ne peuvent pas s'attaquer entre eux.",
|
||||
"info_emoji": "Envoyer un emoji au joueur.",
|
||||
|
||||
"info_emoji": "Envoyer un émoji au joueur.",
|
||||
"info_ally_panel": "Panneau d'informations des alliés",
|
||||
"info_ally_desc": "Lorsque vous vous alliez avec un joueur, les nouvelles icônes suivantes deviennent disponibles :",
|
||||
"ally_betray": "Trahir un allié, mettant fin à l'alliance. Vous aurez alors une icône permanente à côté de votre nom. Les bots seront moins susceptibles de s'allier avec vous et les joueurs, à qui vous demanderez alliance feront plus attention.",
|
||||
"info_ally_desc": "Lorsque vous vous alliez à un joueur, les nouvelles icônes suivantes deviennent disponibles :",
|
||||
"ally_betray": "Trahir son allié, mettant fin à l'alliance. Vous aurez désormais une icône permanente apposée à votre nom, à moins que l'autre nation soit aussi un traître. Les attaques contre vous entraîneront moins de pertes pour l'attaquant jusqu'à la fin de la partie, les bots sont moins susceptibles de s'allier à vous et les joueurs y réfléchirons à deux fois.",
|
||||
"ally_donate": "Donner une partie de vos troupes à un allié. Utilisé lorsqu'ils manquent de troupes et sont attaqués, ou lorsqu'ils ont besoin de puissance supplémentaire pour écraser un ennemi.",
|
||||
|
||||
"build_menu_title": "Menu de construction",
|
||||
"build_name": "Nom",
|
||||
"build_icon": "Icône",
|
||||
"build_desc": "Description",
|
||||
|
||||
"build_city": "Ville",
|
||||
"build_city_desc": "Utile quand vous ne pouvez pas agrandir votre territoire ou quand vous atteignez votre limite de population.",
|
||||
"build_city_desc": "Utile quand vous ne pouvez agrandir votre territoire ou quand vous atteignez votre limite de population.",
|
||||
"build_defense": "Poste de défense",
|
||||
"build_defense_desc": "Augmente les défenses autour des frontières proches. Les attaques des ennemis sont plus lentes et causent plus de pertes.",
|
||||
"build_port": "Port",
|
||||
"build_port_desc": "Envoie automatiquement des navires marchands en partant de vos ports vers d'autres pays (sauf si vous avez cliqué sur \"arrêter le commerce\" sur un joueur, ou s'ils ont cliqué sur \"arrêter le commerce\" sur vous), donnant de l'or aux deux côtés. Permet de construire des navires de guerre. Ne peut être construit qu'à proximité de l'eau.",
|
||||
"build_warship": "Navire de guerre",
|
||||
"build_warship_desc": "Patrouille dans une zone, capturant des navires marchands et détruisant des navires de guerre et des bateaux ennemis. Apparaît dans le port le plus proche et patrouille dans la zone cliquée.",
|
||||
"build_warship_desc": "Patrouille dans une zone, capturant des navires commerciaux et détruisant des navires de guerre et des bateaux ennemis. Fait apparaître depuis le Port le plus proche et patrouille la zone que vous avez cliquée pour le construire. Vous pouvez contrôler les vaisseaux de guerre en cliquant sur eux, puis en cliquant sur la nouvelle zone dans laquelle vous voulez les déplacer.",
|
||||
"build_silo": "Silo à missiles",
|
||||
"build_silo_desc": "Permet de lancer des missiles.",
|
||||
"build_sam": "Lanceur SAM",
|
||||
@@ -85,15 +69,16 @@
|
||||
"build_atom": "Bombe atomique",
|
||||
"build_atom_desc": "Petite bombe explosive qui détruit le territoire, les bâtiments, les navires et les bateaux. Apparaît depuis le Silo à missiles le plus proche et atterrit dans la zone cliquée.",
|
||||
"build_hydrogen": "Bombe à hydrogène",
|
||||
"build_hydrogen_desc": "Grande bombe explosive. Apparaît depuis le Silo à missiles le plus proche et atterrit dans la zone cliquée.",
|
||||
"build_hydrogen_desc": "Grande bombe explosive. Apparaît depuis le Silo à Missiles le plus proche et atterrit dans la zone cliquée.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "La bombe la plus puissante du jeu. Se divise en plus petites bombes qui couvriront une vaste zone de territoire. Ne fait des dégâts qu'au joueur sur lequel vous avez cliqué pour la construire. Apparaît depuis le Silo à missiles le plus proche et atterrit dans la zone cliquée.",
|
||||
|
||||
"build_mirv_desc": "La bombe la plus puissante du jeu. Se divise en plus petites bombes qui couvriront une vaste zone du territoire. Ne fait des dégâts qu'au joueur sur lequel vous avez cliqué pour la construire. Apparaît depuis le Silo à missiles le plus proche et atterrit dans la zone cliquée.",
|
||||
"player_icons": "Icônes des joueurs",
|
||||
"icon_desc": "Exemples de certaines icônes du jeu que vous rencontrerez et leur signification :",
|
||||
"icon_crown": "Couronne - Ce joueur est le numéro 1 du classement",
|
||||
"icon_traitor": "Épées croisées - Traître. Ce joueur a attaqué un allié.",
|
||||
"icon_ally": "Poignée de main - Allié. Ce joueur est votre allié."
|
||||
"icon_ally": "Poignée de main - Allié. Ce joueur est votre allié.",
|
||||
"info_enemy_panel": "Panneau d'information de l'ennemi",
|
||||
"action_emote": "Ouvrir le menu des émojis"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Joueur seul",
|
||||
@@ -109,10 +94,9 @@
|
||||
"start": "Commencer la partie"
|
||||
},
|
||||
"map": {
|
||||
"map": "Carte",
|
||||
"world": "Monde",
|
||||
"europe": "Europe",
|
||||
"mena": "MENA",
|
||||
"mena": "MOAN",
|
||||
"northamerica": "Amérique du Nord",
|
||||
"oceania": "Océanie",
|
||||
"blacksea": "Mer Noire",
|
||||
@@ -120,11 +104,16 @@
|
||||
"asia": "Asie",
|
||||
"mars": "Mars",
|
||||
"southamerica": "Amérique du Sud",
|
||||
"britannia": " Grande-Bretagne",
|
||||
"britannia": "Grande-Bretagne",
|
||||
"gatewaytotheatlantic": "Porte de l'Atlantique",
|
||||
"australia": "Australie",
|
||||
"random": "Aléatoire",
|
||||
"iceland": "Islande",
|
||||
"random": "Aléatoire"
|
||||
"pangaea": "Pangée",
|
||||
"map": "Carte",
|
||||
"betweentwoseas": "Entre deux mers",
|
||||
"japan": "Japon et pays voisins",
|
||||
"knownworld": "Monde connu"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Rejoindre un salon privé",
|
||||
@@ -150,7 +139,7 @@
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "Salon privé",
|
||||
"options_title": "Options",
|
||||
"options_title": "Paramètres",
|
||||
"bots": "Bots : ",
|
||||
"bots_disabled": "Désactivé",
|
||||
"disable_nations": "Désactiver les nations",
|
||||
@@ -161,13 +150,31 @@
|
||||
"player": "Joueur",
|
||||
"players": "Joueurs",
|
||||
"waiting": "En attente de joueurs...",
|
||||
"start": "Commencer la partie"
|
||||
"start": "Commencer la partie",
|
||||
"mode": "Mode"
|
||||
},
|
||||
"difficulty": {
|
||||
"difficulty": "Difficulté",
|
||||
"Relaxed": "Détendu",
|
||||
"Balanced": "Équilibré",
|
||||
"Intense": "Intense",
|
||||
"Impossible": "Impossible"
|
||||
"Impossible": "Impossible",
|
||||
"difficulty": "Difficulté"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "La partie est en train de commencer...",
|
||||
"desc": "Préparation du salon. Veuillez patienter."
|
||||
},
|
||||
"lang": {
|
||||
"en": "French",
|
||||
"native": "Français",
|
||||
"svg": "fr",
|
||||
"lang_code": "fr"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Chacun pour soi",
|
||||
"teams": "Équipes"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Sélectionner une langue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "Discord से जुड़ें!",
|
||||
"create_lobby": "लॉबी बनाएं",
|
||||
"join_lobby": "लॉबी में शामिल हों",
|
||||
"single_player": "कंप्यूटर मोड",
|
||||
"instructions": "निर्देश",
|
||||
"how_to_play": "कैसे खेलें",
|
||||
"wiki": "विकी"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "हट की]",
|
||||
"table_key": "Key",
|
||||
"table_action": "कार्य",
|
||||
"action_alt_view": "वैकल्पिक दृश्य (भूगोल/देश)",
|
||||
"action_attack_altclick": "हमला (जब बाएं क्लिक को मेनू खोलने के लिए सेट किया गया हो)",
|
||||
"action_build": "निर्माण मेनू खोलें",
|
||||
"action_center": "कैमरा खिलाड़ी पर फोकस करें",
|
||||
"action_zoom": "जूम आउट/इन करें",
|
||||
"action_move_camera": "कैमरा हिलाएं",
|
||||
"action_ratio_change": "आक्रमण अनुपात घटाएं/वृद्धि करें",
|
||||
"action_reset_gfx": "ग्राफिक्स को रीसेट करें",
|
||||
"ui_section": "Game UI",
|
||||
"ui_leaderboard": "लीडरबोर्ड",
|
||||
"ui_leaderboard_desc": "खेल के शीर्ष खिलाड़ियों और उनके नाम, स्वामित्व वाली ज़मीन और सोने का प्रतिशत दिखाता है।",
|
||||
"ui_control": "नियंत्रण पैनल",
|
||||
"ui_control_desc": "नियंत्रण पैनल में निम्नलिखित तत्व होते हैं:",
|
||||
"ui_pop": "आपके पास कितनी इकाइयाँ हैं, आपका अधिकतम जनसंख्या और उन्हें प्राप्त करने की दर।",
|
||||
"ui_gold": "आपके पास कितने सोने हैं और इसे अर्जित करने की दर।",
|
||||
"ui_troops_workers": "सैनिक और श्रमिक - आवंटित सैनिकों और श्रमिकों की संख्या। सैनिकों का उपयोग हमले करने या हमलों से बचाव के लिए किया जाता है। श्रमिकों का उपयोग सोना उत्पन्न करने के लिए किया जाता है। आप स्लाइडर का उपयोग करके सैनिकों और श्रमिकों की संख्या को समायोजित कर सकते हैं।",
|
||||
"ui_attack_ratio": "आक्रमण अनुपात - वह संख्या जो आपके द्वारा आक्रमण करते समय सैनिकों का उपयोग किया जाएगा। आप स्लाइडर का उपयोग करके आक्रमण अनुपात को समायोजित कर सकते हैं। यदि आपके पास बचाव करने वाले सैनिकों की तुलना में अधिक आक्रमणकारी सैनिक हैं, तो आपको आक्रमण में कम सैनिकों का नुकसान होगा, जबकि कम सैनिकों के होने से आपके आक्रमणकारी सैनिकों को अधिक नुकसान होगा। प्रभाव 2:1 के अनुपात से आगे नहीं बढ़ता।",
|
||||
"ui_options": "सेटिंग्स",
|
||||
"ui_options_desc": "निम्नलिखित तत्व अंदर पाए जा सकते हैं:",
|
||||
"option_pause": "खेल को विरामित करें/विराम हटाएं - यह केवल एकल खिलाड़ी मोड में उपलब्ध है।",
|
||||
"option_timer": "घड़ी - गेम शुरू होने के बाद का समय।",
|
||||
"option_exit": "बाहर निकलें बटन।",
|
||||
"option_settings": "सेटिंग्स - सेटिंग्स मेनू खोलें। इसमें आप वैकल्पिक दृश्य, डार्क मोड, इमोजी और बायाँ क्लिक पर क्रिया टॉगल कर सकते हैं।",
|
||||
"radial_title": "रेडियल मेनू",
|
||||
"radial_desc": "राइट क्लिक (या मोबाइल पर टच) से रेडियल मेनू खुलता है। यहां से आप:",
|
||||
"radial_build": "निर्माण मेनू खोल सकते हैं।",
|
||||
"radial_info": "जानकारी मेनू खोल सकते हैं।",
|
||||
"radial_boat": "चयनित स्थान पर हमला करने के लिए नाव भेज सकते हैं (केवल यदि आपके पास पानी तक पहुंच हो)।",
|
||||
"radial_close": "मेनू बंद कर सकते हैं।",
|
||||
"info_title": "जानकारी मेनू",
|
||||
"info_enemy_desc": "इसमें चुने गए खिलाड़ी का नाम, सोना, सेना और वह गद्दार है या नहीं, इस बारे में जानकारी होती है।\nगद्दार वह खिलाड़ी होता है जिसने अपने साथ गठबंधन में रहे किसी खिलाड़ी को धोखा दिया और उस पर हमला किया।\nनीचे दिए गए आइकन निम्नलिखित क्रियाओं का प्रतिनिधित्व करते हैं:",
|
||||
"info_target": "खिलाड़ी पर निशाना लगाएं, सभी सहयोगियों के लिए चिह्नित करें, हमलों को समन्वित करने के लिए उपयोगी।",
|
||||
"info_alliance": "खिलाड़ी को सहयोग अनुरोध भेजें। सहयोगी संसाधन और सैनिक साझा कर सकते हैं, लेकिन एक-दूसरे पर हमला नहीं कर सकते।",
|
||||
"info_emoji": "खिलाड़ी को इमोजी भेजें।",
|
||||
"info_ally_panel": "सहयोगी जानकारी पैनल",
|
||||
"info_ally_desc": "जब आप किसी खिलाड़ी के साथ सहयोग करते हैं, निम्नलिखित नए आइकन उपलब्ध होते हैं:",
|
||||
"ally_betray": "अपने सहयोगी से विश्वासघात करें और गठबंधन समाप्त करें। अब आपके नाम के पास एक स्थायी चिन्ह जुड़ जाएगा, जब तक कि दूसरी राष्ट्र ने पहले धोखा न दिया हो। अब आप पर हमलों में दुश्मन को कम नुकसान होगा, और यह प्रभाव पूरे गेम तक बना रहेगा। बॉट्स आपके साथ गठबंधन करने से बचेंगे और खिलाड़ी भी दो बार सोचेंगे।",
|
||||
"ally_donate": "अपने सहयोगी को कुछ सैनिक दान करें। जब उनके पास कम सैनिक हों और हमला हो रहा हो, या जब उन्हें दुश्मन को हराने के लिए अतिरिक्त शक्ति की आवश्यकता हो।",
|
||||
"build_menu_title": "निर्माण मेनू",
|
||||
"build_name": "नाम",
|
||||
"build_icon": "आइकन",
|
||||
"build_desc": "विवरण",
|
||||
"build_city": "शहर",
|
||||
"build_city_desc": "आपकी अधिकतम जनसंख्या बढ़ाता है। जब आप अपना क्षेत्र नहीं बढ़ा सकते या जनसंख्या सीमा पर पहुंचने वाले हों तो उपयोगी।",
|
||||
"build_defense": "रक्षा चौकी",
|
||||
"build_defense_desc": "आसपास की सीमाओं पर रक्षा बढ़ाता है। दुश्मनों के हमले धीमे और अधिक नुकसानदायक होते हैं।",
|
||||
"build_port": "बंदरगाह",
|
||||
"build_port_desc": "आपके देश और अन्य देशों के बंदरगाहों के बीच स्वचालित रूप से व्यापार जहाज भेजता है (जब तक आपने 'व्यापार बंद' नहीं किया हो), दोनों पक्षों को सोना देता है। युद्धपोत निर्माण की अनुमति देता है। केवल पानी के पास बनाया जा सकता है।",
|
||||
"build_warship": "युद्धपोत",
|
||||
"build_warship_desc": "एक क्षेत्र में गश्त लगाता है, व्यापारिक जहाज़ों को पकड़ता है और दुश्मन के युद्धपोतों और नौकाओं को नष्ट करता है। यह नजदीकी बंदरगाह से निकलता है और उस क्षेत्र में गश्त करता है जहाँ आपने इसे बनाने के लिए पहले क्लिक किया था। आप युद्धपोतों पर अटैक-क्लिक करके और फिर नए क्षेत्र पर अटैक-क्लिक करके उन्हें नियंत्रित कर सकते हैं।",
|
||||
"build_silo": "मिसाइल साइलो",
|
||||
"build_silo_desc": "मिसाइल प्रक्षेपण की अनुमति देता है।",
|
||||
"build_sam": "एसएएम लॉन्चर",
|
||||
"build_sam_desc": "100 पिक्सेल रेंज में दुश्मन मिसाइलों को 75% संभावना से रोकता है। एसएएम का 7.5 सेकंड का कूलडाउन होता है और MIRV को नहीं रोक सकता।",
|
||||
"build_atom": "परमाणु बम",
|
||||
"build_atom_desc": "छोटा विस्फोटक बम जो क्षेत्र, इमारतें, जहाज और नावों को नष्ट करता है। निकटतम मिसाइल साइलो से प्रकट होता है और आपके द्वारा चयनित क्षेत्र में गिरता है।",
|
||||
"build_hydrogen": "हाइड्रोजन बम",
|
||||
"build_hydrogen_desc": "बड़ा विस्फोटक बम। निकटतम मिसाइल साइलो से प्रकट होता है और आपके द्वारा चयनित क्षेत्र में गिरता है।",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "गेम का सबसे शक्तिशाली बम। छोटे बमों में विभाजित होकर विशाल क्षेत्र को कवर करता है। केवल उस खिलाड़ी को नुकसान पहुंचाता है जिसे आपने चयनित किया था। निकटतम मिसाइल साइलो से प्रकट होता है।",
|
||||
"player_icons": "खिलाड़ी आइकन",
|
||||
"icon_desc": "खेल में मिलने वाले कुछ आइकन और उनके अर्थ:",
|
||||
"icon_crown": "मुकुट - लीडरबोर्ड में नंबर 1 खिलाड़ी",
|
||||
"icon_traitor": "क्रॉस की गई तलवारें - विश्वासघाती। इस खिलाड़ी ने सहयोगी पर हमला किया।",
|
||||
"icon_ally": "हाथ मिलाना - सहयोगी। यह खिलाड़ी आपका सहयोगी है।",
|
||||
"info_enemy_panel": "दुश्मन जानकारी पैनल",
|
||||
"action_emote": "इमोजी मेन्यू खोलें"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "कंप्यूटर मोड",
|
||||
"allow_alliances": "सहयोग की अनुमति दें",
|
||||
"options_title": "विकल्प",
|
||||
"bots": "बॉट: ",
|
||||
"bots_disabled": "निष्क्रिय",
|
||||
"disable_nations": "राष्ट्र निष्क्रिय करें",
|
||||
"instant_build": "तुरंत निर्माण",
|
||||
"infinite_gold": "असीमित सोना",
|
||||
"infinite_troops": "असीमित सैनिक",
|
||||
"disable_nukes": "परमाणु अस्त्र निष्क्रिय करें",
|
||||
"start": "गेम शुरू करें"
|
||||
},
|
||||
"map": {
|
||||
"world": "विश्व",
|
||||
"europe": "यूरोप",
|
||||
"mena": "मध्य पूर्व",
|
||||
"northamerica": "उत्तरी अमेरिका",
|
||||
"oceania": "ओशिनिया",
|
||||
"blacksea": "काला सागर",
|
||||
"africa": "अफ्रीका",
|
||||
"asia": "एशिया",
|
||||
"mars": "मंगल",
|
||||
"southamerica": "दक्षिण अमेरिका",
|
||||
"britannia": "ब्रिटानिया",
|
||||
"gatewaytotheatlantic": "अटलांटिक का प्रवेश द्वार",
|
||||
"australia": "ऑस्ट्रेलिया",
|
||||
"random": "यादृच्छिक",
|
||||
"iceland": "आइसलैंड",
|
||||
"pangaea": "पांजिया",
|
||||
"map": "नक्शा",
|
||||
"betweentwoseas": "समुद्रों के मध्य भूमि",
|
||||
"japan": "जापान और सीमावर्ती देश",
|
||||
"knownworld": "ज्ञात दुनिया"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "निजी लॉबी में शामिल हों",
|
||||
"enter_id": "लॉबी आईडी दर्ज करें",
|
||||
"player": "खिलाड़ी",
|
||||
"players": "खिलाड़ी",
|
||||
"join_lobby": "लॉबी में शामिल हों",
|
||||
"checking": "लॉबी जांच रहा है...",
|
||||
"not_found": "लॉबी नहीं मिली। कृपया आईडी जांचें और पुनः प्रयास करें।",
|
||||
"error": "एक त्रुटि हुई। कृपया पुनः प्रयास करें।",
|
||||
"joined_waiting": "सफलतापूर्वक शामिल हुए! गेम शुरू होने की प्रतीक्षा कर रहे हैं..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "अगले गेम में शामिल हों",
|
||||
"waiting": "प्रतीक्षा कर रहे खिलाड़ी"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "अपना दर्ज करें",
|
||||
"not_string": "उपयोगकर्ता नाम एक स्ट्रिंग होना चाहिए।",
|
||||
"too_short": "उपयोगकर्ता नाम कम से कम {min} वर्ण लंबा होना चाहिए।",
|
||||
"too_long": "उपयोगकर्ता नाम {max} वर्णों से अधिक नहीं हो सकता।",
|
||||
"invalid_chars": "उपयोगकर्ता नाम में केवल अक्षर, संख्याएं, रिक्त स्थान, अंडरस्कोर और [वर्गाकार कोष्ठक] हो सकते हैं।"
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "निजी लॉबी",
|
||||
"options_title": "विकल्प",
|
||||
"bots": "बॉट: ",
|
||||
"bots_disabled": "निष्क्रिय",
|
||||
"disable_nations": "राष्ट्र निष्क्रिय करें",
|
||||
"instant_build": "तुरंत निर्माण",
|
||||
"infinite_gold": "असीमित सोना",
|
||||
"infinite_troops": "असीमित सैनिक",
|
||||
"disable_nukes": "परमाणु अस्त्र निष्क्रिय करें",
|
||||
"player": "खिलाड़ी",
|
||||
"players": "खिलाड़ी",
|
||||
"waiting": "खिलाड़ियों की प्रतीक्षा कर रहे हैं...",
|
||||
"start": "गेम शुरू करें",
|
||||
"mode": "मोड"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "आसान",
|
||||
"Balanced": "मध्यम",
|
||||
"Intense": "कठिन",
|
||||
"Impossible": "असंभव",
|
||||
"difficulty": "लेवल"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "खेल शुरू हो रहा है...",
|
||||
"desc": "लॉबी शुरू होने की तैयारी हो रही है। कृपया प्रतीक्षा करें।"
|
||||
},
|
||||
"lang": {
|
||||
"en": "Hindi",
|
||||
"native": "हिन्दी",
|
||||
"svg": "in",
|
||||
"lang_code": "hi"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "हर कोई बनाम हर कोई",
|
||||
"teams": "टीम"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "भाषा चुनें"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "Unisciti al nostro Discord!",
|
||||
"create_lobby": "Crea lobby",
|
||||
"join_lobby": "Unisciti a una Lobby",
|
||||
"single_player": "Giocatore Singolo",
|
||||
"instructions": "Istruzioni",
|
||||
"how_to_play": "Come si gioca",
|
||||
"wiki": "Wiki"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Tasti di scelta rapida",
|
||||
"table_key": "Tasto",
|
||||
"table_action": "Azione",
|
||||
"action_alt_view": "Vista alternata (terreno/paesi)",
|
||||
"action_attack_altclick": "Attacco (quando il clic sinistro è impostato per aprire il menu)",
|
||||
"action_build": "Apri il menu di costruzione",
|
||||
"action_center": "Centra camera sul giocatore",
|
||||
"action_zoom": "Zoom avanti/indietro",
|
||||
"action_move_camera": "Muovi la camera",
|
||||
"action_ratio_change": "Diminuisci/Aumenta Il rapporto di attacco",
|
||||
"action_reset_gfx": "Resetta grafica",
|
||||
"ui_section": "Interfaccia Di Gioco",
|
||||
"ui_leaderboard": "Classifica",
|
||||
"ui_leaderboard_desc": "Mostra i migliori giocatori della partita e i loro nomi, % di proprietà di terra e oro.",
|
||||
"ui_control": "Pannello di controllo",
|
||||
"ui_control_desc": "Il pannello di controllo contiene i seguenti elementi:",
|
||||
"ui_pop": "Pop - La quantità di unità che hai, la popolazione massima e la velocità con cui le ottieni.",
|
||||
"ui_gold": "Oro - La quantità di oro che hai e il tasso a cui lo guadagni.",
|
||||
"ui_troops_workers": "Truppe e operai - La quantità di truppe e lavoratori assegnati. Le truppe sono usate per attaccare o difendersi dagli attacchi. I lavoratori sono utilizzati per generare oro. È possibile regolare il numero di truppe e lavoratori utilizzando il cursore.",
|
||||
"ui_attack_ratio": "Rapporto di attacco: la quantità di truppe che verranno utilizzate quando attacchi. Puoi regolare il rapporto di attacco usando il cursore. Avere più truppe d'attacco rispetto alle truppe del difensore ti farà perdere meno truppe nell'attacco, mentre averne meno aumenterà il danno subito dalle tue truppe. L'effetto non va oltre i rapporti di 2:1.",
|
||||
"ui_options": "Opzioni",
|
||||
"ui_options_desc": "All'interno si possono trovare i seguenti elementi:",
|
||||
"option_pause": "Pausa/Riattiva Il gioco - Disponibile solo in modalità giocatore singolo.",
|
||||
"option_timer": "Timer - Tempo passato dall'inizio del gioco.",
|
||||
"option_exit": "Pulsante Esci.",
|
||||
"option_settings": "Impostazioni - Apre il menu delle impostazioni. All'interno è possibile attivare o disattivare la vista alternativa, la modalità scura, le emoji e l'azione con il clic sinistro.",
|
||||
"radial_title": "Menu Radiale",
|
||||
"radial_desc": "Facendo clic con il tasto destro (o toccando il cellulare) si apre il menu radiale. Da lì è possibile:",
|
||||
"radial_build": "Apri il menu Costruzione.",
|
||||
"radial_info": "Apri il menu Informazioni.",
|
||||
"radial_boat": "Invia una barca per sbarcare e attaccare nella posizione selezionata (disponibile solo se hai accesso all'acqua).",
|
||||
"radial_close": "Chiudi menù.",
|
||||
"info_title": "Menu info",
|
||||
"info_enemy_desc": "Contiene informazioni come: il nome del giocatore selezionato, oro, truppe, e se il giocatore è un traditore. Il traditore è un giocatore che ha tradito e attaccato un giocatore che era in alleanza con lui. Le icone qui sotto rappresentano le seguenti interazioni:",
|
||||
"info_target": "Mette un marker di attacco sul giocatore, Richiede un attacco verso il giocatore, contrassegnandolo per tutti gli alleati, usato per coordinare gli attacchi.",
|
||||
"info_alliance": "Invia una richiesta di alleanza al giocatore. Gli alleati possono condividere risorse e truppe, ma non possono attaccarsi.",
|
||||
"info_emoji": "Invia un'emoji al giocatore.",
|
||||
"info_ally_panel": "Pannello informazioni alleato",
|
||||
"info_ally_desc": "Quando sei alleato con un giocatore, diventano disponibili le seguenti nuove icone:",
|
||||
"ally_betray": "Tradisci il tuo alleato, finendo l'alleanza. Ora avrai un'icona permanente accanto al tuo nome, a meno che l'altra nazione non fosse un traditore a sua volta. Gli attacchi contro di te avranno un vantaggio, subendo meno perdite per l'attaccante fino alla fine della partita, i bot hanno meno probabilità di allearsi con te e i giocatori umani ci penseranno due volte prima di farlo.",
|
||||
"ally_donate": "Dona alcune delle tue truppe al tuo alleato. Usalo quando hanno poche truppe e vengono attaccati, o quando hanno bisogno di quelle truppe extra per schiacciare un nemico.",
|
||||
"build_menu_title": "Menu di costruzione",
|
||||
"build_name": "Nome",
|
||||
"build_icon": "Icona",
|
||||
"build_desc": "Descrizione",
|
||||
"build_city": "Città",
|
||||
"build_city_desc": "Aumenta la tua popolazione massima. Utile quando non puoi espandere il tuo territorio o stai per raggiungere il tuo limite di popolazione.",
|
||||
"build_defense": "Fortificazione difensiva",
|
||||
"build_defense_desc": "Aumenta le difese intorno ai confini nelle vicinanze. Gli attacchi dei nemici sono più lenti e hanno più vittime.",
|
||||
"build_port": "Porto",
|
||||
"build_port_desc": "Invia automaticamente delle navi commerciali tra i porti del tuo paese e di altri paesi (tranne se hai cliccato \"Termina Commercio\" su di loro o loro lo hanno fatto su di te), danno oro a entrambi i lati. Permette di costruire navi da Guerra. Può essere costruito solo vicino all'acqua.",
|
||||
"build_warship": "Nave da guerra",
|
||||
"build_warship_desc": "Pattuglia in una zona, catturando navi commerciali e distruggendo navi da guerra nemiche e navi da sbarco. Viene generata dal porto più vicino e pattuglia l'area dove hai cliccato per costruirla. È possibile controllare le navi da guerra facendo clic su di esse e quindi pattugliare una nuova zona, facendo clic sulla nuova area in cui vuoi che pattuglino",
|
||||
"build_silo": "Silo Missilistico",
|
||||
"build_silo_desc": "Permette il lancio di missili Nucleari.",
|
||||
"build_sam": "SAM Antimissile",
|
||||
"build_sam_desc": "Ha il 75% di probabilità d'intercettare i missili nemici nel suo raggio di 100 pixel. Il SAM ha un tempo di ricarica di 7,5 secondi e non può intercettare i MIRV.",
|
||||
"build_atom": "Bomba Atomica",
|
||||
"build_atom_desc": "Piccola bomba atomica che distrugge territorio, edifici, navi e navi da sbarco. Viene generata dal più vicino Silo Missilistico e atterra nella zona in cui hai cliccato per costruirla.",
|
||||
"build_hydrogen": "Bomba A Idrogeno",
|
||||
"build_hydrogen_desc": "Grande bomba atomica. Viene generata dal più vicino Silo Missilistico e atterra nella zona in cui hai cliccato per costruirla.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "La bomba atomica più potente del gioco. Si divide in bombe più piccole che copriranno una vasta gamma di territori. Danneggia solo il giocatore su cui hai cliccato per costruirla. Viene generata dal più vicino Silo Missilistico e atterra nella zona in cui hai cliccato per costruirla.",
|
||||
"player_icons": "Icone del giocatore",
|
||||
"icon_desc": "Esempi di alcune delle icone che incontrerai in gioco e cosa significano:",
|
||||
"icon_crown": "Corona - Questo è il giocatore numero uno della classifica",
|
||||
"icon_traitor": "Spade incrociate - Traditore. Questo giocatore ha attaccato un alleato.",
|
||||
"icon_ally": "Stretta di mano - Alleato, Questo giocatore è un tuo alleato",
|
||||
"info_enemy_panel": "Pannello informazioni nemico",
|
||||
"action_emote": "Apri menu emote"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Giocatore Singolo",
|
||||
"allow_alliances": "Permetti Alleanze",
|
||||
"options_title": "Opzioni",
|
||||
"bots": "Bot: ",
|
||||
"bots_disabled": "Disabilitato",
|
||||
"disable_nations": "Disabilita Nazioni",
|
||||
"instant_build": "Costruzione Istantanea ",
|
||||
"infinite_gold": "Oro infinito",
|
||||
"infinite_troops": "Truppe infinite",
|
||||
"disable_nukes": "Disabilita Bombe Nucleari",
|
||||
"start": "Inizia partita"
|
||||
},
|
||||
"map": {
|
||||
"world": "Mondo",
|
||||
"europe": "Europa",
|
||||
"mena": "MENA",
|
||||
"northamerica": "Nord America",
|
||||
"oceania": "Oceania",
|
||||
"blacksea": "Mar Nero",
|
||||
"africa": "Africa",
|
||||
"asia": "Asia",
|
||||
"mars": "Marte",
|
||||
"southamerica": "Sud America",
|
||||
"britannia": "Britannia",
|
||||
"gatewaytotheatlantic": "Colonne D'ercole",
|
||||
"australia": "Australia",
|
||||
"random": "Casuale",
|
||||
"iceland": "Islanda",
|
||||
"pangaea": "Pangea",
|
||||
"map": "Mappa",
|
||||
"betweentwoseas": "Tra I Due Mari",
|
||||
"japan": "Giappone e paesi confinanti",
|
||||
"knownworld": "Mondo Conosciuto"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Partecipa ad una Lobby Privata",
|
||||
"enter_id": "Inserisci Id Della Lobby",
|
||||
"player": "Giocatore",
|
||||
"players": "Giocatori",
|
||||
"join_lobby": "Unisciti a una Lobby",
|
||||
"checking": "Verifica lobby...",
|
||||
"not_found": "Lobby non trovata. Per favore controlla l'ID e riprova.",
|
||||
"error": "Si è verificato un errore. Si prega di riprovare.",
|
||||
"joined_waiting": "Iscritto con successo! In attesa che la partita inizi..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "Partecipa alla prossima Partita",
|
||||
"waiting": "Giocatori in attesa"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "Inserisci il tuo username",
|
||||
"not_string": "Il nome utente deve essere una stringa.",
|
||||
"too_short": "Il nome utente deve essere di almeno {min} caratteri.",
|
||||
"too_long": "Il nome utente non deve superare {max} caratteri.",
|
||||
"invalid_chars": "Il nome utente può contenere solo lettere, numeri, spazi, trattini bassi e [parentesi quadre]."
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "Lobby privata",
|
||||
"options_title": "Opzioni",
|
||||
"bots": "Bot: ",
|
||||
"bots_disabled": "Disabilitato",
|
||||
"disable_nations": "Disabilita Nazioni",
|
||||
"instant_build": "Costruzione Istantanea ",
|
||||
"infinite_gold": "Oro infinito",
|
||||
"infinite_troops": "Truppe infinite",
|
||||
"disable_nukes": "Disabilita Bombe Nucleari",
|
||||
"player": "Giocatore",
|
||||
"players": "Giocatori",
|
||||
"waiting": "In attesa dei giocatori...",
|
||||
"start": "Avvia Partita",
|
||||
"mode": "Modalità"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "Tranquillo",
|
||||
"Balanced": "Bilanciato",
|
||||
"Intense": "Intenso",
|
||||
"Impossible": "Impossibile",
|
||||
"difficulty": "Difficoltà"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "La partita sta iniziando...",
|
||||
"desc": "Preparazione per l'avvio della lobby. Attendere prego."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Italian",
|
||||
"native": "Italiano",
|
||||
"svg": "it",
|
||||
"lang_code": "it"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Tutti contro tutti",
|
||||
"teams": "A Squadre"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Seleziona Lingua"
|
||||
}
|
||||
}
|
||||
@@ -173,5 +173,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "バトルロワイヤル",
|
||||
"teams": "チーム戦"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "言語を選択"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"ui_pop": "Pop - Jouw totale bevolking, jouw maximale bevolking en de snelheid waarmee je ze verwerft.",
|
||||
"ui_gold": "Goud - Het goud dat je hebt en de snelheid waarmee je het verwerft.",
|
||||
"ui_troops_workers": "Troepen en Werkers - Het aantal toegewezen troepen en werkers. Troepen worden gebruikt om aan te vallen of verdedigen. Werkers worden gebruikt om goud te genereren. Je kunt het aantal troepen en werkers aanpassen met de schuifbalk.",
|
||||
"ui_attack_ratio": "Aanvalsverhouding - Het aantal troepen dat wordt gebruikt bij een aanval. Je kunt de aanvalsverhouding aanpassen met de schuifbalk.",
|
||||
"ui_attack_ratio": "Aanvalsverhouding - Het aantal troepen dat wordt gebruikt wanneer je aanvalt. Je kunt de aanvalsverhouding aanpassen met de schuifbalk. Heb je meer aanvallende dan verdedigende troepen dan verlies je er minder bij de aanval, heb je er minder dan lopen je aanvallende troepen meer schade op. Dit effect gaat niet verder dan verhoudingen van 2:1.",
|
||||
"ui_options": "Opties",
|
||||
"ui_options_desc": "De volgende elementen zijn hierin te vinden:",
|
||||
"option_pause": "Spel pauzeren/hervatten - Alleen beschikbaar in het speltype voor één speler.",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Stuur een emoji naar de speler.",
|
||||
"info_ally_panel": "Infopaneel bondgenoot",
|
||||
"info_ally_desc": "Wanneer je een bondgenootschap sluit met een speler, worden de volgende nieuwe iconen beschikbaar:",
|
||||
"ally_betray": "Verraad je bondgenoot en beëindig het bondgenootschap. Je krijgt dan een permanent icoon naast je naam. Bots zijn minder geneigd om met je een bondgenootschap aan te gaan en spelers zullen er tweemaal over nadenken.",
|
||||
"ally_betray": "Verraad je bondgenoot, beëindig het bondgenootschap. Je krijgt nu een permanent icoon naast je naam, behalve als het andere land zelf een verrader was. Aanvallen tegen jou leiden tot het einde van het spel tot minder verliezen voor de aanvaller, bots zullen minder snel een bondgenootschap met je sluiten en spelers zullen zich wel tweemaal bedenken voor ze dat doen.\"",
|
||||
"ally_donate": "Geef een deel van je troepen aan je bondgenoot. Gebruikt wanneer ze weinig troepen hebben en worden aangevallen, of wanneer ze die extra kracht nodig hebben om een vijand te verpletteren.",
|
||||
"build_menu_title": "Bouwmenu",
|
||||
"build_name": "Naam",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Haven",
|
||||
"build_port_desc": "Stuurt automatisch handelsschepen tussen havens van jouw land en andere landen (behalve als jij bij hen op \"stop handel\" hebt geklikt of zij bij jou), wat goud oplevert voor beide partijen. Maakt het bouwen van Oorlogsschepen mogelijk. Kan alleen bij water worden gebouwd.",
|
||||
"build_warship": "Oorlogsschip",
|
||||
"build_warship_desc": "Patrouilleert in een gebied, vangt handelsschepen en vernietigt vijandelijke Oorlogsschepen en Boten. Spawnt vanuit de dichtstbijzijnde Haven en patrouilleert in het gebied waar je klikte om het te bouwen.",
|
||||
"build_warship_desc": "Patrouilleert in een gebied, vangt handelsschepen en vernietigt vijandelijke Oorlogsschepen en Boten. Komt vanuit de dichtstbijzijnde Haven en patrouilleert in het gebied waar je hebt geklikt om het te bouwen. Je kunt Oorlogsschepen besturen door op ze te klikken (of shift+klik als linkermuisknop is ingesteld op menu openen) en daarna op de plek waar je ze naartoe wilt laten gaan.",
|
||||
"build_silo": "Raketsilo",
|
||||
"build_silo_desc": "Maakt het lanceren van raketten mogelijk.",
|
||||
"build_sam": "Luchtdoelraket (SAM)-lanceerder",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Kroon - Dit is de nummer 1 speler op de leaderboard.",
|
||||
"icon_traitor": "Gekruiste zwaarden - Verrader. Deze speler heeft een bondgenoot aangevallen.",
|
||||
"icon_ally": "Handdruk - Bondgenoot. Deze speler is je bondgenoot.",
|
||||
"info_enemy_panel": "Infopaneel vijand"
|
||||
"info_enemy_panel": "Infopaneel vijand",
|
||||
"action_emote": "Open emoji-menu"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Eén speler",
|
||||
@@ -172,5 +173,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "Iedereen tegen iedereen (FFA)",
|
||||
"teams": "Teams"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Kies taal"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"ui_pop": "Populacja – Liczba posiadanych jednostek, maksymalna liczba ludności oraz tempo, w jakim ją zdobywasz.",
|
||||
"ui_gold": "Złoto – Liczba posiadanego złota oraz tempo jego przyrostu.",
|
||||
"ui_troops_workers": "Wojsko i Pracownicy – Liczba przydzielonych jednostek wojskowych i pracowników. Wojsko służy do ataku oraz obrony przed wrogimi atakami, a pracownicy są wykorzystywani do generowania złota. Możesz regulować ich liczbę za pomocą suwaka.",
|
||||
"ui_attack_ratio": "Współczynnik ataku – Liczba wojsk wykorzystywanych podczas ataku. Możesz dostosować ten współczynnik za pomocą suwaka.",
|
||||
"ui_attack_ratio": "Współczynnik ataku - ilość jednostek, która będzie użyta podczas ataku. Możesz dostosować współczynnik ataku używając suwaka. Posiadanie większej ilości atakujących jednostek niż jednostek obronnych wroga sprawi, że stracisz mniej jednostek podczas ataku, natomiast gdy będziesz miał mniej, zwiększy się ilość obrażeń zadanym twoim jednostkom. Efekt nie wykracza poza stosunek 2:1.",
|
||||
"ui_options": "Opcje",
|
||||
"ui_options_desc": "Wewnątrz można znaleźć następujące elementy:",
|
||||
"option_pause": "Wstrzymaj/Wznów grę – dostępne tylko w trybie jednoosobowym.",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Wyślij emotkę do gracza.",
|
||||
"info_ally_panel": "Panel informacji sojusznika",
|
||||
"info_ally_desc": "Po nawiązaniu sojuszu z graczem dostępne stają się następujące nowe ikony:",
|
||||
"ally_betray": "Zdradzając swojego sojusznika — kończysz z nim sojusz. Od tego momentu do końca gry posiadasz ikonę zdrajcy obok twojej nazwy użytkownika. Boty będą mniej skłonne do zawierania sojuszy z tobą, a gracze dwa razy się zastanowią, zanim to zrobią.",
|
||||
"ally_betray": "Zdradź swojego sojusznika, kończąc sojusz. Będziesz teraz mieć stałą ikonę obok swojej nazwy, chyba że ten naród sam był zdrajcą. Ataki przeciwko tobie spowodują mniejsze straty dla atakującego do końca gry, boty będą mniej przychylne do sprzymierzenia się z tobą, a gracze zastanowią się dwukrotnie, zanim to zrobią.",
|
||||
"ally_donate": "Przekaż część swoich wojsk swojemu sojusznikowi. Używane, gdy brakuje mu wojsk i jest atakowany, lub gdy potrzebuje dodatkowej siły, aby pokonać wroga.",
|
||||
"build_menu_title": "Menu budowy",
|
||||
"build_name": "Nazwa",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Port",
|
||||
"build_port_desc": "Automatycznie wysyła statki handlowe między portami twojego kraju a innymi krajami (chyba że klikniesz „zatrzymaj handel” lub inny gracz zrobi to względem ciebie), przynosząc złoto obu stronom. Umożliwia budowanie okrętów wojennych. Może być budowane tylko w pobliżu wody.",
|
||||
"build_warship": "Okręt wojenny",
|
||||
"build_warship_desc": "Patroluje wyznaczony obszar, przechwytując statki handlowe i niszcząc wrogie okręty wojenne oraz statki z wojskiem. Pojawia się przy porcie, który ma najbliższą drogę do obszaru wyznaczonego do patrolu.",
|
||||
"build_warship_desc": "Patroluje dany obszar, przechwytuje statki handlowe oraz niszczy okręty wojenne i transporty wroga. Pojawia się z najbliższego portu i patroluje obszar, który po raz pierwszy zaznaczyłeś, budując go. Możesz kontrolować okręty wojenne klikając na nie, a następnie klikając na nowy obszar, do którego chcesz by się udały.",
|
||||
"build_silo": "Silos rakietowy",
|
||||
"build_silo_desc": "Umożliwia odpalenie rakiet.",
|
||||
"build_sam": "Wyrzutnia SAM",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Korona — Jest to gracz numer 1 w rankingu",
|
||||
"icon_traitor": "Skrzyżowane miecze — Zdrajca. Ten gracz atakował sojusznika.",
|
||||
"icon_ally": "Uścisk dłoni — Sojusznik. Ten gracz jest twoim sojusznikiem.",
|
||||
"info_enemy_panel": "Panel informacji o wrogu"
|
||||
"info_enemy_panel": "Panel informacji o wrogu",
|
||||
"action_emote": "Otwórz menu emoji"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Gra jednoosobowa",
|
||||
@@ -172,5 +173,8 @@
|
||||
"game_mode": {
|
||||
"ffa": "Każdy na Każdego",
|
||||
"teams": "Drużyny"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Wybierz język"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "Junte-se ao Discord!",
|
||||
"create_lobby": "Criar Sala",
|
||||
"join_lobby": "Entrar na Sala",
|
||||
"single_player": "Um Jogador",
|
||||
"instructions": "Instruções",
|
||||
"how_to_play": "Como Jogar",
|
||||
"wiki": "Wiki"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Atalhos",
|
||||
"table_key": "Teclas",
|
||||
"table_action": "Ação",
|
||||
"action_alt_view": "Modo de exibição (terreno/países)",
|
||||
"action_attack_altclick": "Ataque (quando o botão esquerdo estiver definido para abrir o menu)",
|
||||
"action_build": "Abra o menu de construção",
|
||||
"action_center": "Centralizar câmera no jogador",
|
||||
"action_zoom": "Diminuir/aumentar zoom",
|
||||
"action_move_camera": "Mover câmera",
|
||||
"action_ratio_change": "Diminuir/Aumentar taxa de ataque",
|
||||
"action_reset_gfx": "Redefinir gráficos",
|
||||
"ui_section": "Interface",
|
||||
"ui_leaderboard": "Classificação",
|
||||
"ui_leaderboard_desc": "Mostra os maiores jogadores do jogo e seus nomes, % de ouro e terreno possuídos.",
|
||||
"ui_control": "Painel de controle",
|
||||
"ui_control_desc": "O painel de controle contém os seguintes elementos:",
|
||||
"ui_pop": "Pop - A quantidade de unidades que você tem, a sua população máxima e a taxa em que você os ganha.",
|
||||
"ui_gold": "Ouro - A quantidade de ouro que você tem e a taxa com a qual você o ganha.",
|
||||
"ui_troops_workers": "Tropas e Trabalhadores - A quantidade de tropas alocadas e trabalhadores. Tropas são usadas para atacar ou defender contra os ataques inimigos. Trabalhadores são usados para gerar ouro. Você pode ajustar o número de tropas e trabalhadores usando a barra.",
|
||||
"ui_attack_ratio": "Taxa de ataque – A quantidade de tropas que será usada quando você atacar. Você pode ajustar a proporção de ataque usando o controle deslizante. Ter mais tropas atacando do que tropas defendendo fará com que você perca menos tropas no ataque, enquanto ter menos aumentará o dano sofrido pelas suas tropas atacantes. O efeito não aumenta além da proporção de 2:1.",
|
||||
"ui_options": "Opções",
|
||||
"ui_options_desc": "Os seguintes elementos podem ser encontrados:",
|
||||
"option_pause": "Pausar/Retomar o jogo - Disponível apenas no modo de um jogador.",
|
||||
"option_timer": "Cronômetro - Tempo que passou desde o início da partida.",
|
||||
"option_exit": "Botão de saída.",
|
||||
"option_settings": "Configurações - Abra o menu de configurações. Dentro você poderá alternar Modo de Exibição, Modo Escuro, Emojis e ação ao clicar com o botão esquerdo.",
|
||||
"radial_title": "Menu radial",
|
||||
"radial_desc": "Clique com o botão direito (ou toque no celular) para abrir o menu radial. A partir daí, você pode:",
|
||||
"radial_build": "Abrir o menu de construção.",
|
||||
"radial_info": "Abrir o menu de informação.",
|
||||
"radial_boat": "Enviar um barco para atacar no local selecionado (só disponível se você tiver acesso à água).",
|
||||
"radial_close": "Fechar o menu.",
|
||||
"info_title": "Menu de informações",
|
||||
"info_enemy_desc": "Contém informações como o nome de jogador selecionado, ouro, tropas, e se o jogador for um traidor. Traidor é um jogador que traiu e atacou um jogador que estava em uma aliança com ele. Os ícones abaixo representam as seguintes interações:",
|
||||
"info_target": "Coloca um alvo no jogador, marcando-o para todos os aliados, usado para coordenar ataques.",
|
||||
"info_alliance": "Envie uma solicitação da aliança para o jogador. Os aliados podem compartilhar recursos e tropas, mas não podem atacar um ao outro.",
|
||||
"info_emoji": "Enviar um emoji para o jogador.",
|
||||
"info_ally_panel": "Painel de informações do Aliado",
|
||||
"info_ally_desc": "Quando você se alia com um jogador, os seguintes novos ícones ficam disponíveis:",
|
||||
"ally_betray": "Traia seu aliado, encerrando a aliança. Um ícone permanente ficará fixado ao lado do seu nome, a menos que a outra nação também fosse traidora. Ataques contra você causarão menos perdas ao atacante até o fim do jogo, bots terão menos chance de se aliar a você e os jogadores pensarão duas vezes antes de fazer isso.",
|
||||
"ally_donate": "Doe algumas de suas tropas para seu aliado. Use quando eles estão com tropas baixas e estão sendo atacados, ou quando eles precisam desse poder extra para esmagar um inimigo.",
|
||||
"build_menu_title": "Menu de construção",
|
||||
"build_name": "Nome",
|
||||
"build_icon": "Ícone",
|
||||
"build_desc": "Descrição",
|
||||
"build_city": "Cidade",
|
||||
"build_city_desc": "Aumenta sua população máxima. Útil quando não é possível expandir seu território ou você está prestes a atingir seu limite populacional.",
|
||||
"build_defense": "Posto de Defesa",
|
||||
"build_defense_desc": "Aumenta as defesas nas proximidades. Ataques de inimigos são mais lentos e têm mais vítimas.",
|
||||
"build_port": "Porto",
|
||||
"build_port_desc": "Envia automaticamente navios mercantes entre portos do seu país e de outros países (exceto se você clicou em \"parar comércio\" com eles ou se eles clicaram em \"parar comércio com você\"), dando ouro para ambos os lados. Permite construir Navios de Guerras. Só pode ser construído perto da água.",
|
||||
"build_warship": "Navio de Guerra",
|
||||
"build_warship_desc": "Patrulha em uma área, capturando navios mercantes e destruindo barcos e navios de guerra inimigos. É gerado do Porto e patrulha a área que você primeiro clicou para construí-lo. Você pode controlar Navios de Guerra clicando sobre eles e depois atacando a nova área para a qual você quer move-los.",
|
||||
"build_silo": "Silo de Míssil",
|
||||
"build_silo_desc": "Permite lançar mísseis.",
|
||||
"build_sam": "Lançador SAM",
|
||||
"build_sam_desc": "Há 75% de chance de interceptar mísseis inimigos em sua faixa de 100 pixels. O SAM tem um tempo de recarga de 7,5 segundos e não pode interceptar MIRVs.",
|
||||
"build_atom": "Bomba Atômica",
|
||||
"build_atom_desc": "Pequena bomba explosiva que destrói territórios, edifícios, navios e barcos. Criado do Silo de Míssil mais próximo e aterrissa na área que você clicou primeiro para construí-lo.",
|
||||
"build_hydrogen": "Bomba de Hidrogênio",
|
||||
"build_hydrogen_desc": "Grande bomba explosiva. Criada do Silo de Míssil mais próximo e cai na área que você clicou primeiro para construí-la.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "A bomba mais poderosa do jogo. Divide em pequenas bombas que cobrirão uma enorme quantidade de território. Danifica apenas o jogador em que você clicou primeiro para construí-lo. Criada do Silo de Míssil mais próximo e aterrissa na área que você clicou primeiro para construí-lo.",
|
||||
"player_icons": "Ícones do Jogador",
|
||||
"icon_desc": "Exemplos de alguns ícones que você irá encontrar e o que eles significam:",
|
||||
"icon_crown": "Coroa - Este é o jogador número 1 da classificação",
|
||||
"icon_traitor": "Espadas cruzadas - Traidor. Este jogador atacou um aliado.",
|
||||
"icon_ally": "Aperto de Mãos - Aliado. Esse jogador é seu aliado.",
|
||||
"info_enemy_panel": "Painel de informações Inimigo",
|
||||
"action_emote": "Abrir menu de emotes"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Um Jogador",
|
||||
"allow_alliances": "Permitir Alianças",
|
||||
"options_title": "Opções",
|
||||
"bots": "Bots: ",
|
||||
"bots_disabled": "Desativado",
|
||||
"disable_nations": "Desativar Nações",
|
||||
"instant_build": "Construção instantânea",
|
||||
"infinite_gold": "Ouro infinito",
|
||||
"infinite_troops": "Tropas infinitas",
|
||||
"disable_nukes": "Desativar Bombas",
|
||||
"start": "Iniciar Jogo"
|
||||
},
|
||||
"map": {
|
||||
"world": "Mundo",
|
||||
"europe": "Europa",
|
||||
"mena": "MENA",
|
||||
"northamerica": "América do Norte",
|
||||
"oceania": "Oceânia",
|
||||
"blacksea": "Mar Negro",
|
||||
"africa": "África",
|
||||
"asia": "Ásia",
|
||||
"mars": "Marte",
|
||||
"southamerica": "América do Sul",
|
||||
"britannia": "Britânica",
|
||||
"gatewaytotheatlantic": "Porta de entrada para o Atlântico",
|
||||
"australia": "Austrália",
|
||||
"random": "Aleatório",
|
||||
"iceland": "Islândia",
|
||||
"pangaea": "Pangeia",
|
||||
"map": "Mapa",
|
||||
"betweentwoseas": "Entre Dois Mares",
|
||||
"japan": "Japão e Vizinhos",
|
||||
"knownworld": "Mundo Conhecido"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Entrar na Sala Privada",
|
||||
"enter_id": "Digite o ID da Sala",
|
||||
"player": "Jogador",
|
||||
"players": "Jogadores",
|
||||
"join_lobby": "Entrar na Sala",
|
||||
"checking": "Verificando sala...",
|
||||
"not_found": "Sala não encontrada. Por favor, verifique o ID e tente novamente.",
|
||||
"error": "Ocorreu um erro. Por favor, tente novamente.",
|
||||
"joined_waiting": "Entrou com sucesso! Aguardando o jogo iniciar..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "Entrar no próximo Jogo",
|
||||
"waiting": "jogadores aguardando"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "Insira seu apelido",
|
||||
"not_string": "Apelido deve ser uma string.",
|
||||
"too_short": "O apelido deve ter pelo menos {min} caracteres.",
|
||||
"too_long": "O apelido não deve exceder {max} caracteres.",
|
||||
"invalid_chars": "O apelido só pode conter letras, números, espaços, sublinhados e [colchetes quadrados]."
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "Sala Privada",
|
||||
"options_title": "Opções",
|
||||
"bots": "Bots: ",
|
||||
"bots_disabled": "Desativado",
|
||||
"disable_nations": "Desativar Nações",
|
||||
"instant_build": "Construção instantânea",
|
||||
"infinite_gold": "Ouro infinito",
|
||||
"infinite_troops": "Tropas infinitas",
|
||||
"disable_nukes": "Desativar Bombas",
|
||||
"player": "Jogador",
|
||||
"players": "Jogadores",
|
||||
"waiting": "Aguardando jogadores...",
|
||||
"start": "Iniciar o Jogo",
|
||||
"mode": "Modo"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "Relaxado",
|
||||
"Balanced": "Balanceado",
|
||||
"Intense": "Intenso",
|
||||
"Impossible": "Impossível",
|
||||
"difficulty": "Dificuldade"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "Jogo está Iniciando...",
|
||||
"desc": "Preparando para começar a sala. Por favor, aguarde."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Brazilian Portuguese",
|
||||
"native": "Português brasileiro",
|
||||
"svg": "br",
|
||||
"lang_code": "pt_br"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Free for All",
|
||||
"teams": "Equipes"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Selecionar idioma"
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
"ui_pop": "Население — количество ваших подразделений, максимальное население и темп его роста.",
|
||||
"ui_gold": "Золото — Количество золота и скорость, с которой вы его получаете.",
|
||||
"ui_troops_workers": "Войска и Рабочие — Количество распределённых войск и рабочих. Войска используются для атаки или защиты от атак. Рабочие используются для добычи золота. Вы можете настроить количество войск и рабочих с помощью ползунка.",
|
||||
"ui_attack_ratio": "Соотношение атаки — Количество войск, которое будет использоваться при атаке. Вы можете изменить соотношение атаки с помощью ползунка.",
|
||||
"ui_attack_ratio": "Соотношение атаки — Количество войск, которое будет использовано при атаке. Вы можете настроить соотношение атаки с помощью ползунка. Имея больше войск атаки, чем войск защиты, вы уменьшите потери во время атаки, а меньше — увеличите потери, наносимые вашим атакующим войскам. Эффект не превышает соотношения 2:1.",
|
||||
"ui_options": "Настройки",
|
||||
"ui_options_desc": "Среди них можно найти следующие элементы:",
|
||||
"option_pause": "Приостановить/Продолжить игру — Доступно только в режиме одиночной игры.",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Отправить смайлик игроку.",
|
||||
"info_ally_panel": "Панель информации о союзнике",
|
||||
"info_ally_desc": "Когда вы заключите альянс с игроком, станут доступны следующие значки:",
|
||||
"ally_betray": "Предайте своего союзника, разорвав альянс. Рядом с вашим именем появится постоянный значок. Боты будут с меньшей вероятностью заключать с вами альянс, а игроки подумают дважды, прежде чем сделать это.",
|
||||
"ally_betray": "Предайте своего союзника, разорвав альянс. Рядом с вашим именем появится постоянная иконка, но только если другая страна до этого не была предателем. Атаки против будут нести меньше потерь для атакующего до конца игры, боты будут с меньшей заключать с вами альянсы, а игроки подумают дважды, прежде чем сотрудничать с вами.",
|
||||
"ally_donate": "Пожертвовать часть войска союзнику. Используется, когда у него мало войск и его атакуют, или когда ему нужна дополнительная мощь для уничтожения врага.",
|
||||
"build_menu_title": "Меню строительства",
|
||||
"build_name": "Название",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Порт",
|
||||
"build_port_desc": "Автоматически отправляет торговые корабли между портами вашей страны и других стран (за исключением случаев, когда вы нажали «прекратить торговлю» на них или они нажали «прекратить торговлю» на вас), давая золото обеим сторонам. Позволяет строить военные корабли. Можно размещать только вблизи воды.",
|
||||
"build_warship": "Военный корабль",
|
||||
"build_warship_desc": "Патрулирует территорию, захватывая торговые корабли, а также разрушая вражеские военные корабли и лодки. Строиться в ближайшем порту и патрулирует территорию, выбранную нажатием кнопкой мыши.",
|
||||
"build_warship_desc": "Патрулирует территорию, захватывая торговые корабли и разрушая вражеские военные корабли и лодки. Появляется из ближайшего порта и патрулирует область, выбранную нажатием кнопкой мыши при создании. Вы можете управлять военными кораблями при помощью кнопки атаки: сначала нажмите на корабль, а затем — на новую область, к которой вы хотите переместиться.",
|
||||
"build_silo": "Ракетная шахта",
|
||||
"build_silo_desc": "Позволяет запускать ракеты.",
|
||||
"build_sam": "Пусковая установка ЗРК",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Корона — Это игрок номер 1 в таблице лидеров",
|
||||
"icon_traitor": "Скрещённые мечи — Предатель. Этот игрок напал на союзника.",
|
||||
"icon_ally": "Рукопожатие — Союзник. Этот игрок — ваш союзник.",
|
||||
"info_enemy_panel": "Панель информации о враге"
|
||||
"info_enemy_panel": "Панель информации о враге",
|
||||
"action_emote": "Открыть меню смайлов"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Одиночная игра",
|
||||
@@ -170,7 +171,10 @@
|
||||
"lang_code": "ru"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Свободная игра (FFA)",
|
||||
"ffa": "Каждый против каждого (FFA)",
|
||||
"teams": "Команды"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Выберите язык"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "Pridruži se Diskordu!",
|
||||
"create_lobby": "Napravi čekaonicu",
|
||||
"join_lobby": "Pridruži se čekaonici",
|
||||
"single_player": "Igraj sam",
|
||||
"instructions": "Instrukcije",
|
||||
"how_to_play": "Kako igrati",
|
||||
"wiki": "Wiki"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Prečice",
|
||||
"table_key": "Taster",
|
||||
"table_action": "Efekat",
|
||||
"action_alt_view": "Alternativni prikaz (teren / države)",
|
||||
"action_attack_altclick": "Napad (ukoliko je levi klik podešen da otvara izbornik)",
|
||||
"action_build": "Otvara izbornik za izgradnju",
|
||||
"action_center": "Centrira kameru na igrača",
|
||||
"action_zoom": "Približi / udalji",
|
||||
"action_move_camera": "Pomera kameru",
|
||||
"action_ratio_change": "Povećava / umanjuje razmjer napada",
|
||||
"action_reset_gfx": "Resetovanje grafike",
|
||||
"ui_section": "Korisnički interfejs igre",
|
||||
"ui_leaderboard": "Ljestvica",
|
||||
"ui_leaderboard_desc": "Prikazuje vodeće igrače partije - njihova imena, procenat ukupne teritorije i zlato.",
|
||||
"ui_control": "Konzola",
|
||||
"ui_control_desc": "Konzola sadrži sljedeće elemente:",
|
||||
"ui_pop": "Populacija - Količina jedinica koju posjeduješ, maksimalna populacija i stopa rasta.",
|
||||
"ui_gold": "Zlato - Količina zlata koju posjeduješ i stopa rasta.",
|
||||
"ui_troops_workers": "Vojnici i radnici - Količina dodijeljenih vojnika i radnika. Vojnici se koriste za napad i odbranu od napada. Radnici proizvode zlato. Možeš prilagoditi broj vojnika i radnika koristeći klizač.",
|
||||
"ui_attack_ratio": "Razmjer napada - Količina vojnika koja će biti upotrebljena u napadu. Možeš prilagoditi razmjer pomoću klizača. Ukoliko imaš više napadača nego protivnik branilaca, gubićeš manje vojnika u napadu. Ukoliko imaš manje napadača, trpiti ćeš više štete. Učinak ne raste dalje od razmjera 2:1.",
|
||||
"ui_options": "Opcije",
|
||||
"ui_options_desc": "Sadrže naredne elemente:",
|
||||
"option_pause": "Pauziraj / nastavi igru - Dostupno samo kada igraš sam.",
|
||||
"option_timer": "Tajmer - Prikazuje koliko je vremena protjeklo od početka partije,",
|
||||
"option_exit": "Dugme za izlaz.",
|
||||
"option_settings": "Podješavanja - Otvori izbornik za podješavanje igre. Unutar možeš uključiti i isključiti Alternativni prikaz, Tamni način rada, Emotikone i šta ćeš raditi levim klikom.",
|
||||
"radial_title": "Kružni izbornik",
|
||||
"radial_desc": "Desni klik (odnosno dodir na telefonu) otvara kružni izbornik. Odatle je moguće:",
|
||||
"radial_build": "Otvaranje izbornika za izgradnju.",
|
||||
"radial_info": "Otvaranje izbornika sa informacijama.",
|
||||
"radial_boat": "Slanje čamca u napad na odabranu lokaciju (samo ako imaš pristup vodama).",
|
||||
"radial_close": "Zatvaranje izbornika.",
|
||||
"info_title": "Izbornik sa informacijama",
|
||||
"info_enemy_desc": "Sadrži informacije o odabranom igraču poput imena, zlata, vojnika i da li je izdajica. Izdajica je igrač koji je izdao i napao igrača s kojim je prethodno imao savez. Ikonice ispod predstavljaju naredna međudjelovanja:",
|
||||
"info_target": "Postavljanje mete na odabranog igrača koja se prikazuje svim tvojim saveznicima. Koristi se za koordinirane napade.",
|
||||
"info_alliance": "Slanje zahtjeva za savez odabranom igraču. Saveznici mogu da djele resurse i vojnike, ali ne mogu se međusobno napadati.",
|
||||
"info_emoji": "Slanje emotikona odabranom igraču.",
|
||||
"info_ally_panel": "Informacije o savezniku",
|
||||
"info_ally_desc": "Nakon stupanja u savez sa igračem, naredne nove ikonice postaju dostupne:",
|
||||
"ally_betray": "Izdaj saveznika, time okončavajući savez. Sada ćeš pored imena trajno imati ikonicu izdajnika, osim ako je ta osoba već bila izdajnik. Napadi protiv tebe će napadačima praviti manje štete do kraja igre, botovi će češće odbijati ponude za savez i igrači će se takođe premišljati.",
|
||||
"ally_donate": "Pokloni savezniku deo svoje vojske. Upotrebiti kada njima ostane premalo vojske za odbranu ili kada im fali dodatne sile da satru neprijatelja.",
|
||||
"build_menu_title": "Izbornik za izgradnju",
|
||||
"build_name": "Ime",
|
||||
"build_icon": "Ikonica",
|
||||
"build_desc": "Opis",
|
||||
"build_city": "Grad",
|
||||
"build_city_desc": "Povećava ti maksimalnu populaciju. Korisni su kad ne možeš dalje da širiš teritoriju ili si blizu gornje granice populacije.",
|
||||
"build_defense": "Tvrđava",
|
||||
"build_defense_desc": "Ojačava odbranu okolnih granica. Neprijateljski napadi su sporiji i trpe više gubitaka.",
|
||||
"build_port": "Luka",
|
||||
"build_port_desc": "Automatski šalje trgovačke brodove između tvojih luka i luka drugih država (osim ako je jedno od vas kliknulo na \"obustavi trgovinu\"), nagrađujući zlatom obje strane. Omogućava izgradnju Ratnih brodova. Može se izgraditi isključivo blizu voda.",
|
||||
"build_warship": "Ratni brod",
|
||||
"build_warship_desc": "Patrolira oblašću, zarobljavajući trgovačke brodove i uništavajući neprijateljske Ratne brodove. Stvara se u najbližoj luki i patrolira oblašću gde si kliknuo pri izgradnji. Možeš vršiti kontrolu nad Ratnim brodovima tako što ćeš ih kliknuti tasterom za napad i onda kliknuti na oblast u koju želiš da ih premjestiš.",
|
||||
"build_silo": "Raketni silos",
|
||||
"build_silo_desc": "Omogućava lansiranje raketa.",
|
||||
"build_sam": "SAM raketa",
|
||||
"build_sam_desc": "Ima 75% šanse da presretne neprijateljsku raketu u dometu od 100 piksela. Nakon toga se mora ohladiti 7,5 sekundi. Ne može da presretne M.I.R.V.",
|
||||
"build_atom": "Atomska bomba",
|
||||
"build_atom_desc": "Omanja eksplozivna bomba koja uništava teritoriju, građevine, brodove i čamce. Izleće iz najbližeg Raketnog silosa i pada na oblast gde si kliknuo pri izgradnju.",
|
||||
"build_hydrogen": "Hidrogenska bomba",
|
||||
"build_hydrogen_desc": "Veća eksplozivna bomba. Izleće iz najbližeg Raketnog silosa i pada na oblast gde si kliknuo pri izgradnju.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "Najmoćnija bomba u igri. Deli se na manje bombice koje pokrivaju ogromnu teritoriju. Pogađa isključivo igrača na kog si kliknuo pri izgradnji. Izleće iz najbližeg Raketnog silosa i pada na oblast gde si kliknuo na izgradnju.",
|
||||
"player_icons": "Ikonice igrača",
|
||||
"icon_desc": "Primjeri nekih od ikonica koje ćeš viđati tokom igre i njihova značenja:",
|
||||
"icon_crown": "Kruna - Ovo je igrač broj 1 na ljestvici",
|
||||
"icon_traitor": "Ukršteni mačevi - Izdajica. Ovaj igrač je napao saveznika.",
|
||||
"icon_ally": "Rukovanje - Saveznik. Ovaj igrač ti je saveznik.",
|
||||
"info_enemy_panel": "Informacije o neprijatelju",
|
||||
"action_emote": "Otvori izbornik emotikona"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Igraj sam",
|
||||
"allow_alliances": "Dozvoli saveze",
|
||||
"options_title": "Opcije",
|
||||
"bots": "Botovi: ",
|
||||
"bots_disabled": "Onemogućeni",
|
||||
"disable_nations": "Onemogući nacije",
|
||||
"instant_build": "Neposredna izgradnja",
|
||||
"infinite_gold": "Beskrajno zlato",
|
||||
"infinite_troops": "Beskrajna vojska",
|
||||
"disable_nukes": "Onemogući nuklearna oružja",
|
||||
"start": "Započni partiju"
|
||||
},
|
||||
"map": {
|
||||
"world": "Svijet",
|
||||
"europe": "Evropa",
|
||||
"mena": "BISA",
|
||||
"northamerica": "Sjeverna Amerika",
|
||||
"oceania": "Okeanija",
|
||||
"blacksea": "Crno More",
|
||||
"africa": "Afrika",
|
||||
"asia": "Azija",
|
||||
"mars": "Mars",
|
||||
"southamerica": "Južna Amerika",
|
||||
"britannia": "Britanija",
|
||||
"gatewaytotheatlantic": "Kapije Atlantika",
|
||||
"australia": "Australija",
|
||||
"random": "Nasumična",
|
||||
"iceland": "Island",
|
||||
"pangaea": "Pangea",
|
||||
"map": "Mapa",
|
||||
"betweentwoseas": "Između dva mora",
|
||||
"japan": "Japan i susjedi",
|
||||
"knownworld": "Poznati svijet"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Pridruži se privatnoj čekaonici",
|
||||
"enter_id": "Unesi identifikaciju čekaonice",
|
||||
"player": "Igrač",
|
||||
"players": "Igrači",
|
||||
"join_lobby": "Pridruži se čekaonici",
|
||||
"checking": "Proverava se čekaonica...",
|
||||
"not_found": "Čekaonica nije pronađena. Provjeri identifikaciju i pokušaj ponovo, molim.",
|
||||
"error": "Došlo je do greške. Pokušaj ponovo, molim.",
|
||||
"joined_waiting": "Uspešan ulaz u čekaonicu. Čekamo početak partije..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "Pridruži se sledećoj partiji",
|
||||
"waiting": "je broj igrača koji čeka"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "Unesi korisničko ime",
|
||||
"not_string": "Korisničko ime mora biti string.",
|
||||
"too_short": "Korisničko ime mora imati minimum {min} karaktera.",
|
||||
"too_long": "Korisničko ime ne sme imati više od {max} karaktera.",
|
||||
"invalid_chars": "Korisničko ime može sadržati isključivo slova, cifre, prazne prostore, donje crte i [kockaste zagrade]."
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "Privatna čekaonica",
|
||||
"options_title": "Opcije",
|
||||
"bots": "Botovi: ",
|
||||
"bots_disabled": "Onemogućeni",
|
||||
"disable_nations": "Onemogući nacije",
|
||||
"instant_build": "Neposredna izgradnja",
|
||||
"infinite_gold": "Beskrajno zlato",
|
||||
"infinite_troops": "Beskrajna vojska",
|
||||
"disable_nukes": "Onemogući nuklearna oružja",
|
||||
"player": "Igrač",
|
||||
"players": "Igrači",
|
||||
"waiting": "Čekamo igrače...",
|
||||
"start": "Započni partiju",
|
||||
"mode": "Tip igre"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "Bleja",
|
||||
"Balanced": "Fer",
|
||||
"Intense": "Napeto",
|
||||
"Impossible": "Nemoguće",
|
||||
"difficulty": "Težina"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "Partija počinje...",
|
||||
"desc": "Čekaonica se priprema za start. Ček' malo."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Serbo-Croatian",
|
||||
"native": "Srpsko-Hrvatski",
|
||||
"svg": "sh_yugo",
|
||||
"lang_code": "sh"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Svako za sebe",
|
||||
"teams": "Timski"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Odaberi jezik"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"main": {
|
||||
"join_discord": "Discord'a katılın!",
|
||||
"create_lobby": "Lobi Oluştur",
|
||||
"join_lobby": "Lobiye Katıl",
|
||||
"single_player": "Tek Oyunculu",
|
||||
"instructions": "Rehber",
|
||||
"how_to_play": "Nasıl Oynanır",
|
||||
"wiki": "Wiki"
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Kısayol Tuşları",
|
||||
"table_key": "Tuş",
|
||||
"table_action": "İşlem",
|
||||
"action_alt_view": "Alternatif görünüm (arazi/ülkeler)",
|
||||
"action_attack_altclick": "Saldır (sol tıklama menü açmaya ayarlıysa)",
|
||||
"action_build": "İnşa menüsünü aç",
|
||||
"action_center": "Kamerayı oyuncuya ortala",
|
||||
"action_zoom": "Uzaklaştır/Yakınlaştır",
|
||||
"action_move_camera": "Kamerayı haraket ettir",
|
||||
"action_ratio_change": "Saldırı oranını Azalt/Artır",
|
||||
"action_reset_gfx": "Grafikleri sıfırla",
|
||||
"ui_section": "Oyun Arayüzü",
|
||||
"ui_leaderboard": "Lider Tablosu",
|
||||
"ui_leaderboard_desc": "Oyundaki en iyi oyuncuları, isimlerini, sahip olunan toprak yüzdesini (%) ve altınlarını gösterir.",
|
||||
"ui_control": "Kontrol paneli",
|
||||
"ui_control_desc": "Kontrol paneli aşağıdaki ögeleri içerir:",
|
||||
"ui_pop": "Nüfus - Sahip olduğunuz birim miktarı, maksimum nüfusunuz ve onları kazanma hızınız.",
|
||||
"ui_gold": "Altın - Sahip olduğunuz altın miktarı ve onu kazanma hızınız.",
|
||||
"ui_troops_workers": "Askerler ve İşçiler - Tahsis edilmiş asker ve işçi miktarı. Askerler saldırmak veya saldırılara karşı savunmak için kullanılır. İşçiler altın üretmek için kullanılır. Kaydırıcıyı kullanarak asker ve işçi sayısını ayarlayabilirsiniz.",
|
||||
"ui_attack_ratio": "Saldırı oranı - Saldırdığınızda kullanılacak asker miktarı. Kaydırıcıyı kullanarak saldırı oranını ayarlayabilirsiniz. Savunan birliklerden daha fazla saldıran birliğe sahip olmak, saldırıda daha az asker kaybetmenizi sağlar, daha azına sahip olmak ise saldıran birliklerinize verilen hasarı artırır. Etki 2:1 oranının ötesine geçmez.",
|
||||
"ui_options": "Seçenekler",
|
||||
"ui_options_desc": "İçerisinde aşağıdaki öğeler bulunabilir:",
|
||||
"option_pause": "Oyunu Duraklat/Devam Ettir - Sadece tek oyunculu modda kullanılabilir.",
|
||||
"option_timer": "Zamanlayıcı - Oyunun başlangıcından bu yana geçen süre.",
|
||||
"option_exit": "Çıkış düğmesi.",
|
||||
"option_settings": "Ayarlar - Ayarlar menüsünü açın. İçeride Alternatif Görünüm, Karanlık Mod, Emojiler ve sol tıklama eylemini değiştirebilirsiniz.",
|
||||
"radial_title": "Dairesel menü",
|
||||
"radial_desc": "Sağ tıklama (veya mobilde dokunma) dairesel menüyü açar. Buradan şunları yapabilirsiniz:",
|
||||
"radial_build": "İnşa menüsünü aç.",
|
||||
"radial_info": "Bilgi menüsünü aç.",
|
||||
"radial_boat": "Seçilen konuma saldırması için bir tekne gönder (sadece suya erişiminiz varsa kullanılabilir).",
|
||||
"radial_close": "Menüyü kapat.",
|
||||
"info_title": "Bilgi menüsü",
|
||||
"info_enemy_desc": "Seçilen oyuncunun adı, altını, askerleri gibi bilgileri ve oyuncunun hain olup olmadığını içerir. Hain, ittifak içinde olduğu bir oyuncuya ihanet edip saldıran oyuncudur. Aşağıdaki simgeler şu etkileşimleri temsil eder:",
|
||||
"info_target": "Oyuncuya bir hedef işareti koyun, tüm müttefikler için işaretleyin, saldırıları koordine etmek için kullanılır.",
|
||||
"info_alliance": "Oyuncuya ittifak isteği gönderin. Müttefikler kaynakları ve askerleri paylaşabilir, ancak birbirlerine saldıramazlar.",
|
||||
"info_emoji": "Oyuncuya bir emoji gönderin.",
|
||||
"info_ally_panel": "Müttefik bilgi paneli",
|
||||
"info_ally_desc": "Bir oyuncuyla ittifak kurduğunuzda, aşağıdaki yeni simgeler kullanılabilir hale gelir:",
|
||||
"ally_betray": "Müttefikinize ihanet edin, ittifakı sonlandırın. Diğer ulus kendisi hain değilse, adınızın yanında kalıcı bir simge olacaktır. Oyunun sonuna kadar size yönelik saldırılar saldırgan için daha az kayıpla sonuçlanacaktır, botların sizinle ittifak kurma olasılığı azalır ve oyuncular bunu yapmadan önce iki kez düşünür.",
|
||||
"ally_donate": "Müttefikinize askerlerinizden biraz bağışlayın. Askerleri azaldığında ve saldırı altındayken veya bir düşmanı ezmek için ekstra güce ihtiyaç duyduklarında kullanılır.",
|
||||
"build_menu_title": "İnşa menüsü",
|
||||
"build_name": "Ad",
|
||||
"build_icon": "Simge",
|
||||
"build_desc": "Açıklama",
|
||||
"build_city": "Şehir",
|
||||
"build_city_desc": "Maksimum nüfusunuzu artırır. Bölgenizi genişletemediğinizde veya nüfus sınırınıza ulaşmak üzereyken kullanışlıdır.",
|
||||
"build_defense": "Savunma Karakolu",
|
||||
"build_defense_desc": "Yakındaki sınırlar etrafındaki savunmayı artırır. Düşmanlardan gelen saldırılar daha yavaştır ve daha fazla kayıp verir.",
|
||||
"build_port": "Liman",
|
||||
"build_port_desc": "Ülkenizin limanları ile diğer ülkelerin limanları arasında otomatik olarak ticaret gemileri gönderir (onlarda \"ticareti durdur\" u tıklamadıysanız veya onlar sizde \"ticareti durdur\" u tıklamadıysa), her iki tarafa da altın verir. Savaş Gemileri inşa etmeye izin verir. Sadece su kenarına inşa edilebilir.",
|
||||
"build_warship": "Savaş Gemisi",
|
||||
"build_warship_desc": "Bir alanda devriye gezer, ticaret gemilerini ele geçirir ve düşman Savaş Gemilerini ve Teknelerini yok eder. En yakın Limandan doğar ve ilk inşa etmek için tıkladığınız alanı devriye gezer. Savaş Gemilerini üzerlerine saldırı komutu vererek ve ardından hareket etmelerini istediğiniz yeni alana saldırı komutu vererek kontrol edebilirsiniz.",
|
||||
"build_silo": "Füze Silosu",
|
||||
"build_silo_desc": "Füze fırlatmaya izin verir.",
|
||||
"build_sam": "SAM Fırlatıcı",
|
||||
"build_sam_desc": "100 piksel menzili içindeki düşman füzelerini %75 olasılıkla engeller. SAM'ın 7.5 saniye bekleme süresi vardır ve MIRV'leri engelleyemez.",
|
||||
"build_atom": "Atom Bombası",
|
||||
"build_atom_desc": "Bölgeyi, binaları, gemileri ve tekneleri yok eden küçük patlayıcı bomba. En yakın Füze Silosundan doğar ve ilk inşa etmek için tıkladığınız alana düşer.",
|
||||
"build_hydrogen": "Hidrojen Bombası",
|
||||
"build_hydrogen_desc": "Büyük patlayıcı bomba. En yakın Füze Silosundan doğar ve ilk inşa etmek için tıkladığınız alana düşer.",
|
||||
"build_mirv": "MIRV",
|
||||
"build_mirv_desc": "Oyundaki en güçlü bomba. Geniş bir bölgeyi kaplayacak daha küçük bombalara ayrılır. Yalnızca ilk inşa etmek için tıkladığınız oyuncuya hasar verir. En yakın Füze Silosundan doğar ve ilk inşa etmek için tıkladığınız alana düşer.",
|
||||
"player_icons": "Oyuncu simgeleri",
|
||||
"icon_desc": "Karşılaşacağınız bazı oyun içi simgelerin örnekleri ve anlamları:",
|
||||
"icon_crown": "Taç - Bu, skor tablosundaki 1 numaralı oyuncudur",
|
||||
"icon_traitor": "Çapraz kılıçlar - Hain. Bu oyuncu bir müttefike saldırdı.",
|
||||
"icon_ally": "El sıkışma - Müttefik. Bu oyuncu sizin müttefikinizdir.",
|
||||
"info_enemy_panel": "Düşman bilgi paneli",
|
||||
"action_emote": "İfade menüsünü aç"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Tek Oyunculu",
|
||||
"allow_alliances": "İttifaklara izin ver",
|
||||
"options_title": "Seçenekler",
|
||||
"bots": "Botlar",
|
||||
"bots_disabled": "Devre Dışı",
|
||||
"disable_nations": "Ulusları Devre Dışı Bırak",
|
||||
"instant_build": "Anında İnşa",
|
||||
"infinite_gold": "Sınırsız Altın",
|
||||
"infinite_troops": "Sınırsız Asker",
|
||||
"disable_nukes": "Nükleerleri Devre Dışı Bırak",
|
||||
"start": "Oyunu Başlat"
|
||||
},
|
||||
"map": {
|
||||
"world": "Dünya",
|
||||
"europe": "Avrupa",
|
||||
"mena": "ODKA",
|
||||
"northamerica": "Kuzey Amerika",
|
||||
"oceania": "Okyanusya",
|
||||
"blacksea": "Karadeniz",
|
||||
"africa": "Afrika",
|
||||
"asia": "Asya",
|
||||
"mars": "Mars",
|
||||
"southamerica": "Güney Amerika",
|
||||
"britannia": "Britanya",
|
||||
"gatewaytotheatlantic": "Atlantik'e Açılan Kapı",
|
||||
"australia": "Avustralya",
|
||||
"random": "Rastgele",
|
||||
"iceland": "İzlanda",
|
||||
"pangaea": "Pangea",
|
||||
"map": "Harita",
|
||||
"betweentwoseas": "İki Deniz Arası",
|
||||
"japan": "Japonya ve Komşuları",
|
||||
"knownworld": "Bilinen Dünya"
|
||||
},
|
||||
"private_lobby": {
|
||||
"title": "Özel Lobiye Katıl",
|
||||
"enter_id": "Lobi ID'sini Girin",
|
||||
"player": "Oyuncu",
|
||||
"players": "Oyuncular",
|
||||
"join_lobby": "Lobiye katıl",
|
||||
"checking": "Lobi kontrol ediliyor...",
|
||||
"not_found": "Lobi bulunamadı. Lütfen ID'yi kontrol edip tekrar deneyin.",
|
||||
"error": "Bir hata oluştu. Lütfen tekrar deneyin.",
|
||||
"joined_waiting": "Başarıyla katıldınız! Oyunun başlaması bekleniyor..."
|
||||
},
|
||||
"public_lobby": {
|
||||
"join": "Sıradaki Oyuna Katıl",
|
||||
"waiting": "oyuncu bekliyor"
|
||||
},
|
||||
"username": {
|
||||
"enter_username": "Kullanıcı adınızı girin",
|
||||
"not_string": "Kullanıcı adı bir metin olmalıdır.",
|
||||
"too_short": "Kullanıcı adı en az {min} karakter uzunluğunda olmalıdır.",
|
||||
"too_long": "Kullanıcı adı {max} karakteri geçmemelidir.",
|
||||
"invalid_chars": "Kullanıcı adı yalnızca harf, rakam, boşluk, alt çizgi ve [köşeli parantez] içerebilir."
|
||||
},
|
||||
"host_modal": {
|
||||
"title": "Özel Lobi",
|
||||
"options_title": "Seçenekler",
|
||||
"bots": "Botları:",
|
||||
"bots_disabled": "Devre Dışı",
|
||||
"disable_nations": "Ulusları Devre Dışı Bırak",
|
||||
"instant_build": "Anında İnşa",
|
||||
"infinite_gold": "Sınırsız Altın",
|
||||
"infinite_troops": "Sınırsız Asker",
|
||||
"disable_nukes": "Nükleerleri Devre Dışı Bırak",
|
||||
"player": "Oyuncu",
|
||||
"players": "Oyuncular",
|
||||
"waiting": "Oyuncular bekleniyor...",
|
||||
"start": "Oyunu Başlat",
|
||||
"mode": "Mod"
|
||||
},
|
||||
"difficulty": {
|
||||
"Relaxed": "Rahat",
|
||||
"Balanced": "Dengeli",
|
||||
"Intense": "Yoğun",
|
||||
"Impossible": "İmkansız",
|
||||
"difficulty": "Zorluk"
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "Boyun Başlıyor...",
|
||||
"desc": "Oyun başlamak üzere hazırlanıyor. Lütfen bekleyin."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Turkish",
|
||||
"native": "Türkçe",
|
||||
"svg": "tr",
|
||||
"lang_code": "tr"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Herkes Tek",
|
||||
"teams": "Takımlar"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Dil seç"
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@
|
||||
},
|
||||
"help_modal": {
|
||||
"hotkeys": "Гарячі клавіші",
|
||||
"table_key": "Клавіша",
|
||||
"table_key": "Клавіш",
|
||||
"table_action": "Дія",
|
||||
"action_alt_view": "Альтернативний вигляд (ландшафт/країни)",
|
||||
"action_alt_view": "Альтернативний вигляд (топогорафія/країни)",
|
||||
"action_attack_altclick": "Атака (коли клацання лівою кнопкою миші призначено на відкриття меню)",
|
||||
"action_build": "Відкрити меню будівництва",
|
||||
"action_center": "Відцентрувати камеру на гравцеві",
|
||||
"action_zoom": "Віддалити/Приблизити",
|
||||
"action_zoom": "Зменшити/Збільшити масштаб",
|
||||
"action_move_camera": "Перемістити камеру",
|
||||
"action_ratio_change": "Зменшити/Збільшити співвідношення атаки",
|
||||
"action_reset_gfx": "Скинути графіку",
|
||||
@@ -28,15 +28,15 @@
|
||||
"ui_pop": "Населення — Кількість ваших підрозділів, максимальне населення та темп його приросту.",
|
||||
"ui_gold": "Золото — Обсяг вашого золота та швидкість, з якою ви отримуєте його.",
|
||||
"ui_troops_workers": "Війська та Робітники — Кількість призначених військ і робітників. Війська використовуються для атаки або захисту від атак. Робітники використовуються для видобування золота. Ви можете регулювати кількість військ і робітників використовуючи повзунок.",
|
||||
"ui_attack_ratio": "Співвідношення атаки — Кількість військ, що використовуватиметься під час атаки. Ви можете відрегулювати співвідношення атаки використовуючи повзунок.",
|
||||
"ui_attack_ratio": "Співвідношення атаки — Кількість військ, що буде використано під час атаки. Ви можете налаштувати співвідношення атаки використовуючи повзунок. Маючи більше військ нападу, аніж захисту, ви зменшите втрати під час атаки, а менше — збільшите шкоду, що буде завдано вашим військам нападу. Ефект не перевищує співвідношення 2:1.",
|
||||
"ui_options": "Налаштування",
|
||||
"ui_options_desc": "Серед них можна знайти наступні елементи:",
|
||||
"option_pause": "Призупинити/Продовжити гру — доступно лише в режимі гри наодинці.",
|
||||
"option_pause": "Призупинити/Продовжити гру — Доступно лише в режимі гри наодинці.",
|
||||
"option_timer": "Таймер — Час, що минув із початку гри.",
|
||||
"option_exit": "Кнопка виходу.",
|
||||
"option_settings": "Налаштування — Відкрити меню налаштувань. В ньому можна перемкнути режим альтернативного вигляду, темний режим, емодзі та виконання дії при клацанні лівою кнопкою миші.",
|
||||
"radial_title": "Кругове меню",
|
||||
"radial_desc": "Правий клац (або дотик на мобільному пристрої) відкриває кругове меню. В ньому ви можете:",
|
||||
"radial_desc": "Правий клац (або тиць на мобільному пристрої) відкриває кругове меню. В ньому можна:",
|
||||
"radial_build": "Відкрити меню будівництва.",
|
||||
"radial_info": "Відкрити меню інформації.",
|
||||
"radial_boat": "Надіслати човен для атаки вибраного місця (доступно лише якщо ви маєте доступ до води).",
|
||||
@@ -48,7 +48,7 @@
|
||||
"info_emoji": "Відправити емодзі гравцю.",
|
||||
"info_ally_panel": "Панель інформації союзника",
|
||||
"info_ally_desc": "Коли ви укладете альянс із гравцем, стануть доступними наступні значки:",
|
||||
"ally_betray": "Зрадити союзника, розірвавши альянс. Ви отримаєте постійний значок поруч із вашим іменем. Боти рідше укладатимуть із вами альянси, а гравці подумають двічі, перш ніж робити це.",
|
||||
"ally_betray": "Зрадити свого союзника, розриваючи альянс. Поруч з вашим іменем з'явиться постійний значок, але тільки якщо інша нація до цього не була зрадником. Атаки на вас завдаватимуть менше втрат нападникам до кінця гри, боти рідше укладатимуть із вами альянси, а гравці спочатку двічі подумають, перш ніж співпрацювати.",
|
||||
"ally_donate": "Пожертвувати частину своїх військ союзнику. Використовується, коли в нього мало військ і його атакують, або коли йому необхідна додаткова сила для знищення ворога.",
|
||||
"build_menu_title": "Меню будівництва",
|
||||
"build_name": "Назва",
|
||||
@@ -61,7 +61,7 @@
|
||||
"build_port": "Порт",
|
||||
"build_port_desc": "Автоматично відправляє торгові кораблі між портами вашої країни та іншими країнами (за винятком випадків, коли ви натиснули «припинити торгівлю» на них або вони натиснули кнопку «припинити торгівлю» на вас), даючи золото обом сторонам. Дозволяє будувати військові кораблі. Можна розміщати тільки біля води.",
|
||||
"build_warship": "Військовий корабель",
|
||||
"build_warship_desc": "Патрулює територію, захоплюючи торгові кораблі та знищуючи ворожі кораблі й човни. Будується в найближчому порту й патрулює територію, вибрану клацанням кнопкою миші.",
|
||||
"build_warship_desc": "Патрулює територію, захоплюючи торгові кораблі та знищуючи ворожі військові кораблі й катери. З'являється з найближчого порту та патрулює ділянку, вибрану клацанням при створенні. Можна керувати військовими кораблями кнопкою атаки: спочатку клацніть на корабель, а потім — на ділянку, до якої бажаєте його перемістити.",
|
||||
"build_silo": "Ракетна шахта",
|
||||
"build_silo_desc": "Дає можливість запускати ракети.",
|
||||
"build_sam": "Пускова установка ЗРК",
|
||||
@@ -77,7 +77,8 @@
|
||||
"icon_crown": "Корона — Це гравець номер 1 у таблиці лідерів",
|
||||
"icon_traitor": "Перехрещені мечі — Зрадник. Цей гравець атакував союзника.",
|
||||
"icon_ally": "Рукостискання — Союзник. Цей гравець є вашим союзником.",
|
||||
"info_enemy_panel": "Панель інформації ворога"
|
||||
"info_enemy_panel": "Панель інформації ворога",
|
||||
"action_emote": "Відкрити меню емодзі"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Гра наодинці",
|
||||
@@ -161,7 +162,7 @@
|
||||
},
|
||||
"game_starting_modal": {
|
||||
"title": "Гра починається...",
|
||||
"desc": "Підготовка запуску лобі. Будь ласка, зачекайте."
|
||||
"desc": "Підготовка до запуску лобі. Будь ласка, зачекайте."
|
||||
},
|
||||
"lang": {
|
||||
"en": "Ukrainian",
|
||||
@@ -170,7 +171,10 @@
|
||||
"lang_code": "uk"
|
||||
},
|
||||
"game_mode": {
|
||||
"ffa": "Вільна гра (FFA)",
|
||||
"ffa": "Всі проти всіх (FFA)",
|
||||
"teams": "Команди"
|
||||
},
|
||||
"select_lang": {
|
||||
"title": "Виберіть мову"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"coordinates": [1094, 1093],
|
||||
"name": "Democratic Republic of the Congo",
|
||||
"strength": 2,
|
||||
"flag": "cg"
|
||||
"flag": "cd"
|
||||
},
|
||||
{
|
||||
"coordinates": [1021, 1365],
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [246, 746],
|
||||
"name": "Hous Tully",
|
||||
"name": "House Tully",
|
||||
"strength": 3
|
||||
},
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [1409, 372],
|
||||
"name": "Palestinian Territory, Occupied",
|
||||
"name": "Palestinian Territory",
|
||||
"strength": 1,
|
||||
"flag": "ps"
|
||||
},
|
||||
@@ -173,7 +173,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [98, 55],
|
||||
"name": "2",
|
||||
"name": "Mauritania",
|
||||
"strength": 1,
|
||||
"flag": "mr"
|
||||
},
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [182, 43],
|
||||
"name": "Viet Nam",
|
||||
"name": "Vietnam",
|
||||
"strength": 1,
|
||||
"flag": "vn"
|
||||
},
|
||||
@@ -107,7 +107,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [834, 215],
|
||||
"name": "Micronesia, Federated States of",
|
||||
"name": "Federated States of Micronesia",
|
||||
"strength": 1,
|
||||
"flag": "fm"
|
||||
},
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [1238, 309],
|
||||
"name": "Iran, Islamic Republic Of",
|
||||
"name": "Islamic Republic Of Iran",
|
||||
"strength": 1,
|
||||
"flag": "ir"
|
||||
},
|
||||
@@ -239,7 +239,7 @@
|
||||
},
|
||||
{
|
||||
"coordinates": [1074, 508],
|
||||
"name": "Congo, The Democratic Republic of the",
|
||||
"name": "The Democratic Republic of the Congo",
|
||||
"strength": 1,
|
||||
"flag": "cd"
|
||||
},
|
||||
|
||||
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 248 B |
|
After Width: | Height: | Size: 102 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 154 B |
@@ -11,8 +11,7 @@ import {
|
||||
import { createGameRecord } from "../core/Util";
|
||||
import { ServerConfig } from "../core/configuration/Config";
|
||||
import { getConfig } from "../core/configuration/ConfigLoader";
|
||||
import { TeamName, Unit, UnitType } from "../core/game/Game";
|
||||
import { TileRef } from "../core/game/GameMap";
|
||||
import { Team, UnitType } from "../core/game/Game";
|
||||
import {
|
||||
ErrorUpdate,
|
||||
GameUpdateType,
|
||||
@@ -20,7 +19,7 @@ import {
|
||||
HashUpdate,
|
||||
WinUpdate,
|
||||
} from "../core/game/GameUpdates";
|
||||
import { GameView, PlayerView, UnitView } from "../core/game/GameView";
|
||||
import { GameView, PlayerView } from "../core/game/GameView";
|
||||
import { loadTerrainMap, TerrainMapData } from "../core/game/TerrainMapLoader";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { WorkerClient } from "../core/worker/WorkerClient";
|
||||
@@ -36,15 +35,6 @@ import {
|
||||
import { createCanvas } from "./Utils";
|
||||
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
|
||||
|
||||
export // Is this function needed?
|
||||
function distSortUnitWorld(tile: TileRef, game: GameView) {
|
||||
return (a: Unit | UnitView, b: Unit | UnitView) => {
|
||||
return (
|
||||
game.euclideanDist(tile, a.tile()) - game.euclideanDist(tile, b.tile())
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export interface LobbyConfig {
|
||||
serverConfig: ServerConfig;
|
||||
flag: string;
|
||||
@@ -199,13 +189,13 @@ export class ClientGameRunner {
|
||||
clientID: this.lobby.clientID,
|
||||
},
|
||||
];
|
||||
let winner: ClientID | TeamName | null = null;
|
||||
let winner: ClientID | Team | null = null;
|
||||
if (update.winnerType == "player") {
|
||||
winner = this.gameView
|
||||
.playerBySmallID(update.winner as number)
|
||||
.clientID();
|
||||
} else {
|
||||
winner = update.winner as TeamName;
|
||||
winner = update.winner as Team;
|
||||
}
|
||||
|
||||
const record = createGameRecord(
|
||||
@@ -225,6 +215,7 @@ export class ClientGameRunner {
|
||||
|
||||
public start() {
|
||||
consolex.log("starting client game");
|
||||
|
||||
this.isActive = true;
|
||||
this.lastMessageTime = Date.now();
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -35,43 +35,84 @@ export class HelpModal extends LitElement {
|
||||
</thead>
|
||||
<tbody class="text-left">
|
||||
<tr>
|
||||
<td>Space</td>
|
||||
<td><span class="key">Space</span></td>
|
||||
<td>${translateText("help_modal.action_alt_view")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift + left click</td>
|
||||
<td>
|
||||
<div class="scroll-combo-horizontal">
|
||||
<span class="key">Shift</span>
|
||||
<span class="plus">+</span>
|
||||
<div class="mouse-shell alt-left-click">
|
||||
<div class="mouse-left-corner"></div>
|
||||
<div class="mouse-wheel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>${translateText("help_modal.action_attack_altclick")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ctrl + left click</td>
|
||||
<td>
|
||||
<div class="scroll-combo-horizontal">
|
||||
<span class="key">Ctrl</span>
|
||||
<span class="plus">+</span>
|
||||
<div class="mouse-shell alt-left-click">
|
||||
<div class="mouse-left-corner"></div>
|
||||
<div class="mouse-wheel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>${translateText("help_modal.action_build")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt + left click</td>
|
||||
<td>
|
||||
<div class="scroll-combo-horizontal">
|
||||
<span class="key">Alt</span>
|
||||
<span class="plus">+</span>
|
||||
<div class="mouse-shell alt-left-click">
|
||||
<div class="mouse-left-corner"></div>
|
||||
<div class="mouse-wheel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>${translateText("help_modal.action_emote")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>C</td>
|
||||
<td><span class="key">C</span></td>
|
||||
<td>${translateText("help_modal.action_center")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Q / E</td>
|
||||
<td><span class="key">Q</span> / <span class="key">E</span></td>
|
||||
<td>${translateText("help_modal.action_zoom")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>W / A / S / D</td>
|
||||
<td><span class="key">W</span> <span class="key">A</span> <span class="key">S</span> <span class="key">D</span></td>
|
||||
<td>${translateText("help_modal.action_move_camera")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1 / 2</td>
|
||||
<td><span class="key">1</span> / <span class="key">2</span></td>
|
||||
<td>${translateText("help_modal.action_ratio_change")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift + scroll down / scroll up</td>
|
||||
<td>
|
||||
<div class="scroll-combo-horizontal">
|
||||
<span class="key">Shift</span>
|
||||
<span class="plus">+</span>
|
||||
<div class="mouse-with-arrows">
|
||||
<div class="mouse-shell">
|
||||
<div class="mouse-wheel" id="highlighted-wheel"></div>
|
||||
</div>
|
||||
<div class="mouse-arrows-side">
|
||||
<div class="arrow">↑</div>
|
||||
<div class="arrow">↓</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>${translateText("help_modal.action_ratio_change")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ALT + R</td>
|
||||
<td><span class="key">ALT</span> + <span class="key">R</span></td>
|
||||
<td>${translateText("help_modal.action_reset_gfx")}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -23,6 +23,7 @@ export class HostLobbyModal extends LitElement {
|
||||
@state() private selectedDifficulty: Difficulty = Difficulty.Medium;
|
||||
@state() private disableNPCs = false;
|
||||
@state() private gameMode: GameMode = GameMode.FFA;
|
||||
@state() private teamCount: number = 2;
|
||||
@state() private disableNukes: boolean = false;
|
||||
@state() private bots: number = 400;
|
||||
@state() private infiniteGold: boolean = false;
|
||||
@@ -159,6 +160,33 @@ export class HostLobbyModal extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${
|
||||
this.gameMode === GameMode.FFA
|
||||
? ""
|
||||
: html`
|
||||
<!-- Team Count Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
${translateText("host_modal.team_count")}
|
||||
</div>
|
||||
<div class="option-cards">
|
||||
${[2, 3, 4, 5, 6, 7].map(
|
||||
(o) => html`
|
||||
<div
|
||||
class="option-card ${this.teamCount === o
|
||||
? "selected"
|
||||
: ""}"
|
||||
@click=${() => this.handleTeamCountSelection(o)}
|
||||
>
|
||||
<div class="option-card-title">${o}</div>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
<!-- Game Options -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
@@ -413,6 +441,11 @@ export class HostLobbyModal extends LitElement {
|
||||
this.putGameConfig();
|
||||
}
|
||||
|
||||
private async handleTeamCountSelection(value: number) {
|
||||
this.teamCount = value;
|
||||
this.putGameConfig();
|
||||
}
|
||||
|
||||
private async putGameConfig() {
|
||||
const config = await getServerConfigFromClient();
|
||||
const response = await fetch(
|
||||
@@ -432,6 +465,7 @@ export class HostLobbyModal extends LitElement {
|
||||
infiniteTroops: this.infiniteTroops,
|
||||
instantBuild: this.instantBuild,
|
||||
gameMode: this.gameMode,
|
||||
numPlayerTeams: this.teamCount,
|
||||
} as GameConfig),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,14 +3,21 @@ import { customElement, state } from "lit/decorators.js";
|
||||
import "./LanguageModal";
|
||||
|
||||
import bg from "../../resources/lang/bg.json";
|
||||
import bn from "../../resources/lang/bn.json";
|
||||
import de from "../../resources/lang/de.json";
|
||||
import en from "../../resources/lang/en.json";
|
||||
import eo from "../../resources/lang/eo.json";
|
||||
import es from "../../resources/lang/es.json";
|
||||
import fr from "../../resources/lang/fr.json";
|
||||
import hi from "../../resources/lang/hi.json";
|
||||
import it from "../../resources/lang/it.json";
|
||||
import ja from "../../resources/lang/ja.json";
|
||||
import nl from "../../resources/lang/nl.json";
|
||||
import pl from "../../resources/lang/pl.json";
|
||||
import pt_br from "../../resources/lang/pt_br.json";
|
||||
import ru from "../../resources/lang/ru.json";
|
||||
import sh from "../../resources/lang/sh.json";
|
||||
import tr from "../../resources/lang/tr.json";
|
||||
import uk from "../../resources/lang/uk.json";
|
||||
|
||||
@customElement("lang-selector")
|
||||
@@ -26,14 +33,21 @@ export class LangSelector extends LitElement {
|
||||
|
||||
private languageMap: Record<string, any> = {
|
||||
bg,
|
||||
bn,
|
||||
de,
|
||||
en,
|
||||
es,
|
||||
eo,
|
||||
fr,
|
||||
it,
|
||||
hi,
|
||||
ja,
|
||||
nl,
|
||||
pl,
|
||||
pt_br,
|
||||
ru,
|
||||
sh,
|
||||
tr,
|
||||
uk,
|
||||
};
|
||||
|
||||
@@ -246,7 +260,7 @@ export class LangSelector extends LitElement {
|
||||
: {
|
||||
native: "English",
|
||||
en: "English",
|
||||
svg: "xx",
|
||||
svg: "uk_us_flag",
|
||||
});
|
||||
|
||||
return html`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { translateText } from "../client/Utils";
|
||||
|
||||
@customElement("language-modal")
|
||||
export class LanguageModal extends LitElement {
|
||||
@@ -8,35 +9,55 @@ export class LanguageModal extends LitElement {
|
||||
@property({ type: String }) currentLang = "en";
|
||||
|
||||
static styles = css`
|
||||
.modal {
|
||||
.c-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
padding: 1rem;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 50;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.2);
|
||||
padding: 1.5rem;
|
||||
width: 24rem;
|
||||
max-width: 100%;
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.language-list {
|
||||
.c-modal__wrapper {
|
||||
background: #23232382;
|
||||
border-radius: 8px;
|
||||
min-width: 340px;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.c-modal__header {
|
||||
position: relative;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
font-size: 18px;
|
||||
background: #000000a1;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
padding: 1rem 2.4rem 1rem 1.4rem;
|
||||
}
|
||||
|
||||
.c-modal__close {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.c-modal__content {
|
||||
position: relative;
|
||||
color: #fff;
|
||||
padding: 1.4rem;
|
||||
max-height: 60dvh;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
margin-bottom: 1rem;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.lang-button {
|
||||
@@ -44,19 +65,23 @@ export class LanguageModal extends LitElement {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
transition: background-color 0.3s;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #aaa;
|
||||
background-color: #505050;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.lang-button:hover {
|
||||
background-color: #ebf8ff;
|
||||
background-color: #969696;
|
||||
}
|
||||
|
||||
.lang-button.active {
|
||||
background-color: #bee3f8;
|
||||
background-color: #aaaaaa;
|
||||
border-color: #bbb;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.flag-icon {
|
||||
@@ -65,30 +90,44 @@ export class LanguageModal extends LitElement {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background-color: #3182ce;
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
@keyframes rainbow {
|
||||
0% {
|
||||
background-color: #990033;
|
||||
}
|
||||
20% {
|
||||
background-color: #996600;
|
||||
}
|
||||
40% {
|
||||
background-color: #336600;
|
||||
}
|
||||
60% {
|
||||
background-color: #008080;
|
||||
}
|
||||
80% {
|
||||
background-color: #1c3f99;
|
||||
}
|
||||
100% {
|
||||
background-color: #5e0099;
|
||||
}
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
background-color: #2b6cb0;
|
||||
.lang-button.debug {
|
||||
animation: rainbow 10s infinite;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
border: 2px dashed aqua;
|
||||
box-shadow: 0 0 4px aqua;
|
||||
}
|
||||
`;
|
||||
|
||||
private selectLanguage(lang: string) {
|
||||
private close = () => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("language-selected", {
|
||||
detail: { lang },
|
||||
new CustomEvent("close-modal", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
updated(changedProps: Map<string, unknown>) {
|
||||
if (changedProps.has("visible")) {
|
||||
@@ -105,18 +144,36 @@ export class LanguageModal extends LitElement {
|
||||
document.body.style.overflow = "auto";
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="modal ${this.visible ? "" : "hidden"}">
|
||||
<div class="modal-content">
|
||||
<h2 class="text-xl font-semibold mb-4">Select Language</h2>
|
||||
private selectLanguage = (lang: string) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("language-selected", {
|
||||
detail: { lang },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
<div class="language-list">
|
||||
render() {
|
||||
if (!this.visible) return null;
|
||||
|
||||
return html`
|
||||
<aside class="c-modal">
|
||||
<div class="c-modal__wrapper">
|
||||
<header class="c-modal__header">
|
||||
${translateText("select_lang.title")}
|
||||
<div class="c-modal__close" @click=${this.close}>X</div>
|
||||
</header>
|
||||
|
||||
<section class="c-modal__content">
|
||||
${this.languageList.map((lang) => {
|
||||
const isActive = this.currentLang === lang.code;
|
||||
return html`
|
||||
<button
|
||||
class="lang-button ${isActive ? "active" : ""}"
|
||||
class="lang-button ${isActive ? "active" : ""} ${lang.code ===
|
||||
"debug"
|
||||
? "debug"
|
||||
: ""}"
|
||||
@click=${() => this.selectLanguage(lang.code)}
|
||||
>
|
||||
<img
|
||||
@@ -128,22 +185,9 @@ export class LanguageModal extends LitElement {
|
||||
</button>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="close-button"
|
||||
@click=${() =>
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("close-modal", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,7 @@ import {
|
||||
ServerStartGameMessageSchema,
|
||||
Turn,
|
||||
} from "../core/Schemas";
|
||||
import {
|
||||
createGameRecord,
|
||||
decompressGameRecord,
|
||||
generateID,
|
||||
} from "../core/Util";
|
||||
import { createGameRecord, decompressGameRecord } from "../core/Util";
|
||||
import { LobbyConfig } from "./ClientGameRunner";
|
||||
import { getPersistentIDFromCookie } from "./Main";
|
||||
|
||||
@@ -56,14 +52,6 @@ export class LocalServer {
|
||||
gameID: this.lobbyConfig.gameStartInfo.gameID,
|
||||
gameStartInfo: this.lobbyConfig.gameStartInfo,
|
||||
turns: this.turns,
|
||||
players: [
|
||||
{
|
||||
flag: this.lobbyConfig.flag,
|
||||
playerID: generateID(),
|
||||
clientID: this.lobbyConfig.clientID,
|
||||
username: this.lobbyConfig.playerName,
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { LanguageModal } from "./LanguageModal";
|
||||
import "./PublicLobby";
|
||||
import { PublicLobby } from "./PublicLobby";
|
||||
import { SinglePlayerModal } from "./SinglePlayerModal";
|
||||
import { UserSettingModal } from "./UserSettingModal";
|
||||
import "./UsernameInput";
|
||||
import { UsernameInput } from "./UsernameInput";
|
||||
import { generateCryptoRandomUUID } from "./Utils";
|
||||
@@ -118,6 +119,14 @@ class Client {
|
||||
hlpModal.open();
|
||||
});
|
||||
|
||||
const settingsModal = document.querySelector(
|
||||
"user-setting",
|
||||
) as UserSettingModal;
|
||||
settingsModal instanceof UserSettingModal;
|
||||
document.getElementById("settings-button").addEventListener("click", () => {
|
||||
settingsModal.open();
|
||||
});
|
||||
|
||||
const hostModal = document.querySelector(
|
||||
"host-lobby-modal",
|
||||
) as HostPrivateLobbyModal;
|
||||
@@ -200,6 +209,33 @@ class Client {
|
||||
gameRecord: lobby.gameRecord,
|
||||
},
|
||||
() => {
|
||||
console.log("Closing modals");
|
||||
document.getElementById("settings-button").classList.add("hidden");
|
||||
[
|
||||
"single-player-modal",
|
||||
"host-lobby-modal",
|
||||
"join-private-lobby-modal",
|
||||
"game-starting-modal",
|
||||
"top-bar",
|
||||
"help-modal",
|
||||
"user-setting",
|
||||
].forEach((tag) => {
|
||||
const modal = document.querySelector(tag) as HTMLElement & {
|
||||
close?: () => void;
|
||||
isModalOpen?: boolean;
|
||||
};
|
||||
if (modal?.close) {
|
||||
modal.close();
|
||||
} else if ("isModalOpen" in modal) {
|
||||
modal.isModalOpen = false;
|
||||
}
|
||||
});
|
||||
this.publicLobby.stop();
|
||||
document.querySelectorAll(".ad").forEach((ad) => {
|
||||
(ad as HTMLElement).style.display = "none";
|
||||
});
|
||||
|
||||
// show when the game loads
|
||||
const startingModal = document.querySelector(
|
||||
"game-starting-modal",
|
||||
) as GameStartingModal;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
export class MultiTabDetector {
|
||||
private focusChanges: number[] = [];
|
||||
private readonly maxFocusChanges: number = 10;
|
||||
private readonly timeWindow: number = 60_000;
|
||||
private readonly punishmentDelays: number[] = [
|
||||
2_000, 3_000, 5_000, 10_000, 30_000, 60_000,
|
||||
];
|
||||
private lastFocusChangeTime: number = 0;
|
||||
private isPunished: boolean = false;
|
||||
private isMonitoring: boolean = false;
|
||||
private startPenaltyCallback?: (duration: number) => void;
|
||||
|
||||
private numPunishmentsGiven = 0;
|
||||
|
||||
/**
|
||||
* Start monitoring for multi-tabbing behavior
|
||||
*
|
||||
* @param startPenalty Callback function when punishment starts
|
||||
*/
|
||||
public startMonitoring(startPenalty: (duration: number) => void): void {
|
||||
if (this.isMonitoring) return;
|
||||
|
||||
this.isMonitoring = true;
|
||||
this.startPenaltyCallback = startPenalty;
|
||||
|
||||
// Event listeners for window focus/blur
|
||||
window.addEventListener("blur", this.handleFocusChange.bind(this));
|
||||
window.addEventListener("focus", this.handleFocusChange.bind(this));
|
||||
|
||||
// Also track visibility changes for tab switching
|
||||
document.addEventListener(
|
||||
"visibilitychange",
|
||||
this.handleVisibilityChange.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
public stopMonitoring(): void {
|
||||
if (!this.isMonitoring) return;
|
||||
|
||||
this.isMonitoring = false;
|
||||
|
||||
// Remove event listeners
|
||||
window.removeEventListener("blur", this.handleFocusChange.bind(this));
|
||||
window.removeEventListener("focus", this.handleFocusChange.bind(this));
|
||||
document.removeEventListener(
|
||||
"visibilitychange",
|
||||
this.handleVisibilityChange.bind(this),
|
||||
);
|
||||
|
||||
// Clear data
|
||||
this.focusChanges = [];
|
||||
this.isPunished = false;
|
||||
}
|
||||
|
||||
private handleFocusChange(): void {
|
||||
const currentTime = Date.now();
|
||||
|
||||
this.recordFocusChange(currentTime);
|
||||
|
||||
// Check for multi-tabbing when focus is gained
|
||||
if (document.hasFocus() && !this.isPunished) {
|
||||
this.checkForMultiTabbing(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
private handleVisibilityChange(): void {
|
||||
const currentTime = Date.now();
|
||||
|
||||
// Record and check regardless of current focus state
|
||||
this.recordFocusChange(currentTime);
|
||||
|
||||
// Only check when tab becomes visible
|
||||
if (document.visibilityState === "visible" && !this.isPunished) {
|
||||
this.checkForMultiTabbing(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
private recordFocusChange(timestamp: number): void {
|
||||
if (Math.abs(this.lastFocusChangeTime - timestamp) < 100) {
|
||||
// Don't count multiple triggers at same time
|
||||
return;
|
||||
}
|
||||
this.focusChanges.push(timestamp);
|
||||
console.log(`pushing focus change at ${timestamp}`);
|
||||
this.lastFocusChangeTime = timestamp;
|
||||
|
||||
// Keep only recent changes
|
||||
if (this.focusChanges.length > this.maxFocusChanges) {
|
||||
this.focusChanges.shift();
|
||||
}
|
||||
}
|
||||
|
||||
private checkForMultiTabbing(currentTime: number): void {
|
||||
// Only if we have enough data points
|
||||
if (this.focusChanges.length >= this.maxFocusChanges) {
|
||||
const oldestChange = this.focusChanges[0];
|
||||
const timeSpan = currentTime - oldestChange;
|
||||
|
||||
// If changes happened within detection window
|
||||
if (timeSpan <= this.timeWindow) {
|
||||
this.applyPunishment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private applyPunishment(): void {
|
||||
// Prevent multiple punishments
|
||||
if (this.isPunished) return;
|
||||
this.isPunished = true;
|
||||
|
||||
let punishmentDelay = 0;
|
||||
if (this.numPunishmentsGiven >= this.punishmentDelays.length) {
|
||||
punishmentDelay = this.punishmentDelays[this.punishmentDelays.length - 1];
|
||||
} else {
|
||||
punishmentDelay = this.punishmentDelays[this.numPunishmentsGiven];
|
||||
}
|
||||
|
||||
this.numPunishmentsGiven++;
|
||||
|
||||
// Call the start penalty callback
|
||||
if (this.startPenaltyCallback) {
|
||||
this.startPenaltyCallback(punishmentDelay);
|
||||
}
|
||||
|
||||
// Remove penalty after delay
|
||||
setTimeout(() => {
|
||||
this.isPunished = false;
|
||||
}, punishmentDelay);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import "./components/baseComponents/Modal";
|
||||
import "./components/Difficulties";
|
||||
import { DifficultyDescription } from "./components/Difficulties";
|
||||
import "./components/Maps";
|
||||
import { FlagInput } from "./FlagInput";
|
||||
import { JoinLobbyEvent } from "./Main";
|
||||
import { UsernameInput } from "./UsernameInput";
|
||||
|
||||
@@ -29,6 +30,7 @@ export class SinglePlayerModal extends LitElement {
|
||||
@state() private instantBuild: boolean = false;
|
||||
@state() private useRandomMap: boolean = false;
|
||||
@state() private gameMode: GameMode = GameMode.FFA;
|
||||
@state() private teamCount: number = 2;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
@@ -135,6 +137,31 @@ export class SinglePlayerModal extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this.gameMode === GameMode.FFA
|
||||
? ""
|
||||
: html`
|
||||
<!-- Team Count Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
${translateText("host_modal.team_count")}
|
||||
</div>
|
||||
<div class="option-cards">
|
||||
${[2, 3, 4, 5, 6, 7].map(
|
||||
(o) => html`
|
||||
<div
|
||||
class="option-card ${this.teamCount === o
|
||||
? "selected"
|
||||
: ""}"
|
||||
@click=${() => this.handleTeamCountSelection(o)}
|
||||
>
|
||||
<div class="option-card-title">${o}</div>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
|
||||
<!-- Game Options -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
@@ -309,6 +336,10 @@ export class SinglePlayerModal extends LitElement {
|
||||
this.gameMode = value;
|
||||
}
|
||||
|
||||
private handleTeamCountSelection(value: number) {
|
||||
this.teamCount = value;
|
||||
}
|
||||
|
||||
private getRandomMap(): GameMapType {
|
||||
const maps = Object.values(GameMapType);
|
||||
const randIdx = Math.floor(Math.random() * maps.length);
|
||||
@@ -334,6 +365,10 @@ export class SinglePlayerModal extends LitElement {
|
||||
consolex.warn("Username input element not found");
|
||||
}
|
||||
|
||||
const flagInput = document.querySelector("flag-input") as FlagInput;
|
||||
if (!flagInput) {
|
||||
consolex.warn("Flag input element not found");
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("join-lobby", {
|
||||
detail: {
|
||||
@@ -346,12 +381,17 @@ export class SinglePlayerModal extends LitElement {
|
||||
playerID: generateID(),
|
||||
clientID,
|
||||
username: usernameInput.getCurrentUsername(),
|
||||
flag:
|
||||
flagInput.getCurrentFlag() == "xx"
|
||||
? ""
|
||||
: flagInput.getCurrentFlag(),
|
||||
},
|
||||
],
|
||||
config: {
|
||||
gameMap: this.selectedMap,
|
||||
gameType: GameType.Singleplayer,
|
||||
gameMode: this.gameMode,
|
||||
numPlayerTeams: this.teamCount,
|
||||
difficulty: this.selectedDifficulty,
|
||||
disableNPCs: this.disableNPCs,
|
||||
disableNukes: this.disableNukes,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
GameType,
|
||||
PlayerID,
|
||||
PlayerType,
|
||||
TeamName,
|
||||
Team,
|
||||
Tick,
|
||||
UnitType,
|
||||
} from "../core/game/Game";
|
||||
@@ -128,7 +128,7 @@ export class SendSetTargetTroopRatioEvent implements GameEvent {
|
||||
|
||||
export class SendWinnerEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly winner: ClientID | TeamName,
|
||||
public readonly winner: ClientID | Team,
|
||||
public readonly allPlayersStats: AllPlayersStats,
|
||||
public readonly winnerType: "player" | "team",
|
||||
) {}
|
||||
@@ -337,6 +337,7 @@ export class Transport {
|
||||
lastTurn: numTurns,
|
||||
persistentID: this.lobbyConfig.persistentID,
|
||||
username: this.lobbyConfig.playerName,
|
||||
flag: this.lobbyConfig.flag,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import "./components/baseComponents/setting/SettingNumber";
|
||||
import "./components/baseComponents/setting/SettingSlider";
|
||||
import "./components/baseComponents/setting/SettingToggle";
|
||||
|
||||
@customElement("user-setting")
|
||||
export class UserSettingModal extends LitElement {
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
|
||||
@state() private darkMode: boolean = this.userSettings.darkMode();
|
||||
|
||||
@state() private keySequence: string[] = [];
|
||||
@state() private showEasterEggSettings = false;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("keydown", this.handleKeyDown);
|
||||
}
|
||||
|
||||
@query("o-modal") private modalEl!: HTMLElement & {
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
isModalOpen: boolean;
|
||||
};
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener("keydown", this.handleKeyDown);
|
||||
super.disconnectedCallback();
|
||||
document.body.style.overflow = "auto";
|
||||
}
|
||||
|
||||
private handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (!this.modalEl?.isModalOpen || this.showEasterEggSettings) return;
|
||||
|
||||
const key = e.key.toLowerCase();
|
||||
const nextSequence = [...this.keySequence, key].slice(-4);
|
||||
this.keySequence = nextSequence;
|
||||
|
||||
if (nextSequence.join("") === "evan") {
|
||||
this.triggerEasterEgg();
|
||||
this.keySequence = [];
|
||||
}
|
||||
};
|
||||
|
||||
private triggerEasterEgg() {
|
||||
console.log("🪺 Setting~ unlocked by EVAN combo!");
|
||||
this.showEasterEggSettings = true;
|
||||
const popup = document.createElement("div");
|
||||
popup.className = "easter-egg-popup";
|
||||
popup.textContent = "🎉 You found a secret setting!";
|
||||
document.body.appendChild(popup);
|
||||
|
||||
setTimeout(() => {
|
||||
popup.remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
toggleDarkMode(e: CustomEvent<{ checked: boolean }>) {
|
||||
const enabled = e.detail?.checked;
|
||||
|
||||
if (typeof enabled !== "boolean") {
|
||||
console.warn("Unexpected toggle event payload", e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.userSettings.set("settings.darkMode", enabled);
|
||||
|
||||
if (enabled) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
|
||||
console.log("🌙 Dark Mode:", enabled ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
private toggleEmojis(e: CustomEvent<{ checked: boolean }>) {
|
||||
const enabled = e.detail?.checked;
|
||||
if (typeof enabled !== "boolean") return;
|
||||
|
||||
this.userSettings.set("settings.emojis", enabled);
|
||||
|
||||
console.log("🤡 Emojis:", enabled ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
private toggleLeftClickOpensMenu(e: CustomEvent<{ checked: boolean }>) {
|
||||
const enabled = e.detail?.checked;
|
||||
if (typeof enabled !== "boolean") return;
|
||||
|
||||
this.userSettings.set("settings.leftClickOpensMenu", enabled);
|
||||
console.log("🖱️ Left Click Opens Menu:", enabled ? "ON" : "OFF");
|
||||
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private sliderAttackRatio(e: CustomEvent<{ value: number }>) {
|
||||
const value = e.detail?.value;
|
||||
if (typeof value === "number") {
|
||||
const ratio = value / 100;
|
||||
localStorage.setItem("settings.attackRatio", ratio.toString());
|
||||
} else {
|
||||
console.warn("Slider event missing detail.value", e);
|
||||
}
|
||||
}
|
||||
|
||||
private sliderTroopRatio(e: CustomEvent<{ value: number }>) {
|
||||
const value = e.detail?.value;
|
||||
if (typeof value === "number") {
|
||||
const ratio = value / 100;
|
||||
localStorage.setItem("settings.troopRatio", ratio.toString());
|
||||
} else {
|
||||
console.warn("Slider event missing detail.value", e);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<o-modal title="User Settings">
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-content user-setting-modal">
|
||||
<div class="settings-list">
|
||||
<setting-toggle
|
||||
label="🌙 Dark Mode"
|
||||
description="Toggle the site’s appearance between light and dark themes"
|
||||
id="dark-mode-toggle"
|
||||
.checked=${this.userSettings.darkMode()}
|
||||
@change=${(e: CustomEvent<{ checked: boolean }>) =>
|
||||
this.toggleDarkMode(e)}
|
||||
></setting-toggle>
|
||||
|
||||
<setting-toggle
|
||||
label="😊 Emojis"
|
||||
description="Toggle whether emojis are shown in game"
|
||||
id="emoji-toggle"
|
||||
.checked=${this.userSettings.emojis()}
|
||||
@change=${this.toggleEmojis}
|
||||
></setting-toggle>
|
||||
|
||||
<setting-toggle
|
||||
label="🖱️ Left Click to Open Menu"
|
||||
description="When ON, left-click opens menu and sword button attacks. When OFF, right-click attacks directly."
|
||||
id="left-click-toggle"
|
||||
.checked=${this.userSettings.leftClickOpensMenu()}
|
||||
@change=${this.toggleLeftClickOpensMenu}
|
||||
></setting-toggle>
|
||||
|
||||
<setting-slider
|
||||
label="⚔️ Attack Ratio"
|
||||
description="What percentage of your troops to send in an attack (1–100%)"
|
||||
min="1"
|
||||
max="100"
|
||||
.value=${Number(
|
||||
localStorage.getItem("settings.attackRatio") ?? "0.2",
|
||||
) * 100}
|
||||
@change=${this.sliderAttackRatio}
|
||||
></setting-slider>
|
||||
|
||||
<setting-slider
|
||||
label="🪖🛠️ Troops and Workers Ratio"
|
||||
description="Adjust the balance between troops (for combat) and workers (for gold production) (1–100%)"
|
||||
min="1"
|
||||
max="100"
|
||||
.value=${Number(
|
||||
localStorage.getItem("settings.troopRatio") ?? "0.95",
|
||||
) * 100}
|
||||
@change=${this.sliderTroopRatio}
|
||||
></setting-slider>
|
||||
|
||||
${this.showEasterEggSettings
|
||||
? html`
|
||||
<setting-slider
|
||||
label="Writing Speed Multiplier"
|
||||
description="Adjust how fast you pretend to code (x1–x100)"
|
||||
min="0"
|
||||
max="100"
|
||||
value="40"
|
||||
easter="true"
|
||||
@change=${(e: CustomEvent) => {
|
||||
const value = e.detail?.value;
|
||||
if (typeof value !== "undefined") {
|
||||
console.log("Changed:", value);
|
||||
} else {
|
||||
console.warn("Slider event missing detail.value", e);
|
||||
}
|
||||
}}
|
||||
></setting-slider>
|
||||
|
||||
<setting-number
|
||||
label="Bug Count"
|
||||
description="How many bugs you're okay with (0–1000, emotionally)"
|
||||
value="100"
|
||||
min="0"
|
||||
max="1000"
|
||||
easter="true"
|
||||
@change=${(e: CustomEvent) => {
|
||||
const value = e.detail?.value;
|
||||
if (typeof value !== "undefined") {
|
||||
console.log("Changed:", value);
|
||||
} else {
|
||||
console.warn("Slider event missing detail.value", e);
|
||||
}
|
||||
}}
|
||||
></setting-number>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</o-modal>
|
||||
`;
|
||||
}
|
||||
|
||||
public open() {
|
||||
this.modalEl?.open();
|
||||
}
|
||||
|
||||
public close() {
|
||||
this.modalEl?.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
@customElement("setting-number")
|
||||
export class SettingNumber extends LitElement {
|
||||
@property() label = "Setting";
|
||||
@property() description = "";
|
||||
@property({ type: Number }) value = 0;
|
||||
@property({ type: Number }) min = 0;
|
||||
@property({ type: Number }) max = 100;
|
||||
@property({ type: Boolean }) easter = false;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private handleInput(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
const newValue = Number(input.value);
|
||||
this.value = newValue;
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("change", {
|
||||
detail: { value: newValue },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="setting-item${this.easter ? " easter-egg" : ""}">
|
||||
<div class="setting-label-group">
|
||||
<label class="setting-label" for="setting-number-input"
|
||||
>${this.label}</label
|
||||
>
|
||||
<div class="setting-description">${this.description}</div>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
id="setting-number-input"
|
||||
class="setting-input number"
|
||||
.value=${String(this.value ?? 0)}
|
||||
min=${this.min}
|
||||
max=${this.max}
|
||||
@input=${this.handleInput}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
@customElement("setting-slider")
|
||||
export class SettingSlider extends LitElement {
|
||||
@property() label = "Setting";
|
||||
@property() description = "";
|
||||
@property({ type: Number }) value = 0;
|
||||
@property({ type: Number }) min = 0;
|
||||
@property({ type: Number }) max = 100;
|
||||
@property({ type: Boolean }) easter = false;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private handleInput(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
this.value = Number(input.value);
|
||||
this.updateSliderStyle(input);
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("change", {
|
||||
detail: { value: this.value },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private handleSliderChange(e: Event) {
|
||||
const detail = (e as CustomEvent)?.detail;
|
||||
if (!detail || typeof detail.value === "undefined") {
|
||||
console.warn("Invalid slider change event", e);
|
||||
return;
|
||||
}
|
||||
|
||||
const value = detail.value;
|
||||
console.log("Slider changed to", value);
|
||||
}
|
||||
|
||||
private updateSliderStyle(slider: HTMLInputElement) {
|
||||
const percent = ((this.value - this.min) / (this.max - this.min)) * 100;
|
||||
slider.style.background = `linear-gradient(to right, #2196f3 ${percent}%, #444 ${percent}%)`;
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
const slider = this.renderRoot.querySelector(
|
||||
"input[type=range]",
|
||||
) as HTMLInputElement;
|
||||
if (slider) this.updateSliderStyle(slider);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="setting-item vertical${this.easter ? " easter-egg" : ""}">
|
||||
<div class="setting-label-group">
|
||||
<label class="setting-label" for="setting-slider-input"
|
||||
>${this.label}</label
|
||||
>
|
||||
<div class="setting-description">${this.description}</div>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
id="setting-slider-input"
|
||||
class="setting-input slider full-width"
|
||||
min=${this.min}
|
||||
max=${this.max}
|
||||
.value=${String(this.value)}
|
||||
@input=${this.handleInput}
|
||||
/>
|
||||
<div class="slider-value">${this.value}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
@customElement("setting-toggle")
|
||||
export class SettingToggle extends LitElement {
|
||||
@property() label = "Setting";
|
||||
@property() description = "";
|
||||
@property() id = "";
|
||||
@property({ type: Boolean, reflect: true }) checked = false;
|
||||
@property({ type: Boolean }) easter = false;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private handleChange(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
this.checked = input.checked;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("change", {
|
||||
detail: { checked: this.checked },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="setting-item vertical${this.easter ? " easter-egg" : ""}">
|
||||
<div class="toggle-row">
|
||||
<label class="setting-label" for=${this.id}>${this.label}</label>
|
||||
<label class="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
id=${this.id}
|
||||
?checked=${this.checked}
|
||||
@change=${this.handleChange}
|
||||
/>
|
||||
<span class="slider-round"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-description">${this.description}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { EmojiTable } from "./layers/EmojiTable";
|
||||
import { EventsDisplay } from "./layers/EventsDisplay";
|
||||
import { Layer } from "./layers/Layer";
|
||||
import { Leaderboard } from "./layers/Leaderboard";
|
||||
import { MultiTabModal } from "./layers/MultiTabModal";
|
||||
import { NameLayer } from "./layers/NameLayer";
|
||||
import { OptionsMenu } from "./layers/OptionsMenu";
|
||||
import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
|
||||
@@ -125,8 +126,16 @@ export function createRenderer(
|
||||
playerPanel.eventBus = eventBus;
|
||||
playerPanel.emojiTable = emojiTable;
|
||||
|
||||
const multiTabModal = document.querySelector(
|
||||
"multi-tab-modal",
|
||||
) as MultiTabModal;
|
||||
if (!(multiTabModal instanceof MultiTabModal)) {
|
||||
console.error("multi-tab modal not found");
|
||||
}
|
||||
multiTabModal.game = game;
|
||||
|
||||
const layers: Layer[] = [
|
||||
new TerrainLayer(game),
|
||||
new TerrainLayer(game, transformHandler),
|
||||
new TerritoryLayer(game, eventBus),
|
||||
new StructureLayer(game, eventBus),
|
||||
new UnitLayer(game, eventBus, clientID, transformHandler),
|
||||
@@ -153,6 +162,7 @@ export function createRenderer(
|
||||
optionsMenu,
|
||||
topBar,
|
||||
playerPanel,
|
||||
multiTabModal,
|
||||
];
|
||||
|
||||
return new GameRenderer(
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import { Colord } from "colord";
|
||||
import atomBombSprite from "../../../resources/sprites/atombomb.png";
|
||||
import hydrogenBombSprite from "../../../resources/sprites/hydrogenbomb.png";
|
||||
import mirvSprite from "../../../resources/sprites/mirv2.png";
|
||||
import samMissileSprite from "../../../resources/sprites/samMissile.png";
|
||||
import tradeShipSprite from "../../../resources/sprites/tradeship.png";
|
||||
import transportShipSprite from "../../../resources/sprites/transportship.png";
|
||||
import warshipSprite from "../../../resources/sprites/warship.png";
|
||||
import { Theme } from "../../core/configuration/Config";
|
||||
import { UnitType } from "../../core/game/Game";
|
||||
import { UnitView } from "../../core/game/GameView";
|
||||
|
||||
const SPRITE_CONFIG: Partial<Record<UnitType, string>> = {
|
||||
[UnitType.TransportShip]: transportShipSprite,
|
||||
[UnitType.Warship]: warshipSprite,
|
||||
[UnitType.SAMMissile]: samMissileSprite,
|
||||
[UnitType.AtomBomb]: atomBombSprite,
|
||||
[UnitType.HydrogenBomb]: hydrogenBombSprite,
|
||||
[UnitType.TradeShip]: tradeShipSprite,
|
||||
[UnitType.MIRV]: mirvSprite,
|
||||
};
|
||||
|
||||
const spriteMap: Map<UnitType, ImageBitmap> = new Map();
|
||||
|
||||
// preload all images
|
||||
export const loadAllSprites = async (): Promise<void> => {
|
||||
const entries = Object.entries(SPRITE_CONFIG);
|
||||
const totalSprites = entries.length;
|
||||
let loadedCount = 0;
|
||||
|
||||
await Promise.all(
|
||||
entries.map(async ([unitType, url]) => {
|
||||
const typedUnitType = unitType as UnitType;
|
||||
|
||||
if (!url || url === "") {
|
||||
console.warn(`No sprite URL for ${typedUnitType}, skipping...`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = url;
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
img.onload = () => resolve();
|
||||
img.onerror = (err) => reject(err);
|
||||
});
|
||||
|
||||
const bitmap = await createImageBitmap(img);
|
||||
spriteMap.set(typedUnitType, bitmap);
|
||||
loadedCount++;
|
||||
|
||||
if (loadedCount === totalSprites) {
|
||||
console.log("All sprites loaded.");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to load sprite for ${typedUnitType}:`, err);
|
||||
}
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const getSpriteForUnit = (unitType: UnitType): ImageBitmap | null => {
|
||||
return spriteMap.get(unitType) ?? null;
|
||||
};
|
||||
|
||||
export const isSpriteReady = (unitType: UnitType): boolean => {
|
||||
return spriteMap.has(unitType);
|
||||
};
|
||||
|
||||
const coloredSpriteCache: Map<string, HTMLCanvasElement> = new Map();
|
||||
|
||||
// puts the sprite in an canvas colors it and caches the colored canvas
|
||||
export const getColoredSprite = (
|
||||
unit: UnitView,
|
||||
theme: Theme,
|
||||
customTerritoryColor?: Colord,
|
||||
customBorderColor?: Colord,
|
||||
): HTMLCanvasElement => {
|
||||
const owner = unit.owner();
|
||||
const territoryColor = customTerritoryColor ?? theme.territoryColor(owner);
|
||||
const borderColor = customBorderColor ?? theme.borderColor(owner);
|
||||
const spawnHighlightColor = theme.spawnHighlightColor();
|
||||
const colorKey = customTerritoryColor
|
||||
? customTerritoryColor.toRgbString()
|
||||
: "";
|
||||
const key = owner.id() + unit.type() + colorKey;
|
||||
|
||||
if (coloredSpriteCache.has(key)) {
|
||||
return coloredSpriteCache.get(key)!;
|
||||
}
|
||||
|
||||
const sprite = getSpriteForUnit(unit.type());
|
||||
|
||||
const territoryRgb = territoryColor.toRgb();
|
||||
const borderRgb = borderColor.toRgb();
|
||||
const spawnHighlightRgb = spawnHighlightColor.toRgb();
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
canvas.width = sprite.width;
|
||||
canvas.height = sprite.height;
|
||||
|
||||
ctx.drawImage(sprite, 0, 0);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const data = imageData.data;
|
||||
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const r = data[i];
|
||||
const g = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
|
||||
if (r === 180 && g === 180 && b === 180) {
|
||||
data[i] = territoryRgb.r;
|
||||
data[i + 1] = territoryRgb.g;
|
||||
data[i + 2] = territoryRgb.b;
|
||||
}
|
||||
|
||||
if (r === 70 && g === 70 && b === 70) {
|
||||
data[i] = borderRgb.r;
|
||||
data[i + 1] = borderRgb.g;
|
||||
data[i + 2] = borderRgb.b;
|
||||
}
|
||||
|
||||
if (r === 130 && g === 130 && b === 130) {
|
||||
data[i] = spawnHighlightRgb.r;
|
||||
data[i + 1] = spawnHighlightRgb.g;
|
||||
data[i + 2] = spawnHighlightRgb.b;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(imageData, 0.5, 0.5);
|
||||
coloredSpriteCache.set(key, canvas);
|
||||
return canvas;
|
||||
};
|
||||
@@ -97,6 +97,10 @@ export class TransformHandler {
|
||||
}
|
||||
|
||||
screenBoundingRect(): [Cell, Cell] {
|
||||
const canvasRect = this.boundingRect();
|
||||
const canvasWidth = canvasRect.width;
|
||||
const canvasHeight = canvasRect.height;
|
||||
|
||||
const LeftX = -this.game.width() / 2 / this.scale + this.offsetX;
|
||||
const TopY = -this.game.height() / 2 / this.scale + this.offsetY;
|
||||
|
||||
@@ -104,12 +108,12 @@ export class TransformHandler {
|
||||
const gameTopY = TopY + this.game.height() / 2;
|
||||
|
||||
const rightX =
|
||||
(screen.width - this.game.width() / 2) / this.scale + this.offsetX;
|
||||
const rightY =
|
||||
(screen.height - this.game.height() / 2) / this.scale + this.offsetY;
|
||||
(canvasWidth - this.game.width() / 2) / this.scale + this.offsetX;
|
||||
const bottomY =
|
||||
(canvasHeight - this.game.height() / 2) / this.scale + this.offsetY;
|
||||
|
||||
const gameRightX = rightX + this.game.width() / 2;
|
||||
const gameBottomY = rightY + this.game.height() / 2;
|
||||
const gameBottomY = bottomY + this.game.height() / 2;
|
||||
|
||||
return [
|
||||
new Cell(Math.floor(gameLeftX), Math.floor(gameTopY)),
|
||||
|
||||
@@ -56,8 +56,16 @@ export class ControlPanel extends LitElement implements Layer {
|
||||
|
||||
private _popRateIsIncreasing: boolean = true;
|
||||
|
||||
private init_: boolean = false;
|
||||
|
||||
init() {
|
||||
this.attackRatio = 0.2;
|
||||
this.attackRatio = Number(
|
||||
localStorage.getItem("settings.attackRatio") ?? "0.2",
|
||||
);
|
||||
this.targetTroopRatio = Number(
|
||||
localStorage.getItem("settings.troopRatio") ?? "0.95",
|
||||
);
|
||||
this.init_ = true;
|
||||
this.uiState.attackRatio = this.attackRatio;
|
||||
this.currentTroopRatio = this.targetTroopRatio;
|
||||
this.eventBus.on(AttackRatioEvent, (event) => {
|
||||
@@ -87,6 +95,13 @@ export class ControlPanel extends LitElement implements Layer {
|
||||
}
|
||||
|
||||
tick() {
|
||||
if (this.init_) {
|
||||
this.eventBus.emit(
|
||||
new SendSetTargetTroopRatioEvent(this.targetTroopRatio),
|
||||
);
|
||||
this.init_ = false;
|
||||
}
|
||||
|
||||
if (!this._isVisible && !this.game.inSpawnPhase()) {
|
||||
this.setVisibile(true);
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
});
|
||||
} else if (betrayed === myPlayer) {
|
||||
this.addEvent({
|
||||
description: `${traitor.name()}, broke their alliance with you`,
|
||||
description: `${traitor.name()} broke their alliance with you`,
|
||||
type: MessageType.ERROR,
|
||||
highlight: true,
|
||||
createdAt: this.game.ticks(),
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { GameType } from "../../../core/game/Game";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { MultiTabDetector } from "../../MultiTabDetector";
|
||||
import { translateText } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
@customElement("multi-tab-modal")
|
||||
export class MultiTabModal extends LitElement implements Layer {
|
||||
public game: GameView;
|
||||
|
||||
private detector: MultiTabDetector;
|
||||
|
||||
@property({ type: Number }) duration: number = 5000;
|
||||
@state() private countdown: number = 5;
|
||||
@state() private isVisible: boolean = false;
|
||||
|
||||
private intervalId?: number;
|
||||
|
||||
// Disable shadow DOM to allow Tailwind classes to work
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
tick() {
|
||||
if (
|
||||
this.game.inSpawnPhase() ||
|
||||
this.game.config().gameConfig().gameType == GameType.Singleplayer
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!this.detector) {
|
||||
this.detector = new MultiTabDetector();
|
||||
this.detector.startMonitoring((duration: number) => {
|
||||
this.show(duration);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Show the modal with penalty information
|
||||
public show(duration: number): void {
|
||||
if (!this.game.myPlayer()?.isAlive()) {
|
||||
return;
|
||||
}
|
||||
this.duration = duration;
|
||||
this.countdown = Math.ceil(duration / 1000);
|
||||
this.isVisible = true;
|
||||
|
||||
// Start countdown timer
|
||||
this.intervalId = window.setInterval(() => {
|
||||
this.countdown--;
|
||||
|
||||
if (this.countdown <= 0) {
|
||||
this.hide();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
// Hide the modal
|
||||
public hide(): void {
|
||||
this.isVisible = false;
|
||||
|
||||
if (this.intervalId) {
|
||||
window.clearInterval(this.intervalId);
|
||||
this.intervalId = undefined;
|
||||
}
|
||||
|
||||
// Dispatch event when modal is closed
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("penalty-complete", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this.intervalId) {
|
||||
window.clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="fixed inset-0 z-50 overflow-auto bg-red-500/20 flex items-center justify-center"
|
||||
>
|
||||
<div
|
||||
class="relative p-6 bg-white dark:bg-gray-800 rounded-xl shadow-xl max-w-md w-full m-4 transition-all transform"
|
||||
>
|
||||
<h2 class="text-2xl font-bold mb-4 text-red-600 dark:text-red-400">
|
||||
${translateText("multi_tab.warning")}
|
||||
</h2>
|
||||
|
||||
<p class="mb-4 text-gray-800 dark:text-gray-200">
|
||||
${translateText("multi_tab.detected")}
|
||||
</p>
|
||||
|
||||
<p class="mb-4 text-gray-800 dark:text-gray-200">
|
||||
${translateText("multi_tab.please_wait")}
|
||||
<span class="font-bold text-xl">${this.countdown}</span>
|
||||
${translateText("multi_tab.seconds")}
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 mb-4"
|
||||
>
|
||||
<div
|
||||
class="bg-red-600 dark:bg-red-500 h-2.5 rounded-full transition-all duration-1000 ease-linear"
|
||||
style="width: ${(this.countdown / (this.duration / 1000)) * 100}%"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
${translateText("multi_tab.explanation")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ export class OptionsMenu extends LitElement implements Layer {
|
||||
? "Opens menu"
|
||||
: "Attack"),
|
||||
})}
|
||||
${button({
|
||||
<!-- ${button({
|
||||
onClick: this.onToggleFocusLockedButtonClick,
|
||||
title: "Lock Focus",
|
||||
children:
|
||||
@@ -213,7 +213,7 @@ export class OptionsMenu extends LitElement implements Layer {
|
||||
(this.userSettings.focusLocked()
|
||||
? "Focus locked"
|
||||
: "Hover focus"),
|
||||
})}
|
||||
})} -->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -138,6 +138,7 @@ export class RadialMenu implements Layer {
|
||||
.style("touch-action", "none")
|
||||
.on("contextmenu", (e) => {
|
||||
e.preventDefault();
|
||||
this.hideRadialMenu();
|
||||
});
|
||||
|
||||
const svg = this.menuElement
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { blue, red } from "../../../core/configuration/Colors";
|
||||
import { GameMode, TeamName } from "../../../core/game/Game";
|
||||
import { GameMode, Team } from "../../../core/game/Game";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
export class SpawnTimer implements Layer {
|
||||
private ratio = 0;
|
||||
private leftColor = "rgba(0, 128, 255, 0.7)";
|
||||
private rightColor = "rgba(0, 0, 0, 0.5)";
|
||||
private ratios = [0];
|
||||
private colors = ["rgba(0, 128, 255, 0.7)", "rgba(0, 0, 0, 0.5)"];
|
||||
|
||||
constructor(
|
||||
private game: GameView,
|
||||
@@ -18,27 +16,35 @@ export class SpawnTimer implements Layer {
|
||||
|
||||
tick() {
|
||||
if (this.game.inSpawnPhase()) {
|
||||
this.ratio = this.game.ticks() / this.game.config().numSpawnPhaseTurns();
|
||||
this.ratios[0] =
|
||||
this.game.ticks() / this.game.config().numSpawnPhaseTurns();
|
||||
return;
|
||||
}
|
||||
|
||||
this.ratios = [];
|
||||
this.colors = [];
|
||||
|
||||
if (this.game.config().gameConfig().gameMode != GameMode.Team) {
|
||||
this.ratio = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const numBlueTiles = this.game
|
||||
.players()
|
||||
.filter((p) => p.teamName() == TeamName.Blue)
|
||||
.reduce((acc, p) => acc + p.numTilesOwned(), 0);
|
||||
const teamTiles: Map<Team, number> = new Map();
|
||||
for (const player of this.game.players()) {
|
||||
const team = player.team();
|
||||
const tiles = teamTiles.get(team) ?? 0;
|
||||
const sum = tiles + player.numTilesOwned();
|
||||
teamTiles.set(team, sum);
|
||||
}
|
||||
|
||||
const numRedTiles = this.game
|
||||
.players()
|
||||
.filter((p) => p.teamName() == TeamName.Red)
|
||||
.reduce((acc, p) => acc + p.numTilesOwned(), 0);
|
||||
|
||||
this.ratio = numBlueTiles / (numBlueTiles + numRedTiles);
|
||||
this.leftColor = blue.toRgbString();
|
||||
this.rightColor = red.toRgbString();
|
||||
const theme = this.game.config().theme();
|
||||
const total = sumIterator(teamTiles.values());
|
||||
if (total === 0) return;
|
||||
for (const [team, count] of teamTiles) {
|
||||
const ratio = count / total;
|
||||
const color = theme.teamColor(team).toRgbString();
|
||||
this.ratios.push(ratio);
|
||||
this.colors.push(color);
|
||||
}
|
||||
}
|
||||
|
||||
shouldTransform(): boolean {
|
||||
@@ -46,18 +52,34 @@ export class SpawnTimer implements Layer {
|
||||
}
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
if (this.ratio == 0) {
|
||||
return;
|
||||
}
|
||||
if (this.ratios === null) return;
|
||||
if (this.ratios.length === 0) return;
|
||||
if (this.colors.length === 0) return;
|
||||
|
||||
const barHeight = 10;
|
||||
const barBackgroundWidth = this.transformHandler.width();
|
||||
const barWidth = this.transformHandler.width();
|
||||
|
||||
// Draw bar background
|
||||
context.fillStyle = this.rightColor;
|
||||
context.fillRect(0, 0, barBackgroundWidth, barHeight);
|
||||
let x = 0;
|
||||
let filledRatio = 0;
|
||||
for (let i = 0; i < this.ratios.length && i < this.colors.length; i++) {
|
||||
const ratio = this.ratios[i];
|
||||
const segmentWidth = barWidth * ratio;
|
||||
|
||||
context.fillStyle = this.leftColor;
|
||||
context.fillRect(0, 0, barBackgroundWidth * this.ratio, barHeight);
|
||||
context.fillStyle = this.colors[i];
|
||||
context.fillRect(x, 0, segmentWidth, barHeight);
|
||||
|
||||
x += segmentWidth;
|
||||
filledRatio += ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sumIterator(values: MapIterator<number>) {
|
||||
// To use reduce, we'd need to allocate an array:
|
||||
// return Array.from(values).reduce((sum, v) => sum + v, 0);
|
||||
let total = 0;
|
||||
for (const value of values) {
|
||||
total += value;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Theme } from "../../../core/configuration/Config";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
export class TerrainLayer implements Layer {
|
||||
@@ -8,7 +9,10 @@ export class TerrainLayer implements Layer {
|
||||
private imageData: ImageData;
|
||||
private theme: Theme;
|
||||
|
||||
constructor(private game: GameView) {}
|
||||
constructor(
|
||||
private game: GameView,
|
||||
private transformHandler: TransformHandler,
|
||||
) {}
|
||||
shouldTransform(): boolean {
|
||||
return true;
|
||||
}
|
||||
@@ -54,6 +58,12 @@ export class TerrainLayer implements Layer {
|
||||
}
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
if (this.transformHandler.scale < 1) {
|
||||
context.imageSmoothingEnabled = true;
|
||||
context.imageSmoothingQuality = "low";
|
||||
} else {
|
||||
context.imageSmoothingEnabled = false;
|
||||
}
|
||||
context.drawImage(
|
||||
this.canvas,
|
||||
-this.game.width() / 2,
|
||||
|
||||
@@ -36,7 +36,7 @@ export class TerritoryLayer implements Layer {
|
||||
private lastDragTime = 0;
|
||||
private nodrawDragDuration = 200;
|
||||
|
||||
private refreshRate = 50;
|
||||
private refreshRate = 10;
|
||||
private lastRefresh = 0;
|
||||
|
||||
private lastFocusedPlayer: PlayerView | null = null;
|
||||
@@ -55,7 +55,7 @@ export class TerritoryLayer implements Layer {
|
||||
paintPlayerBorder(player: PlayerView) {
|
||||
player.borderTiles().then((playerBorderTiles) => {
|
||||
playerBorderTiles.borderTiles.forEach((tile: TileRef) => {
|
||||
this.paintTerritory(tile); // Immediately paint the tile instead of enqueueing
|
||||
this.paintTerritory(tile, true); // Immediately paint the tile instead of enqueueing
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -215,7 +215,7 @@ export class TerritoryLayer implements Layer {
|
||||
}
|
||||
|
||||
renderTerritory() {
|
||||
let numToRender = Math.floor(this.tileToRenderQueue.size() / 5);
|
||||
let numToRender = Math.floor(this.tileToRenderQueue.size() / 10);
|
||||
if (numToRender == 0 || this.game.inSpawnPhase()) {
|
||||
numToRender = this.tileToRenderQueue.size();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import { MoveWarshipIntentEvent } from "../../Transport";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
import { getColoredSprite, loadAllSprites } from "../SpriteLoader";
|
||||
|
||||
enum Relationship {
|
||||
Self,
|
||||
Ally,
|
||||
@@ -28,8 +30,10 @@ enum Relationship {
|
||||
export class UnitLayer implements Layer {
|
||||
private canvas: HTMLCanvasElement;
|
||||
private context: CanvasRenderingContext2D;
|
||||
private transportShipTrailCanvas: HTMLCanvasElement;
|
||||
private transportShipTrailContext: CanvasRenderingContext2D;
|
||||
|
||||
private boatToTrail = new Map<UnitView, Set<TileRef>>();
|
||||
private boatToTrail = new Map<UnitView, TileRef[]>();
|
||||
|
||||
private theme: Theme = null;
|
||||
|
||||
@@ -75,6 +79,8 @@ export class UnitLayer implements Layer {
|
||||
this.eventBus.on(MouseUpEvent, (e) => this.onMouseUp(e));
|
||||
this.eventBus.on(UnitSelectionEvent, (e) => this.onUnitSelectionChange(e));
|
||||
this.redraw();
|
||||
|
||||
loadAllSprites();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,6 +166,13 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
context.drawImage(
|
||||
this.transportShipTrailCanvas,
|
||||
-this.game.width() / 2,
|
||||
-this.game.height() / 2,
|
||||
this.game.width(),
|
||||
this.game.height(),
|
||||
);
|
||||
context.drawImage(
|
||||
this.canvas,
|
||||
-this.game.width() / 2,
|
||||
@@ -177,14 +190,31 @@ export class UnitLayer implements Layer {
|
||||
redraw() {
|
||||
this.canvas = document.createElement("canvas");
|
||||
this.context = this.canvas.getContext("2d");
|
||||
this.transportShipTrailCanvas = document.createElement("canvas");
|
||||
this.transportShipTrailContext =
|
||||
this.transportShipTrailCanvas.getContext("2d");
|
||||
|
||||
this.canvas.width = this.game.width();
|
||||
this.canvas.height = this.game.height();
|
||||
this.transportShipTrailCanvas.width = this.game.width();
|
||||
this.transportShipTrailCanvas.height = this.game.height();
|
||||
this.game
|
||||
?.updatesSinceLastTick()
|
||||
?.[GameUpdateType.Unit]?.forEach((unit) => {
|
||||
this.onUnitEvent(this.game.unit(unit.id));
|
||||
});
|
||||
this.boatToTrail.forEach((trail, unit) => {
|
||||
for (const t of trail) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
this.relationship(unit),
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
150,
|
||||
this.transportShipTrailContext,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private relationship(unit: UnitView): Relationship {
|
||||
@@ -244,56 +274,13 @@ export class UnitLayer implements Layer {
|
||||
this.clearCell(this.game.x(t), this.game.y(t));
|
||||
}
|
||||
|
||||
if (!unit.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let outerColor = this.theme.territoryColor(unit.owner());
|
||||
if (unit.warshipTargetId()) {
|
||||
const targetOwner = this.game
|
||||
.units()
|
||||
.find((u) => u.id() == unit.warshipTargetId())
|
||||
?.owner();
|
||||
if (targetOwner == this.myPlayer) {
|
||||
outerColor = colord({ r: 200, b: 0, g: 0 });
|
||||
if (unit.isActive()) {
|
||||
if (unit.warshipTargetId()) {
|
||||
this.drawSprite(unit, colord({ r: 200, b: 0, g: 0 }));
|
||||
} else {
|
||||
this.drawSprite(unit);
|
||||
}
|
||||
}
|
||||
|
||||
// Paint outer territory
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
euclDistFN(unit.tile(), 5, false),
|
||||
)) {
|
||||
this.paintCell(this.game.x(t), this.game.y(t), rel, outerColor, 255);
|
||||
}
|
||||
|
||||
// Paint border
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
manhattanDistFN(unit.tile(), 4),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
|
||||
// Paint inner territory
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
euclDistFN(unit.tile(), 1, false),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private handleShellEvent(unit: UnitView) {
|
||||
@@ -341,32 +328,13 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
|
||||
if (unit.isActive()) {
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
euclDistFN(unit.tile(), range, false),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.spawnHighlightColor(),
|
||||
255,
|
||||
);
|
||||
}
|
||||
|
||||
this.paintCell(
|
||||
this.game.x(unit.tile()),
|
||||
this.game.y(unit.tile()),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
this.drawSprite(unit);
|
||||
}
|
||||
}
|
||||
|
||||
private handleNuke(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
let range = 0;
|
||||
|
||||
switch (unit.type()) {
|
||||
case UnitType.AtomBomb:
|
||||
range = 4;
|
||||
@@ -379,7 +347,6 @@ export class UnitLayer implements Layer {
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear previous area
|
||||
for (const t of this.game.bfs(
|
||||
unit.lastTile(),
|
||||
euclDistFN(unit.lastTile(), range, false),
|
||||
@@ -388,30 +355,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
|
||||
if (unit.isActive()) {
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
euclDistFN(unit.tile(), range, false),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.spawnHighlightColor(),
|
||||
255,
|
||||
);
|
||||
}
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
euclDistFN(unit.tile(), 2, false),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
this.drawSprite(unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,8 +377,6 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
|
||||
private handleTradeShipEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear previous area
|
||||
for (const t of this.game.bfs(
|
||||
unit.lastTile(),
|
||||
@@ -444,33 +386,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
|
||||
if (unit.isActive()) {
|
||||
// Paint territory
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
manhattanDistFN(unit.tile(), 2),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
|
||||
// Paint border
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
manhattanDistFN(unit.tile(), 1),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
this.drawSprite(unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,63 +394,59 @@ export class UnitLayer implements Layer {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
if (!this.boatToTrail.has(unit)) {
|
||||
this.boatToTrail.set(unit, new Set<TileRef>());
|
||||
this.boatToTrail.set(unit, []);
|
||||
}
|
||||
const trail = this.boatToTrail.get(unit);
|
||||
trail.add(unit.lastTile());
|
||||
trail.push(unit.lastTile());
|
||||
|
||||
// Clear previous area
|
||||
for (const t of this.game.bfs(
|
||||
unit.lastTile(),
|
||||
manhattanDistFN(unit.lastTile(), 3),
|
||||
manhattanDistFN(unit.lastTile(), 4),
|
||||
)) {
|
||||
this.clearCell(this.game.x(t), this.game.y(t));
|
||||
}
|
||||
|
||||
if (unit.isActive()) {
|
||||
// Paint trail
|
||||
for (const t of trail) {
|
||||
for (const t of trail.slice(-1)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
150,
|
||||
this.transportShipTrailContext,
|
||||
);
|
||||
}
|
||||
|
||||
// Paint border
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
manhattanDistFN(unit.tile(), 2),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
|
||||
// Paint territory
|
||||
for (const t of this.game.bfs(
|
||||
unit.tile(),
|
||||
manhattanDistFN(unit.tile(), 1),
|
||||
)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
255,
|
||||
);
|
||||
}
|
||||
this.drawSprite(unit);
|
||||
} else {
|
||||
for (const t of trail) {
|
||||
this.clearCell(this.game.x(t), this.game.y(t));
|
||||
this.clearCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
this.transportShipTrailContext,
|
||||
);
|
||||
}
|
||||
this.boatToTrail.delete(unit);
|
||||
|
||||
// Repaint overlapping trails
|
||||
const trailSet = new Set(trail);
|
||||
for (const [other, trail] of this.boatToTrail) {
|
||||
for (const t of trail) {
|
||||
if (trailSet.has(t)) {
|
||||
this.paintCell(
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(other.owner()),
|
||||
150,
|
||||
this.transportShipTrailContext,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,27 +456,69 @@ export class UnitLayer implements Layer {
|
||||
relationship: Relationship,
|
||||
color: Colord,
|
||||
alpha: number,
|
||||
context: CanvasRenderingContext2D = this.context,
|
||||
) {
|
||||
this.clearCell(x, y);
|
||||
this.clearCell(x, y, context);
|
||||
if (this.alternateView) {
|
||||
switch (relationship) {
|
||||
case Relationship.Self:
|
||||
this.context.fillStyle = this.theme.selfColor().toRgbString();
|
||||
context.fillStyle = this.theme.selfColor().toRgbString();
|
||||
break;
|
||||
case Relationship.Ally:
|
||||
this.context.fillStyle = this.theme.allyColor().toRgbString();
|
||||
context.fillStyle = this.theme.allyColor().toRgbString();
|
||||
break;
|
||||
case Relationship.Enemy:
|
||||
this.context.fillStyle = this.theme.enemyColor().toRgbString();
|
||||
context.fillStyle = this.theme.enemyColor().toRgbString();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.context.fillStyle = color.alpha(alpha / 255).toRgbString();
|
||||
context.fillStyle = color.alpha(alpha / 255).toRgbString();
|
||||
}
|
||||
this.context.fillRect(x, y, 1, 1);
|
||||
context.fillRect(x, y, 1, 1);
|
||||
}
|
||||
|
||||
clearCell(x: number, y: number) {
|
||||
this.context.clearRect(x, y, 1, 1);
|
||||
clearCell(
|
||||
x: number,
|
||||
y: number,
|
||||
context: CanvasRenderingContext2D = this.context,
|
||||
) {
|
||||
context.clearRect(x, y, 1, 1);
|
||||
}
|
||||
|
||||
drawSprite(unit: UnitView, customTerritoryColor?: Colord) {
|
||||
const x = this.game.x(unit.tile());
|
||||
const y = this.game.y(unit.tile());
|
||||
|
||||
let alternateViewColor = null;
|
||||
|
||||
if (this.alternateView) {
|
||||
const rel = this.relationship(unit);
|
||||
switch (rel) {
|
||||
case Relationship.Self:
|
||||
alternateViewColor = this.theme.selfColor();
|
||||
break;
|
||||
case Relationship.Ally:
|
||||
alternateViewColor = this.theme.allyColor();
|
||||
break;
|
||||
case Relationship.Enemy:
|
||||
alternateViewColor = this.theme.enemyColor();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const sprite = getColoredSprite(
|
||||
unit,
|
||||
this.theme,
|
||||
alternateViewColor ?? customTerritoryColor,
|
||||
alternateViewColor,
|
||||
);
|
||||
|
||||
this.context.drawImage(
|
||||
sprite,
|
||||
Math.round(x - sprite.width / 2),
|
||||
Math.round(y - sprite.height / 2),
|
||||
sprite.width,
|
||||
sprite.width,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { TeamName } from "../../../core/game/Game";
|
||||
import { Team } from "../../../core/game/Game";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView, PlayerView } from "../../../core/game/GameView";
|
||||
import { PseudoRandom } from "../../../core/PseudoRandom";
|
||||
@@ -149,7 +149,7 @@ export class WinModal extends LitElement implements Layer {
|
||||
return html`
|
||||
<div class="win-modal ${this.isVisible ? "visible" : ""}">
|
||||
<h2>${this._title || ""}</h2>
|
||||
${this.supportHTML()}
|
||||
${this.innerHtml()}
|
||||
<div class="button-container">
|
||||
<button @click=${this._handleExit}>Exit Game</button>
|
||||
<button @click=${this.hide}>Keep Playing</button>
|
||||
@@ -158,35 +158,9 @@ export class WinModal extends LitElement implements Layer {
|
||||
`;
|
||||
}
|
||||
|
||||
updated(changedProperties) {
|
||||
super.updated(changedProperties);
|
||||
// Initialize ads if modal is visible and showing ads
|
||||
if (changedProperties.has("isVisible") && this.isVisible && !this.won) {
|
||||
try {
|
||||
setTimeout(() => {
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
}, 0);
|
||||
} catch (error) {
|
||||
console.error("Error initializing ad:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supportHTML() {
|
||||
innerHtml() {
|
||||
return html`
|
||||
<div style="text-align: center; margin: 15px 0;">
|
||||
<p>
|
||||
Like the game? Help make this my full-time project!
|
||||
<a
|
||||
href="https://discord.gg/k22YrnAzGp"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style="color: #0096ff; text-decoration: underline; display: block; margin-top: 5px;"
|
||||
>
|
||||
Support the game!
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div style="text-align: center; margin: 15px 0; line-height: 1.5;"></div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -226,13 +200,9 @@ export class WinModal extends LitElement implements Layer {
|
||||
this.game.updatesSinceLastTick()[GameUpdateType.Win].forEach((wu) => {
|
||||
if (wu.winnerType === "team") {
|
||||
this.eventBus.emit(
|
||||
new SendWinnerEvent(
|
||||
wu.winner as TeamName,
|
||||
wu.allPlayersStats,
|
||||
"team",
|
||||
),
|
||||
new SendWinnerEvent(wu.winner as Team, wu.allPlayersStats, "team"),
|
||||
);
|
||||
if (wu.winner == this.game.myPlayer()?.teamName()) {
|
||||
if (wu.winner == this.game.myPlayer()?.team()) {
|
||||
this._title = "Your team won!";
|
||||
this.won = true;
|
||||
} else {
|
||||
|
||||
@@ -48,8 +48,10 @@
|
||||
.left-gutter-ad {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 200px; /* Changed from top: 50% */
|
||||
transform: none; /* Removed translateY(-50%) since we don't need to center anymore */
|
||||
top: 200px;
|
||||
/* Changed from top: 50% */
|
||||
transform: none;
|
||||
/* Removed translateY(-50%) since we don't need to center anymore */
|
||||
z-index: 40;
|
||||
width: 300px;
|
||||
height: 600px;
|
||||
@@ -68,8 +70,10 @@
|
||||
.right-gutter-ad {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 200px; /* Changed from top: 50% */
|
||||
transform: none; /* Removed translateY(-50%) since we don't need to center anymore */
|
||||
top: 200px;
|
||||
/* Changed from top: 50% */
|
||||
transform: none;
|
||||
/* Removed translateY(-50%) since we don't need to center anymore */
|
||||
z-index: 40;
|
||||
width: 300px;
|
||||
height: 600px;
|
||||
@@ -122,7 +126,22 @@
|
||||
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7035513310742290"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=G-WQGQQ8RDN4"
|
||||
></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
|
||||
gtag("config", "G-WQGQQ8RDN4");
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body
|
||||
class="h-full select-none font-sans min-h-screen bg-opacity-0 bg-cover bg-center bg-fixed transition-opacity duration-300 ease-in-out flex flex-col"
|
||||
>
|
||||
@@ -184,25 +203,10 @@
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<div class="l-header__highlightText">v21.0</div>
|
||||
<div class="l-header__highlightText">v21.2</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="bg-image"></div>
|
||||
<!-- Left gutter ad placement - full height, no empty space -->
|
||||
<div class="left-gutter-ad ad">
|
||||
<google-ad
|
||||
adSlot="5220834834"
|
||||
adFormat="vertical"
|
||||
fullWidthResponsive="false"
|
||||
></google-ad>
|
||||
</div>
|
||||
<div class="right-gutter-ad ad">
|
||||
<google-ad
|
||||
adSlot="1814331462"
|
||||
adFormat="vertical"
|
||||
fullWidthResponsive="false"
|
||||
></google-ad>
|
||||
</div>
|
||||
|
||||
<!-- Main container with responsive padding -->
|
||||
<main class="flex justify-center items-center flex-grow">
|
||||
@@ -265,6 +269,20 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- User Setting -->
|
||||
<button
|
||||
id="settings-button"
|
||||
title="Settings"
|
||||
class="fixed bottom-4 right-4 z-50 rounded-full p-2 shadow-lg transition-colors duration-300 flex items-center justify-center"
|
||||
style="width: 80px; height: 80px; background-color: #0075ff"
|
||||
>
|
||||
<img
|
||||
src="../../resources/images/SettingIconWhite.svg"
|
||||
alt="Settings"
|
||||
style="width: 72px; height: 72px"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<!-- Game components -->
|
||||
<div id="customMenu" class="mt-4 sm:mt-6 lg:mt-8">
|
||||
<ul></ul>
|
||||
@@ -339,6 +357,8 @@
|
||||
<player-panel></player-panel>
|
||||
<help-modal></help-modal>
|
||||
<dark-mode-button></dark-mode-button>
|
||||
<user-setting></user-setting>
|
||||
<multi-tab-modal></multi-tab-modal>
|
||||
<div
|
||||
id="language-modal"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex justify-center items-center"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
@import url("./styles/layout/container.css");
|
||||
@import url("./styles/components/button.css");
|
||||
@import url("./styles/components/modal.css");
|
||||
@import url("./styles/components/setting.css");
|
||||
@import url("./styles/components/controls.css");
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
@@ -214,6 +216,8 @@ label.option-card:hover {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.players-list {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
.scroll-combo-horizontal {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-family: sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.key {
|
||||
display: inline-block;
|
||||
padding: 4px 14px;
|
||||
border-radius: 6px;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 2px 0 #444;
|
||||
}
|
||||
|
||||
.plus {
|
||||
font-size: 16px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.mouse-shell {
|
||||
width: 28px;
|
||||
height: 45px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 50px;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mouse-left-corner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
background-color: #ff4d4d;
|
||||
border-top-left-radius: 50px;
|
||||
}
|
||||
|
||||
.mouse-right-corner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
background-color: #ff4d4d;
|
||||
border-top-right-radius: 50px;
|
||||
}
|
||||
|
||||
.mouse-wheel {
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
background-color: #ccc;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
#highlighted-wheel {
|
||||
background-color: #ff4d4d;
|
||||
}
|
||||
|
||||
.mouse-with-arrows {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mouse-arrows-side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
.settings-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #333;
|
||||
border-radius: 10px;
|
||||
padding: 12px 20px;
|
||||
width: 360px !important;
|
||||
max-width: 360px !important;
|
||||
min-width: 360px !important;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
|
||||
transition: background 0.3s ease;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@keyframes rainbow-background {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-item.easter-egg {
|
||||
background: linear-gradient(
|
||||
270deg,
|
||||
#990033,
|
||||
#996600,
|
||||
#336600,
|
||||
#008080,
|
||||
#1c3f99,
|
||||
#5e0099,
|
||||
#990033
|
||||
);
|
||||
background-size: 1400% 1400%;
|
||||
animation: rainbow-background 10s ease infinite;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.easter-egg-popup {
|
||||
position: fixed;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(0.9);
|
||||
padding: 16px 24px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 12px;
|
||||
animation: fadePop 5s ease-out forwards;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
@keyframes fadePop {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.6);
|
||||
}
|
||||
30% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
70% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.setting-item:hover {
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.setting-item.easter-egg:hover {
|
||||
background: linear-gradient(
|
||||
270deg,
|
||||
#990033,
|
||||
#996600,
|
||||
#336600,
|
||||
#008080,
|
||||
#1c3f99,
|
||||
#5e0099,
|
||||
#990033
|
||||
);
|
||||
background-size: 1400% 1400%;
|
||||
animation: rainbow-background 10s ease infinite;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
color: #f0f0f0;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.setting-input {
|
||||
margin-left: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.setting-item.vertical {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toggle-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.slider-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.setting-input.slider.full-width {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.setting-input.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 180px;
|
||||
height: 10px;
|
||||
background: linear-gradient(to right, #2196f3 50%, #444 50%);
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.setting-input.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
border: 2px solid #2196f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.setting-input.slider::-moz-range-thumb {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
border: 2px solid #2196f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.setting-input.slider::-moz-range-track {
|
||||
background: linear-gradient(to right, #2196f3 50%, #444 50%);
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.setting-input.slider:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.setting-input.number {
|
||||
width: 80px;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.switch.switch-right {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.slider-round {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #d9534f;
|
||||
transition: 0.4s;
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider-round::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
transition: 0.4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.switch input:checked + .slider-round {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.switch input:checked + .slider-round::before {
|
||||
transform: translateX(24px);
|
||||
}
|
||||
|
||||
.setting-label-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-top: 2px;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
GameMode,
|
||||
GameType,
|
||||
PlayerType,
|
||||
TeamName,
|
||||
Team,
|
||||
UnitType,
|
||||
} from "./game/Game";
|
||||
|
||||
@@ -121,16 +121,14 @@ const GameConfigSchema = z.object({
|
||||
infiniteTroops: z.boolean(),
|
||||
instantBuild: z.boolean(),
|
||||
maxPlayers: z.number().optional(),
|
||||
numPlayerTeams: z.number().optional(),
|
||||
});
|
||||
|
||||
const SafeString = z
|
||||
.string()
|
||||
// Remove common dangerous characters and patterns
|
||||
// The weird \u stuff is to allow emojis
|
||||
.regex(
|
||||
/^[a-zA-Z0-9\s.,!?@#$%&*()-_+=\[\]{}|;:"'\/\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]|üÜ]+$/,
|
||||
/^([a-zA-Z0-9\s.,!?@#$%&*()-_+=\[\]{}|;:"'\/\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]|üÜ])*$/,
|
||||
)
|
||||
// Reasonable max length to prevent DOS
|
||||
.max(1000);
|
||||
|
||||
const EmojiSchema = z.string().refine(
|
||||
@@ -364,7 +362,7 @@ const ClientBaseMessageSchema = z.object({
|
||||
|
||||
export const ClientSendWinnerSchema = ClientBaseMessageSchema.extend({
|
||||
type: z.literal("winner"),
|
||||
winner: ID.or(z.nativeEnum(TeamName)).nullable(),
|
||||
winner: ID.or(z.nativeEnum(Team)).nullable(),
|
||||
allPlayersStats: AllPlayersStatsSchema,
|
||||
winnerType: z.enum(["player", "team"]),
|
||||
});
|
||||
@@ -396,6 +394,7 @@ export const ClientJoinMessageSchema = ClientBaseMessageSchema.extend({
|
||||
type: z.literal("join"),
|
||||
lastTurn: z.number(), // The last turn the client saw.
|
||||
username: SafeString,
|
||||
flag: SafeString.nullable().optional(),
|
||||
});
|
||||
|
||||
export const ClientMessageSchema = z.union([
|
||||
@@ -425,7 +424,7 @@ export const GameRecordSchema = z.object({
|
||||
num_turns: z.number(),
|
||||
turns: z.array(TurnSchema),
|
||||
winner: z
|
||||
.union([ID, z.nativeEnum(TeamName)])
|
||||
.union([ID, z.nativeEnum(Team)])
|
||||
.nullable()
|
||||
.optional(),
|
||||
winnerType: z.enum(["player", "team"]).nullable().optional(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import DOMPurify from "dompurify";
|
||||
import { customAlphabet } from "nanoid";
|
||||
import twemoji from "twemoji";
|
||||
import { Cell, Game, Player, TeamName, Unit } from "./game/Game";
|
||||
import { Cell, Game, Player, Team, Unit } from "./game/Game";
|
||||
import { andFN, GameMap, manhattanDistFN, TileRef } from "./game/GameMap";
|
||||
import {
|
||||
AllPlayersStats,
|
||||
@@ -253,7 +253,7 @@ export function createGameRecord(
|
||||
turns: Turn[],
|
||||
start: number,
|
||||
end: number,
|
||||
winner: ClientID | TeamName | null,
|
||||
winner: ClientID | Team | null,
|
||||
winnerType: "player" | "team" | null,
|
||||
allPlayersStats: AllPlayersStats,
|
||||
): GameRecord {
|
||||
|
||||
@@ -2,6 +2,11 @@ import { colord, Colord } from "colord";
|
||||
|
||||
export const red: Colord = colord({ r: 235, g: 53, b: 53 }); // Bright Red
|
||||
export const blue: Colord = colord({ r: 41, g: 98, b: 255 }); // Royal Blue
|
||||
export const teal = colord({ h: 172, s: 66, l: 50 });
|
||||
export const purple = colord({ h: 271, s: 81, l: 56 });
|
||||
export const yellow = colord({ h: 45, s: 93, l: 47 });
|
||||
export const orange = colord({ h: 25, s: 95, l: 53 });
|
||||
export const green = colord({ h: 128, s: 49, l: 50 });
|
||||
export const botColor: Colord = colord({ r: 210, g: 206, b: 200 }); // Muted Beige Gray
|
||||
|
||||
export const territoryColors: Colord[] = [
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Gold,
|
||||
Player,
|
||||
PlayerInfo,
|
||||
Team,
|
||||
TerraNullius,
|
||||
Tick,
|
||||
UnitInfo,
|
||||
@@ -65,6 +66,7 @@ export interface Config {
|
||||
instantBuild(): boolean;
|
||||
numSpawnPhaseTurns(): number;
|
||||
userSettings(): UserSettings;
|
||||
numPlayerTeams(): number;
|
||||
|
||||
startManpower(playerInfo: PlayerInfo): number;
|
||||
populationIncreaseRate(player: Player | PlayerView): number;
|
||||
@@ -122,6 +124,7 @@ export interface Config {
|
||||
}
|
||||
|
||||
export interface Theme {
|
||||
teamColor(team: Team): Colord;
|
||||
territoryColor(playerInfo: PlayerView): Colord;
|
||||
specialBuildingColor(playerInfo: PlayerView): Colord;
|
||||
borderColor(playerInfo: PlayerView): Colord;
|
||||
|
||||
@@ -34,7 +34,7 @@ export abstract class DefaultServerConfig implements ServerConfig {
|
||||
return process.env.GIT_COMMIT;
|
||||
}
|
||||
r2Endpoint(): string {
|
||||
return process.env.R2_ENDPOINT;
|
||||
return `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`;
|
||||
}
|
||||
r2AccessKey(): string {
|
||||
return process.env.R2_ACCESS_KEY;
|
||||
@@ -189,6 +189,9 @@ export class DefaultConfig implements Config {
|
||||
defensePostDefenseBonus(): number {
|
||||
return 5;
|
||||
}
|
||||
numPlayerTeams(): number {
|
||||
return this._gameConfig.numPlayerTeams ?? 0;
|
||||
}
|
||||
spawnNPCs(): boolean {
|
||||
return !this._gameConfig.disableNPCs;
|
||||
}
|
||||
@@ -211,12 +214,12 @@ export class DefaultConfig implements Config {
|
||||
return 10000 + 150 * Math.pow(dist, 1.1);
|
||||
}
|
||||
tradeShipSpawnRate(numberOfPorts: number): number {
|
||||
if (numberOfPorts <= 3) return 180;
|
||||
if (numberOfPorts <= 5) return 250;
|
||||
if (numberOfPorts <= 8) return 350;
|
||||
if (numberOfPorts <= 10) return 400;
|
||||
if (numberOfPorts <= 12) return 450;
|
||||
return 500;
|
||||
if (numberOfPorts <= 3) return 18;
|
||||
if (numberOfPorts <= 5) return 25;
|
||||
if (numberOfPorts <= 8) return 35;
|
||||
if (numberOfPorts <= 10) return 40;
|
||||
if (numberOfPorts <= 12) return 45;
|
||||
return 50;
|
||||
}
|
||||
|
||||
unitInfo(type: UnitType): UnitInfo {
|
||||
@@ -268,7 +271,7 @@ export class DefaultConfig implements Config {
|
||||
case UnitType.AtomBomb:
|
||||
return {
|
||||
cost: (p: Player) =>
|
||||
p.type() == PlayerType.Human && this.infiniteGold() ? 0 : 500_000,
|
||||
p.type() == PlayerType.Human && this.infiniteGold() ? 0 : 750_000,
|
||||
territoryBound: false,
|
||||
};
|
||||
case UnitType.HydrogenBomb:
|
||||
@@ -336,7 +339,7 @@ export class DefaultConfig implements Config {
|
||||
p.type() == PlayerType.Human && this.infiniteGold()
|
||||
? 0
|
||||
: Math.min(
|
||||
2_000_000,
|
||||
1_000_000,
|
||||
Math.pow(
|
||||
2,
|
||||
p.unitsIncludingConstruction(UnitType.City).length,
|
||||
@@ -473,18 +476,25 @@ export class DefaultConfig implements Config {
|
||||
}
|
||||
|
||||
if (defender.isPlayer()) {
|
||||
const ratio = within(
|
||||
Math.pow(defender.troops() / attackTroops, 0.4),
|
||||
0.1,
|
||||
10,
|
||||
);
|
||||
const speedRatio = within(
|
||||
defender.troops() / (5 * attackTroops),
|
||||
0.1,
|
||||
10,
|
||||
);
|
||||
|
||||
return {
|
||||
attackerTroopLoss:
|
||||
within(defender.troops() / attackTroops, 0.6, 2) *
|
||||
ratio *
|
||||
mag *
|
||||
0.8 *
|
||||
largeLossModifier *
|
||||
(defender.isTraitor() ? this.traitorDefenseDebuff() : 1),
|
||||
defenderTroopLoss: defender.troops() / defender.numTilesOwned(),
|
||||
tilesPerTickUsed:
|
||||
within(defender.troops() / (5 * attackTroops), 0.2, 1.5) *
|
||||
speed *
|
||||
largeSpeedMalus,
|
||||
defenderTroopLoss: defender.population() / defender.numTilesOwned(),
|
||||
tilesPerTickUsed: Math.floor(speedRatio * speed * largeSpeedMalus),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@@ -620,7 +630,8 @@ export class DefaultConfig implements Config {
|
||||
}
|
||||
|
||||
goldAdditionRate(player: Player): number {
|
||||
return Math.sqrt(player.workers() * player.numTilesOwned()) / 200;
|
||||
const ratio = Math.pow(player.workers() / player.population(), 1.3);
|
||||
return Math.floor(Math.sqrt(player.workers()) * ratio * 5);
|
||||
}
|
||||
|
||||
troopAdjustmentRate(player: Player): number {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GameType, UnitInfo, UnitType } from "../game/Game";
|
||||
import { UnitInfo, UnitType } from "../game/Game";
|
||||
import { UserSettings } from "../game/UserSettings";
|
||||
import { GameConfig } from "../Schemas";
|
||||
import { GameEnv, ServerConfig } from "./Config";
|
||||
@@ -40,10 +40,10 @@ export class DevConfig extends DefaultConfig {
|
||||
super(sc, gc, us);
|
||||
}
|
||||
|
||||
numSpawnPhaseTurns(): number {
|
||||
return this.gameConfig().gameType == GameType.Singleplayer ? 40 : 100;
|
||||
// return 100
|
||||
}
|
||||
// numSpawnPhaseTurns(): number {
|
||||
// return this.gameConfig().gameType == GameType.Singleplayer ? 70 : 100;
|
||||
// // return 100
|
||||
// }
|
||||
|
||||
unitInfo(type: UnitType): UnitInfo {
|
||||
const info = super.unitInfo(type);
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { Colord, colord } from "colord";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { simpleHash } from "../Util";
|
||||
import { PlayerType, TeamName, TerrainType } from "../game/Game";
|
||||
import { PlayerType, Team, TerrainType } from "../game/Game";
|
||||
import { GameMap, TileRef } from "../game/GameMap";
|
||||
import { PlayerView } from "../game/GameView";
|
||||
import {
|
||||
blue,
|
||||
botColor,
|
||||
botColors,
|
||||
green,
|
||||
humanColors,
|
||||
orange,
|
||||
purple,
|
||||
red,
|
||||
teal,
|
||||
territoryColors,
|
||||
yellow,
|
||||
} from "./Colors";
|
||||
import { Theme } from "./Config";
|
||||
|
||||
@@ -36,15 +41,31 @@ export const pastelTheme = new (class implements Theme {
|
||||
|
||||
private _spawnHighlightColor = colord({ r: 255, g: 213, b: 79 });
|
||||
|
||||
teamColor(team: Team): Colord {
|
||||
switch (team) {
|
||||
case Team.Blue:
|
||||
return blue;
|
||||
case Team.Red:
|
||||
return red;
|
||||
case Team.Teal:
|
||||
return teal;
|
||||
case Team.Purple:
|
||||
return purple;
|
||||
case Team.Yellow:
|
||||
return yellow;
|
||||
case Team.Orange:
|
||||
return orange;
|
||||
case Team.Green:
|
||||
return green;
|
||||
case Team.Bot:
|
||||
return botColor;
|
||||
}
|
||||
throw new Error(`Missing color for ${team}`);
|
||||
}
|
||||
|
||||
territoryColor(player: PlayerView): Colord {
|
||||
if (player.teamName() == TeamName.Bot) {
|
||||
return botColor;
|
||||
}
|
||||
if (player.teamName() == TeamName.Red) {
|
||||
return red;
|
||||
}
|
||||
if (player.teamName() == TeamName.Blue) {
|
||||
return blue;
|
||||
if (player.team() !== null) {
|
||||
return this.teamColor(player.team());
|
||||
}
|
||||
if (player.info().playerType == PlayerType.Human) {
|
||||
return humanColors[simpleHash(player.id()) % humanColors.length];
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { Colord, colord } from "colord";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { simpleHash } from "../Util";
|
||||
import { PlayerType, TeamName, TerrainType } from "../game/Game";
|
||||
import { PlayerType, Team, TerrainType } from "../game/Game";
|
||||
import { GameMap, TileRef } from "../game/GameMap";
|
||||
import { PlayerView } from "../game/GameView";
|
||||
import {
|
||||
blue,
|
||||
botColor,
|
||||
botColors,
|
||||
green,
|
||||
humanColors,
|
||||
orange,
|
||||
purple,
|
||||
red,
|
||||
teal,
|
||||
territoryColors,
|
||||
yellow,
|
||||
} from "./Colors";
|
||||
import { Theme } from "./Config";
|
||||
|
||||
@@ -36,15 +41,31 @@ export const pastelThemeDark = new (class implements Theme {
|
||||
|
||||
private _spawnHighlightColor = colord({ r: 255, g: 213, b: 79 });
|
||||
|
||||
teamColor(team: Team): Colord {
|
||||
switch (team) {
|
||||
case Team.Blue:
|
||||
return blue;
|
||||
case Team.Red:
|
||||
return red;
|
||||
case Team.Teal:
|
||||
return teal;
|
||||
case Team.Purple:
|
||||
return purple;
|
||||
case Team.Yellow:
|
||||
return yellow;
|
||||
case Team.Orange:
|
||||
return orange;
|
||||
case Team.Green:
|
||||
return green;
|
||||
case Team.Bot:
|
||||
return botColor;
|
||||
}
|
||||
throw new Error(`Missing color for ${team}`);
|
||||
}
|
||||
|
||||
territoryColor(player: PlayerView): Colord {
|
||||
if (player.teamName() == TeamName.Bot) {
|
||||
return botColor;
|
||||
}
|
||||
if (player.teamName() == TeamName.Red) {
|
||||
return red;
|
||||
}
|
||||
if (player.teamName() == TeamName.Blue) {
|
||||
return blue;
|
||||
if (player.team() !== null) {
|
||||
return this.teamColor(player.team());
|
||||
}
|
||||
if (player.info().playerType == PlayerType.Human) {
|
||||
return humanColors[simpleHash(player.id()) % humanColors.length];
|
||||
|
||||
@@ -150,12 +150,12 @@ export class FakeHumanExecution implements Execution {
|
||||
);
|
||||
|
||||
if (enemyborder.length == 0) {
|
||||
if (this.random.chance(5)) {
|
||||
if (this.random.chance(10)) {
|
||||
this.sendBoatRandomly();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.random.chance(10)) {
|
||||
if (this.random.chance(20)) {
|
||||
this.sendBoatRandomly();
|
||||
return;
|
||||
}
|
||||
@@ -513,7 +513,7 @@ export class FakeHumanExecution implements Execution {
|
||||
|
||||
const src = this.random.randElement(oceanShore);
|
||||
|
||||
const dst = this.randOceanShoreTile(src, 250);
|
||||
const dst = this.randOceanShoreTile(src, 150);
|
||||
if (dst == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ export class MirvExecution implements Execution {
|
||||
|
||||
randomLand(ref: TileRef, taken: TileRef[]): TileRef | null {
|
||||
let tries = 0;
|
||||
const mirvRange2 = this.mirvRange * this.mirvRange;
|
||||
while (tries < 100) {
|
||||
tries++;
|
||||
const x = this.random.nextInt(
|
||||
@@ -174,7 +175,7 @@ export class MirvExecution implements Execution {
|
||||
if (!this.mg.isLand(tile)) {
|
||||
continue;
|
||||
}
|
||||
if (this.mg.euclideanDist(tile, ref) > this.mirvRange) {
|
||||
if (this.mg.euclideanDistSquared(tile, ref) > mirvRange2) {
|
||||
continue;
|
||||
}
|
||||
if (this.mg.owner(tile) != this.targetPlayer) {
|
||||
|
||||
@@ -52,30 +52,25 @@ export class NukeExecution implements Execution {
|
||||
private tilesToDestroy(): Set<TileRef> {
|
||||
const magnitude = this.mg.config().nukeMagnitudes(this.nuke.type());
|
||||
const rand = new PseudoRandom(this.mg.ticks());
|
||||
const inner2 = magnitude.inner * magnitude.inner;
|
||||
const outer2 = magnitude.outer * magnitude.outer;
|
||||
return this.mg.bfs(this.dst, (_, n: TileRef) => {
|
||||
const d = this.mg.euclideanDist(this.dst, n);
|
||||
return (d <= magnitude.inner || rand.chance(2)) && d <= magnitude.outer;
|
||||
const d2 = this.mg.euclideanDistSquared(this.dst, n);
|
||||
return d2 <= outer2 && (d2 <= inner2 || rand.chance(2));
|
||||
});
|
||||
}
|
||||
|
||||
private getAttackedTiles() {
|
||||
const toDestroy = this.tilesToDestroy();
|
||||
|
||||
private breakAlliances(toDestroy: Set<TileRef>) {
|
||||
const attacked = new Map<Player, number>();
|
||||
for (const tile of toDestroy) {
|
||||
const owner = this.mg.owner(tile);
|
||||
if (owner.isPlayer()) {
|
||||
const mp = this.mg.player(owner.id());
|
||||
const prev = attacked.get(mp) ?? 0;
|
||||
attacked.set(mp, prev + 1);
|
||||
const prev = attacked.get(owner) ?? 0;
|
||||
attacked.set(owner, prev + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return attacked;
|
||||
}
|
||||
|
||||
private breakAlliances() {
|
||||
for (const [other, tilesDestroyed] of this.getAttackedTiles()) {
|
||||
for (const [other, tilesDestroyed] of attacked) {
|
||||
if (tilesDestroyed > 100 && this.nuke.type() != UnitType.MIRVWarhead) {
|
||||
// Mirv warheads shouldn't break alliances
|
||||
const alliance = this.player.allianceWith(other);
|
||||
@@ -143,8 +138,6 @@ export class NukeExecution implements Execution {
|
||||
return;
|
||||
}
|
||||
|
||||
this.breakAlliances();
|
||||
|
||||
if (this.waitTicks > 0) {
|
||||
this.waitTicks--;
|
||||
return;
|
||||
@@ -196,28 +189,32 @@ export class NukeExecution implements Execution {
|
||||
private detonate() {
|
||||
const magnitude = this.mg.config().nukeMagnitudes(this.nuke.type());
|
||||
const toDestroy = this.tilesToDestroy();
|
||||
this.breakAlliances(toDestroy);
|
||||
|
||||
for (const tile of toDestroy) {
|
||||
const owner = this.mg.owner(tile);
|
||||
if (owner.isPlayer()) {
|
||||
const mp = this.mg.player(owner.id());
|
||||
mp.relinquish(tile);
|
||||
mp.removeTroops(
|
||||
this.mg.config().nukeDeathFactor(mp.troops(), mp.numTilesOwned()),
|
||||
owner.relinquish(tile);
|
||||
owner.removeTroops(
|
||||
this.mg
|
||||
.config()
|
||||
.nukeDeathFactor(owner.troops(), owner.numTilesOwned()),
|
||||
);
|
||||
mp.removeWorkers(
|
||||
this.mg.config().nukeDeathFactor(mp.workers(), mp.numTilesOwned()),
|
||||
owner.removeWorkers(
|
||||
this.mg
|
||||
.config()
|
||||
.nukeDeathFactor(owner.workers(), owner.numTilesOwned()),
|
||||
);
|
||||
mp.outgoingAttacks().forEach((attack) => {
|
||||
owner.outgoingAttacks().forEach((attack) => {
|
||||
const deaths = this.mg
|
||||
.config()
|
||||
.nukeDeathFactor(attack.troops(), mp.numTilesOwned());
|
||||
.nukeDeathFactor(attack.troops(), owner.numTilesOwned());
|
||||
attack.setTroops(attack.troops() - deaths);
|
||||
});
|
||||
mp.units(UnitType.TransportShip).forEach((attack) => {
|
||||
owner.units(UnitType.TransportShip).forEach((attack) => {
|
||||
const deaths = this.mg
|
||||
.config()
|
||||
.nukeDeathFactor(attack.troops(), mp.numTilesOwned());
|
||||
.nukeDeathFactor(attack.troops(), owner.numTilesOwned());
|
||||
attack.setTroops(attack.troops() - deaths);
|
||||
});
|
||||
}
|
||||
@@ -227,6 +224,7 @@ export class NukeExecution implements Execution {
|
||||
}
|
||||
}
|
||||
|
||||
const outer2 = magnitude.outer * magnitude.outer;
|
||||
for (const unit of this.mg.units()) {
|
||||
if (
|
||||
unit.type() != UnitType.AtomBomb &&
|
||||
@@ -234,7 +232,7 @@ export class NukeExecution implements Execution {
|
||||
unit.type() != UnitType.MIRVWarhead &&
|
||||
unit.type() != UnitType.MIRV
|
||||
) {
|
||||
if (this.mg.euclideanDist(this.dst, unit.tile()) < magnitude.outer) {
|
||||
if (this.mg.euclideanDistSquared(this.dst, unit.tile()) < outer2) {
|
||||
unit.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ export class PortExecution implements Execution {
|
||||
private mg: Game;
|
||||
private port: Unit;
|
||||
private random: PseudoRandom;
|
||||
private checkOffset: number;
|
||||
|
||||
constructor(
|
||||
private _owner: PlayerID,
|
||||
@@ -31,6 +32,7 @@ export class PortExecution implements Execution {
|
||||
}
|
||||
this.mg = mg;
|
||||
this.random = new PseudoRandom(mg.ticks());
|
||||
this.checkOffset = mg.ticks() % 10;
|
||||
}
|
||||
|
||||
tick(ticks: number): void {
|
||||
@@ -55,6 +57,11 @@ export class PortExecution implements Execution {
|
||||
this._owner = this.port.owner().id();
|
||||
}
|
||||
|
||||
// Only check every 10 ticks for performance.
|
||||
if ((this.mg.ticks() + this.checkOffset) % 10 != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const totalNbOfPorts = this.mg.units(UnitType.Port).length;
|
||||
if (
|
||||
!this.random.chance(this.mg.config().tradeShipSpawnRate(totalNbOfPorts))
|
||||
|
||||
@@ -105,7 +105,10 @@ export class SAMLauncherExecution implements Execution {
|
||||
if (this.target && !this.sam.isCooldown() && !this.target.targetedBySAM()) {
|
||||
this.sam.setCooldown(true);
|
||||
const random = this.pseudoRandom.next();
|
||||
const hit = random < this.mg.config().samHittingChance();
|
||||
let hit = true;
|
||||
if (this.target.type() != UnitType.AtomBomb) {
|
||||
hit = random < this.mg.config().samHittingChance();
|
||||
}
|
||||
if (!hit) {
|
||||
this.mg.displayMessage(
|
||||
`Missile failed to intercept ${this.target.type()}`,
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { GameEvent } from "../EventBus";
|
||||
import {
|
||||
Execution,
|
||||
Game,
|
||||
GameMode,
|
||||
Player,
|
||||
Team,
|
||||
TeamName,
|
||||
} from "../game/Game";
|
||||
import { Execution, Game, GameMode, Player, Team } from "../game/Game";
|
||||
|
||||
export class WinEvent implements GameEvent {
|
||||
constructor(public readonly winner: Player) {}
|
||||
@@ -73,9 +66,9 @@ export class WinCheckExecution implements Execution {
|
||||
this.mg.numLandTiles() - this.mg.numTilesWithFallout();
|
||||
const percentage = (max[1] / numTilesWithoutFallout) * 100;
|
||||
if (percentage > this.mg.config().percentageTilesOwnedToWin()) {
|
||||
if (max[0].name == TeamName.Bot) return;
|
||||
this.mg.setWinner(max[0].name, this.mg.stats().stats());
|
||||
console.log(`${max[0].name} has won the game`);
|
||||
if (max[0] == Team.Bot) return;
|
||||
this.mg.setWinner(max[0], this.mg.stats().stats());
|
||||
console.log(`${max[0]} has won the game`);
|
||||
this.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,14 @@ export enum Difficulty {
|
||||
Impossible = "Impossible",
|
||||
}
|
||||
|
||||
export enum TeamName {
|
||||
export enum Team {
|
||||
Red = "Red",
|
||||
Blue = "Blue",
|
||||
Teal = "Teal",
|
||||
Purple = "Purple",
|
||||
Yellow = "Yellow",
|
||||
Orange = "Orange",
|
||||
Green = "Green",
|
||||
Bot = "Bot",
|
||||
}
|
||||
|
||||
@@ -75,10 +80,6 @@ export enum GameMode {
|
||||
Team = "Team",
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
name: TeamName;
|
||||
}
|
||||
|
||||
export interface UnitInfo {
|
||||
cost: (player: Player | PlayerView) => Gold;
|
||||
// Determines if its owner changes when its tile is conquered.
|
||||
@@ -443,7 +444,7 @@ export interface Game extends GameMap {
|
||||
ticks(): Tick;
|
||||
inSpawnPhase(): boolean;
|
||||
executeNextTick(): GameUpdates;
|
||||
setWinner(winner: Player | TeamName, allPlayersStats: AllPlayersStats): void;
|
||||
setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void;
|
||||
config(): Config;
|
||||
|
||||
// Units
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
PlayerInfo,
|
||||
PlayerType,
|
||||
Team,
|
||||
TeamName,
|
||||
TerrainType,
|
||||
TerraNullius,
|
||||
Unit,
|
||||
@@ -76,11 +75,8 @@ export class GameImpl implements Game {
|
||||
|
||||
private _stats: StatsImpl = new StatsImpl();
|
||||
|
||||
private playerTeams: Team[] = [
|
||||
{ name: TeamName.Red },
|
||||
{ name: TeamName.Blue },
|
||||
];
|
||||
private botTeam: Team = { name: TeamName.Bot };
|
||||
private playerTeams: Team[] = [Team.Red, Team.Blue];
|
||||
private botTeam: Team = Team.Bot;
|
||||
|
||||
constructor(
|
||||
private _humans: PlayerInfo[],
|
||||
@@ -103,6 +99,17 @@ export class GameImpl implements Game {
|
||||
),
|
||||
);
|
||||
this.unitGrid = new UnitGrid(this._map);
|
||||
|
||||
if (_config.gameConfig().gameMode === GameMode.Team) {
|
||||
const numPlayerTeams = _config.numPlayerTeams();
|
||||
if (numPlayerTeams < 2) throw new Error("Too few teams!");
|
||||
if (numPlayerTeams >= 3) this.playerTeams.push(Team.Teal);
|
||||
if (numPlayerTeams >= 4) this.playerTeams.push(Team.Purple);
|
||||
if (numPlayerTeams >= 5) this.playerTeams.push(Team.Yellow);
|
||||
if (numPlayerTeams >= 6) this.playerTeams.push(Team.Orange);
|
||||
if (numPlayerTeams >= 7) this.playerTeams.push(Team.Green);
|
||||
if (numPlayerTeams >= 8) throw new Error("Too many teams!");
|
||||
}
|
||||
}
|
||||
|
||||
private addHumans() {
|
||||
@@ -110,7 +117,7 @@ export class GameImpl implements Game {
|
||||
this._humans.forEach((p) => this.addPlayer(p));
|
||||
return;
|
||||
}
|
||||
const playerToTeam = assignTeams(this._humans);
|
||||
const playerToTeam = assignTeams(this._humans, this.playerTeams);
|
||||
for (const [playerInfo, team] of playerToTeam.entries()) {
|
||||
if (team == "kicked") {
|
||||
console.warn(`Player ${playerInfo.name} was kicked from team`);
|
||||
@@ -555,7 +562,7 @@ export class GameImpl implements Game {
|
||||
});
|
||||
}
|
||||
|
||||
setWinner(winner: Player | TeamName, allPlayersStats: AllPlayersStats): void {
|
||||
setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void {
|
||||
this.addUpdate({
|
||||
type: GameUpdateType.Win,
|
||||
winner: typeof winner === "string" ? winner : winner.smallID(),
|
||||
@@ -684,8 +691,8 @@ export class GameImpl implements Game {
|
||||
manhattanDist(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.manhattanDist(c1, c2);
|
||||
}
|
||||
euclideanDist(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.euclideanDist(c1, c2);
|
||||
euclideanDistSquared(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.euclideanDistSquared(c1, c2);
|
||||
}
|
||||
bfs(
|
||||
tile: TileRef,
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface GameMap {
|
||||
forEachTile(fn: (tile: TileRef) => void): void;
|
||||
|
||||
manhattanDist(c1: TileRef, c2: TileRef): number;
|
||||
euclideanDist(c1: TileRef, c2: TileRef): number;
|
||||
euclideanDistSquared(c1: TileRef, c2: TileRef): number;
|
||||
bfs(
|
||||
tile: TileRef,
|
||||
filter: (gm: GameMap, tile: TileRef) => boolean,
|
||||
@@ -266,11 +266,10 @@ export class GameMapImpl implements GameMap {
|
||||
Math.abs(this.x(c1) - this.x(c2)) + Math.abs(this.y(c1) - this.y(c2))
|
||||
);
|
||||
}
|
||||
euclideanDist(c1: TileRef, c2: TileRef): number {
|
||||
return Math.sqrt(
|
||||
Math.pow(this.x(c1) - this.x(c2), 2) +
|
||||
Math.pow(this.y(c1) - this.y(c2), 2),
|
||||
);
|
||||
euclideanDistSquared(c1: TileRef, c2: TileRef): number {
|
||||
const x = this.x(c1) - this.x(c2);
|
||||
const y = this.y(c1) - this.y(c2);
|
||||
return x * x + y * y;
|
||||
}
|
||||
bfs(
|
||||
tile: TileRef,
|
||||
@@ -322,8 +321,10 @@ export function euclDistFN(
|
||||
dist: number,
|
||||
center: boolean = false,
|
||||
): (gm: GameMap, tile: TileRef) => boolean {
|
||||
const dist2 = dist * dist;
|
||||
if (!center) {
|
||||
return (gm: GameMap, n: TileRef) => gm.euclideanDist(root, n) <= dist;
|
||||
return (gm: GameMap, n: TileRef) =>
|
||||
gm.euclideanDistSquared(root, n) <= dist2;
|
||||
} else {
|
||||
return (gm: GameMap, n: TileRef) => {
|
||||
// shifts the root tile’s coordinates by -0.5 so that its “center”
|
||||
@@ -333,7 +334,7 @@ export function euclDistFN(
|
||||
const rootY = gm.y(root) - 0.5;
|
||||
const dx = gm.x(n) - rootX;
|
||||
const dy = gm.y(n) - rootY;
|
||||
return Math.sqrt(dx * dx + dy * dy) <= dist;
|
||||
return dx * dx + dy * dy <= dist2;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
NameViewData,
|
||||
PlayerID,
|
||||
PlayerType,
|
||||
TeamName,
|
||||
Team,
|
||||
Tick,
|
||||
UnitType,
|
||||
} from "./Game";
|
||||
@@ -92,7 +92,7 @@ export interface PlayerUpdate {
|
||||
name: string;
|
||||
displayName: string;
|
||||
id: PlayerID;
|
||||
teamName?: TeamName;
|
||||
team?: Team;
|
||||
smallID: number;
|
||||
playerType: PlayerType;
|
||||
isAlive: boolean;
|
||||
@@ -161,7 +161,7 @@ export interface WinUpdate {
|
||||
type: GameUpdateType.Win;
|
||||
allPlayersStats: AllPlayersStats;
|
||||
// Player id or team name.
|
||||
winner: number | TeamName;
|
||||
winner: number | Team;
|
||||
winnerType: "player" | "team";
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
PlayerInfo,
|
||||
PlayerProfile,
|
||||
PlayerType,
|
||||
TeamName,
|
||||
Team,
|
||||
TerrainType,
|
||||
TerraNullius,
|
||||
Tick,
|
||||
@@ -177,8 +177,8 @@ export class PlayerView {
|
||||
id(): PlayerID {
|
||||
return this.data.id;
|
||||
}
|
||||
teamName(): TeamName {
|
||||
return this.data.teamName;
|
||||
team(): Team | null {
|
||||
return this.data.team ?? null;
|
||||
}
|
||||
type(): PlayerType {
|
||||
return this.data.playerType;
|
||||
@@ -223,9 +223,7 @@ export class PlayerView {
|
||||
}
|
||||
|
||||
isOnSameTeam(other: PlayerView): boolean {
|
||||
return (
|
||||
this.data.teamName != null && this.data.teamName == other.data.teamName
|
||||
);
|
||||
return this.data.team != null && this.data.team == other.data.team;
|
||||
}
|
||||
|
||||
isFriendly(other: PlayerView): boolean {
|
||||
@@ -529,8 +527,8 @@ export class GameView implements GameMap {
|
||||
manhattanDist(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.manhattanDist(c1, c2);
|
||||
}
|
||||
euclideanDist(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.euclideanDist(c1, c2);
|
||||
euclideanDistSquared(c1: TileRef, c2: TileRef): number {
|
||||
return this._map.euclideanDistSquared(c1, c2);
|
||||
}
|
||||
bfs(
|
||||
tile: TileRef,
|
||||
@@ -552,6 +550,8 @@ export class GameView implements GameMap {
|
||||
}
|
||||
|
||||
focusedPlayer(): PlayerView | null {
|
||||
// TODO: renable when performance issues are fixed.
|
||||
return this.myPlayer();
|
||||
if (userSettings.focusLocked()) return this.myPlayer();
|
||||
return this._focusedPlayer;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
Attack,
|
||||
Cell,
|
||||
EmojiMessage,
|
||||
GameMode,
|
||||
Gold,
|
||||
MessageType,
|
||||
MutableAlliance,
|
||||
@@ -127,7 +128,7 @@ export class PlayerImpl implements Player {
|
||||
name: this.name(),
|
||||
displayName: this.displayName(),
|
||||
id: this.id(),
|
||||
teamName: this.team()?.name,
|
||||
team: this.team(),
|
||||
smallID: this.smallID(),
|
||||
playerType: this.type(),
|
||||
isAlive: this.isAlive(),
|
||||
@@ -516,6 +517,13 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
canDonate(recipient: Player): boolean {
|
||||
if (
|
||||
recipient.type() == PlayerType.Human &&
|
||||
this.mg.config().gameConfig().gameMode == GameMode.FFA
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isFriendly(recipient)) {
|
||||
return false;
|
||||
}
|
||||
@@ -596,7 +604,7 @@ export class PlayerImpl implements Player {
|
||||
if (this.team() == null || other.team() == null) {
|
||||
return false;
|
||||
}
|
||||
return this._team.name == other.team().name;
|
||||
return this._team == other.team();
|
||||
}
|
||||
|
||||
isFriendly(other: Player): boolean {
|
||||
@@ -768,6 +776,12 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
nukeSpawn(tile: TileRef): TileRef | false {
|
||||
const owner = this.mg.owner(tile);
|
||||
if (owner.isPlayer()) {
|
||||
if (this.isOnSameTeam(owner)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// only get missilesilos that are not on cooldown
|
||||
const spawns = this.units(UnitType.MissileSilo)
|
||||
.map((u) => u as Unit)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { PlayerInfo, Team, TeamName } from "./Game";
|
||||
import { PlayerInfo, Team } from "./Game";
|
||||
|
||||
export function assignTeams(
|
||||
players: PlayerInfo[],
|
||||
teams: Team[],
|
||||
): Map<PlayerInfo, Team | "kicked"> {
|
||||
const result = new Map<PlayerInfo, Team | "kicked">();
|
||||
let redTeamCount = 0;
|
||||
let blueTeamCount = 0;
|
||||
const teamPlayerCount = new Map<Team, number>();
|
||||
|
||||
// Group players by clan
|
||||
const clanGroups = new Map<string, PlayerInfo[]>();
|
||||
@@ -23,7 +23,7 @@ export function assignTeams(
|
||||
}
|
||||
}
|
||||
|
||||
const maxTeamSize = Math.ceil(players.length / 2);
|
||||
const maxTeamSize = Math.ceil(players.length / teams.length);
|
||||
|
||||
// Sort clans by size (largest first)
|
||||
const sortedClans = Array.from(clanGroups.entries()).sort(
|
||||
@@ -33,38 +33,38 @@ export function assignTeams(
|
||||
// First, assign clan players
|
||||
for (const [_, clanPlayers] of sortedClans) {
|
||||
// Try to keep the clan together on the team with fewer players
|
||||
if (redTeamCount <= blueTeamCount) {
|
||||
// Assign to red team
|
||||
for (const player of clanPlayers) {
|
||||
if (redTeamCount < maxTeamSize) {
|
||||
redTeamCount++;
|
||||
result.set(player, { name: TeamName.Red });
|
||||
} else {
|
||||
result.set(player, "kicked");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assign to blue team
|
||||
for (const player of clanPlayers) {
|
||||
if (blueTeamCount < maxTeamSize) {
|
||||
blueTeamCount++;
|
||||
result.set(player, { name: TeamName.Blue });
|
||||
} else {
|
||||
result.set(player, "kicked");
|
||||
}
|
||||
let team: Team | null = null;
|
||||
let teamSize = 0;
|
||||
for (const t of teams) {
|
||||
const p = teamPlayerCount.get(t) ?? 0;
|
||||
if (team !== null && teamSize <= p) continue;
|
||||
teamSize = p;
|
||||
team = t;
|
||||
}
|
||||
|
||||
for (const player of clanPlayers) {
|
||||
if (teamSize < maxTeamSize) {
|
||||
teamSize++;
|
||||
result.set(player, team);
|
||||
} else {
|
||||
result.set(player, "kicked");
|
||||
}
|
||||
}
|
||||
teamPlayerCount.set(team, teamSize);
|
||||
}
|
||||
|
||||
// Then, assign non-clan players to balance teams
|
||||
for (const player of noClanPlayers) {
|
||||
if (redTeamCount <= blueTeamCount) {
|
||||
redTeamCount++;
|
||||
result.set(player, { name: TeamName.Red });
|
||||
} else {
|
||||
blueTeamCount++;
|
||||
result.set(player, { name: TeamName.Blue });
|
||||
let team: Team | null = null;
|
||||
let teamSize = 0;
|
||||
for (const t of teams) {
|
||||
const p = teamPlayerCount.get(t) ?? 0;
|
||||
if (team !== null && teamSize <= p) continue;
|
||||
teamSize = p;
|
||||
team = t;
|
||||
}
|
||||
teamPlayerCount.set(team, teamSize + 1);
|
||||
result.set(player, team);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -86,6 +86,8 @@ export class UnitImpl implements Unit {
|
||||
}
|
||||
this._lastTile = this._tile;
|
||||
this._tile = tile;
|
||||
this.mg.removeUnit(this);
|
||||
this.mg.addUnit(this);
|
||||
this.mg.addUpdate(this.toUpdate());
|
||||
}
|
||||
setTroops(troops: number): void {
|
||||
|
||||
@@ -25,7 +25,9 @@ export class UserSettings {
|
||||
}
|
||||
|
||||
focusLocked() {
|
||||
return this.get("settings.focusLocked", false);
|
||||
return false;
|
||||
// TODO: renable when performance issues are fixed.
|
||||
this.get("settings.focusLocked", true);
|
||||
}
|
||||
|
||||
toggleLeftClickOpenMenu() {
|
||||
|
||||
@@ -16,5 +16,6 @@ export class Client {
|
||||
public readonly ip: string,
|
||||
public readonly username: string,
|
||||
public readonly ws: WebSocket,
|
||||
public readonly flag: string | null,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import { GameType } from "../core/game/Game";
|
||||
import { archive } from "./Archive";
|
||||
import { Client } from "./Client";
|
||||
import { gatekeeper } from "./Gatekeeper";
|
||||
import { slog } from "./StructuredLog";
|
||||
export enum GamePhase {
|
||||
Lobby = "LOBBY",
|
||||
Active = "ACTIVE",
|
||||
@@ -99,19 +98,11 @@ export class GameServer {
|
||||
}
|
||||
|
||||
public addClient(client: Client, lastTurn: number) {
|
||||
this.log.info(`adding client ${client.clientID}`);
|
||||
slog({
|
||||
logKey: "client_joined_game",
|
||||
msg: `client ${client.clientID} (re)joining game ${this.id}`,
|
||||
data: {
|
||||
clientID: client.clientID,
|
||||
clientIP: client.ip,
|
||||
gameID: this.id,
|
||||
isRejoin: lastTurn > 0,
|
||||
},
|
||||
this.log.info("client (re)joining game", {
|
||||
clientID: client.clientID,
|
||||
persistentID: client.persistentID,
|
||||
gameID: this.id,
|
||||
clientIP: client.ip,
|
||||
isRejoin: lastTurn > 0,
|
||||
});
|
||||
|
||||
if (
|
||||
@@ -120,9 +111,10 @@ export class GameServer {
|
||||
(c) => c.ip == client.ip && c.clientID != client.clientID,
|
||||
).length >= 3
|
||||
) {
|
||||
this.log.info(
|
||||
`cannot add client ${client.clientID}, already have 3 ips (${client.ip})`,
|
||||
);
|
||||
this.log.warn("cannot add client, already have 3 ips", {
|
||||
clientID: client.clientID,
|
||||
clientIP: client.ip,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,6 +148,10 @@ export class GameServer {
|
||||
if (client.persistentID != clientMsg.persistentID) {
|
||||
this.log.warn(
|
||||
`Client ID ${clientMsg.clientID} sent incorrect id ${clientMsg.persistentID}, does not match persistent id ${client.persistentID}`,
|
||||
{
|
||||
clientID: clientMsg.clientID,
|
||||
persistentID: clientMsg.persistentID,
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -168,9 +164,10 @@ export class GameServer {
|
||||
if (clientMsg.gameID == this.id) {
|
||||
this.addIntent(clientMsg.intent);
|
||||
} else {
|
||||
this.log.warn(
|
||||
`${this.id}: client ${clientMsg.clientID} sent to wrong game`,
|
||||
);
|
||||
this.log.warn("client sent to wrong game", {
|
||||
clientID: clientMsg.clientID,
|
||||
persistentID: clientMsg.persistentID,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (clientMsg.type == "ping") {
|
||||
@@ -187,12 +184,18 @@ export class GameServer {
|
||||
} catch (error) {
|
||||
this.log.info(
|
||||
`error handline websocket request in game server: ${error}`,
|
||||
{
|
||||
clientID: client.clientID,
|
||||
},
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
client.ws.on("close", () => {
|
||||
this.log.info(`${this.id}: client ${client.clientID} disconnected`);
|
||||
this.log.info("client disconnected", {
|
||||
clientID: client.clientID,
|
||||
persistentID: client.persistentID,
|
||||
});
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID != client.clientID,
|
||||
);
|
||||
@@ -245,7 +248,10 @@ export class GameServer {
|
||||
|
||||
const msg = JSON.stringify(prestartMsg.data);
|
||||
this.activeClients.forEach((c) => {
|
||||
this.log.info(`${this.id}: sending prestart message to ${c.clientID}`);
|
||||
this.log.info("sending prestart message", {
|
||||
clientID: c.clientID,
|
||||
persistentID: c.persistentID,
|
||||
});
|
||||
c.ws.send(msg);
|
||||
});
|
||||
}
|
||||
@@ -267,6 +273,7 @@ export class GameServer {
|
||||
playerID: c.playerID,
|
||||
username: c.username,
|
||||
clientID: c.clientID,
|
||||
flag: c.flag,
|
||||
})),
|
||||
});
|
||||
|
||||
@@ -275,7 +282,10 @@ export class GameServer {
|
||||
this.config.turnIntervalMs(),
|
||||
);
|
||||
this.activeClients.forEach((c) => {
|
||||
this.log.info(`${this.id}: sending start message to ${c.clientID}`);
|
||||
this.log.info("sending start message", {
|
||||
clientID: c.clientID,
|
||||
persistentID: c.persistentID,
|
||||
});
|
||||
this.sendStartGameMsg(c.ws, 0);
|
||||
});
|
||||
}
|
||||
@@ -326,10 +336,8 @@ export class GameServer {
|
||||
);
|
||||
} catch (error) {
|
||||
this.log.info(
|
||||
`error sending message for game ${this.id}, error ${error}`.substring(
|
||||
0,
|
||||
250,
|
||||
),
|
||||
`error sending message for game: ${error.substring(0, 250)}`,
|
||||
{},
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -348,9 +356,11 @@ export class GameServer {
|
||||
client.ws.close(1000, "game has ended");
|
||||
}
|
||||
});
|
||||
this.log.info(
|
||||
`${this.id}: ending game ${this.id} with ${this.turns.length} turns`,
|
||||
);
|
||||
if (!this._hasPrestarted || !this._hasStarted) {
|
||||
this.log.info(`game not started, not archiving game`);
|
||||
return;
|
||||
}
|
||||
this.log.info(`ending game with ${this.turns.length} turns`);
|
||||
try {
|
||||
if (this.allClients.size > 0) {
|
||||
const playerRecords: PlayerRecord[] = Array.from(
|
||||
@@ -375,7 +385,9 @@ export class GameServer {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
this.log.info(`${this.id}: no clients joined, not archiving game`);
|
||||
this.log.info("no clients joined, not archiving game", {
|
||||
gameID: this.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
let errorDetails;
|
||||
@@ -407,9 +419,10 @@ export class GameServer {
|
||||
const alive = [];
|
||||
for (const client of this.activeClients) {
|
||||
if (now - client.lastPing > 60_000) {
|
||||
this.log.info(
|
||||
`${this.id}: no pings from ${client.clientID}, terminating connection`,
|
||||
);
|
||||
this.log.info("no pings received, terminating connection", {
|
||||
clientID: client.clientID,
|
||||
persistentID: client.persistentID,
|
||||
});
|
||||
if (client.ws.readyState === WebSocket.OPEN) {
|
||||
client.ws.close(1000, "no heartbeats received, closing connection");
|
||||
}
|
||||
@@ -419,7 +432,9 @@ export class GameServer {
|
||||
}
|
||||
this.activeClients = alive;
|
||||
if (now > this.createdAt + this.maxGameDuration) {
|
||||
this.log.warn(`${this.id}: game past max duration ${this.id}`);
|
||||
this.log.warn("game past max duration", {
|
||||
gameID: this.id,
|
||||
});
|
||||
return GamePhase.Finished;
|
||||
}
|
||||
|
||||
@@ -429,7 +444,9 @@ export class GameServer {
|
||||
if (this.gameConfig.gameType != GameType.Public) {
|
||||
if (this._hasStarted) {
|
||||
if (noActive && noRecentPings) {
|
||||
this.log.info(`${this.id}: private game: ${this.id} complete`);
|
||||
this.log.info("private game complete", {
|
||||
gameID: this.id,
|
||||
});
|
||||
return GamePhase.Finished;
|
||||
} else {
|
||||
return GamePhase.Active;
|
||||
@@ -507,7 +524,10 @@ export class GameServer {
|
||||
totalActiveClients: this.activeClients.length,
|
||||
});
|
||||
if (!serverDesync.success) {
|
||||
this.log.warn(`failed to create desync message ${serverDesync.error}`);
|
||||
this.log.warn("failed to create desync message", {
|
||||
gameID: this.id,
|
||||
error: serverDesync.error,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -517,7 +537,11 @@ export class GameServer {
|
||||
continue;
|
||||
}
|
||||
this.sentDesyncMessageClients.add(c.clientID);
|
||||
this.log.info(`game: ${this.id}: sending desync to client ${c.clientID}`);
|
||||
this.log.info("sending desync to client", {
|
||||
gameID: this.id,
|
||||
clientID: c.clientID,
|
||||
persistentID: c.persistentID,
|
||||
});
|
||||
c.ws.send(desyncMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GameMapType } from "../core/game/Game";
|
||||
import { GameMapType, GameMode } from "../core/game/Game";
|
||||
import { PseudoRandom } from "../core/PseudoRandom";
|
||||
|
||||
enum PlaylistType {
|
||||
@@ -9,6 +9,9 @@ enum PlaylistType {
|
||||
const random = new PseudoRandom(123);
|
||||
|
||||
export class MapPlaylist {
|
||||
private gameModeRotation = [GameMode.FFA, GameMode.FFA, GameMode.Team];
|
||||
private currentGameModeIndex = 0;
|
||||
|
||||
private mapsPlaylistBig: GameMapType[] = [];
|
||||
private mapsPlaylistSmall: GameMapType[] = [];
|
||||
private currentPlaylistCounter = 0;
|
||||
@@ -20,6 +23,13 @@ export class MapPlaylist {
|
||||
return mapsPlaylist.shift()!;
|
||||
}
|
||||
|
||||
public getNextGameMode(): GameMode {
|
||||
const nextGameMode = this.gameModeRotation[this.currentGameModeIndex];
|
||||
this.currentGameModeIndex =
|
||||
(this.currentGameModeIndex + 1) % this.gameModeRotation.length;
|
||||
return nextGameMode;
|
||||
}
|
||||
|
||||
private getNextMapsPlayList(playlistType: PlaylistType): GameMapType[] {
|
||||
switch (playlistType) {
|
||||
case PlaylistType.BigMaps:
|
||||
|
||||
@@ -24,7 +24,7 @@ const server = http.createServer(app);
|
||||
const metricsApp = express();
|
||||
const metricsServer = http.createServer(metricsApp);
|
||||
|
||||
const log = logger.child({ component: "Master" });
|
||||
const log = logger.child({ comp: "m" });
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -222,13 +222,26 @@ async function fetchLobbies(): Promise<number> {
|
||||
return publicLobbyIDs.size;
|
||||
}
|
||||
|
||||
let lastGameMode: GameMode = GameMode.FFA;
|
||||
|
||||
// Function to schedule a new public game
|
||||
async function schedulePublicGame(playlist: MapPlaylist) {
|
||||
const gameID = generateID();
|
||||
const map = playlist.getNextMap();
|
||||
publicLobbyIDs.add(gameID);
|
||||
|
||||
if (lastGameMode == GameMode.FFA) {
|
||||
lastGameMode = GameMode.Team;
|
||||
} else {
|
||||
lastGameMode = GameMode.FFA;
|
||||
}
|
||||
|
||||
const gameMode = playlist.getNextGameMode();
|
||||
const numPlayerTeams =
|
||||
gameMode === GameMode.Team ? 2 + Math.floor(Math.random() * 5) : undefined;
|
||||
|
||||
// Create the default public game config (from your GameManager)
|
||||
const defaultGameConfig = {
|
||||
const defaultGameConfig: GameConfig = {
|
||||
gameMap: map,
|
||||
maxPlayers: config.lobbyMaxPlayers(map),
|
||||
gameType: GameType.Public,
|
||||
@@ -236,11 +249,12 @@ async function schedulePublicGame(playlist: MapPlaylist) {
|
||||
infiniteGold: false,
|
||||
infiniteTroops: false,
|
||||
instantBuild: false,
|
||||
disableNPCs: false,
|
||||
disableNPCs: gameMode == GameMode.Team,
|
||||
disableNukes: false,
|
||||
gameMode: Math.random() < 0.7 ? GameMode.FFA : GameMode.Team,
|
||||
gameMode,
|
||||
numPlayerTeams,
|
||||
bots: 400,
|
||||
} as GameConfig;
|
||||
};
|
||||
|
||||
const workerPath = config.workerPath(gameID);
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import cluster from "cluster";
|
||||
import * as dotenv from "dotenv";
|
||||
import { startMaster } from "./Master";
|
||||
import { startWorker } from "./Worker";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
// Main entry point of the application
|
||||
async function main() {
|
||||
// Check if this is the primary (master) process
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { ClientID, GameID, LogSeverity } from "../core/Schemas";
|
||||
|
||||
export interface slogMsg {
|
||||
logKey: string;
|
||||
msg: string;
|
||||
data?: {
|
||||
stack?: unknown;
|
||||
clientID?: unknown;
|
||||
clientIP?: unknown;
|
||||
gameID?: unknown;
|
||||
isRejoin?: unknown;
|
||||
};
|
||||
severity?: LogSeverity;
|
||||
gameID?: GameID;
|
||||
clientID?: ClientID;
|
||||
persistentID?: string;
|
||||
stack?: string; // Added stack property
|
||||
}
|
||||
|
||||
export function slog(msg: slogMsg): void {
|
||||
msg.severity = msg.severity ?? LogSeverity.Info;
|
||||
|
||||
// Format stack trace if available
|
||||
if (msg.stack) {
|
||||
// Keep the stack trace in the log data
|
||||
if (!msg.data) {
|
||||
msg.data = { stack: msg.stack };
|
||||
} else if (typeof msg.data === "object") {
|
||||
msg.data.stack = msg.stack;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.GAME_ENV == "dev") {
|
||||
// Avoid blowing up the log during development.
|
||||
if (msg.logKey == "client_console_log") {
|
||||
return;
|
||||
}
|
||||
if (msg.severity != LogSeverity.Debug) {
|
||||
console.log(msg.msg);
|
||||
// Print stack trace in development for errors
|
||||
if (msg.severity === LogSeverity.Error && msg.stack) {
|
||||
console.error(msg.stack);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
console.log(JSON.stringify(msg));
|
||||
} catch (error) {
|
||||
console.error("Failed to stringify log message:", error);
|
||||
// Fallback to basic logging
|
||||
console.log(`${msg.severity}: ${msg.msg}`);
|
||||
if (msg.severity === LogSeverity.Error && msg.stack) {
|
||||
console.error(msg.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||