diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2024-11-23 21:52:24 +0100 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2024-11-23 21:52:24 +0100 |
| commit | 6f7374c2fa58c8692b51018864b802e6b876d305 (patch) | |
| tree | a7e8ead757e9f4de1920395336dcac1c8a989576 | |
A new start
174 files changed, 17631 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a661307 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/
+build/
+art/*.psd
\ No newline at end of file @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Aldrik Ramaekers + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e82448 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +
+main:
+ mkdir -p "build/"
+ cp -a "data/." "build/data"
+ gcc -m64 -Wall -g -DMODE_DEBUG src/main.c -o build/truckerx.exe -Llibs/ -lprojectbase-debug -lSDL2 -lSDL2_mixer
+ ./build/truckerx.exe
+
+debug:
+ mkdir -p "build/"
+ cp -a "data/." "build/data"
+ gcc -m64 -Wall -g -DMODE_DEBUG src/main.c -o build/truckerx.exe -Llibs/ -lprojectbase-debug -lSDL2 -lSDL2_mixer
+ gdb -q -ex='set confirm on' -ex=run -ex=quit --args ./build/truckerx.exe
+
+linux:
+ mkdir -p "build/"
+ cp -a "data/." "build/data"
+ gcc -m64 -Wall -g -DMODE_DEBUG src/main.c -o build/truckerx -lprojectbase-debug -lX11 -lm -ldl -lSDL2 -lSDL2_mixer
+ sudo chmod +x ./build/truckerx
+ ./build/truckerx
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b3d1d4 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +Truck logistics management game written using C + OpenGL. Uses SDL2 SDL2_Mixer for audio. + +Video: https://www.youtube.com/watch?v=vd9a-LMGzrs&ab_channel=Aldrik diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..5a407c9 --- /dev/null +++ b/build.bat @@ -0,0 +1,2 @@ +gcc.exe -m64 -w -g -DMODE_DEBUG src/main.c -o build/truckerx2.exe -Llibs/ -lSDL2 -lSDL2_mixer +call build\truckerx2.exe
\ No newline at end of file diff --git a/data/fonts/Exo-Light.ttf b/data/fonts/Exo-Light.ttf Binary files differnew file mode 100644 index 0000000..b539e75 --- /dev/null +++ b/data/fonts/Exo-Light.ttf diff --git a/data/fonts/Exo-LightItalic.ttf b/data/fonts/Exo-LightItalic.ttf Binary files differnew file mode 100644 index 0000000..494f1dd --- /dev/null +++ b/data/fonts/Exo-LightItalic.ttf diff --git a/data/fonts/Exo-Medium.ttf b/data/fonts/Exo-Medium.ttf Binary files differnew file mode 100644 index 0000000..dccd527 --- /dev/null +++ b/data/fonts/Exo-Medium.ttf diff --git a/data/fonts/Exo-MediumItalic.ttf b/data/fonts/Exo-MediumItalic.ttf Binary files differnew file mode 100644 index 0000000..573fbe7 --- /dev/null +++ b/data/fonts/Exo-MediumItalic.ttf diff --git a/data/fonts/Exo-Regular.ttf b/data/fonts/Exo-Regular.ttf Binary files differnew file mode 100644 index 0000000..e370360 --- /dev/null +++ b/data/fonts/Exo-Regular.ttf diff --git a/data/fonts/Exo-RegularItalic.ttf b/data/fonts/Exo-RegularItalic.ttf Binary files differnew file mode 100644 index 0000000..b0e0121 --- /dev/null +++ b/data/fonts/Exo-RegularItalic.ttf diff --git a/data/fonts/Exo-SemiBold.ttf b/data/fonts/Exo-SemiBold.ttf Binary files differnew file mode 100644 index 0000000..f61ce97 --- /dev/null +++ b/data/fonts/Exo-SemiBold.ttf diff --git a/data/fonts/Exo-SemiBoldItalic.ttf b/data/fonts/Exo-SemiBoldItalic.ttf Binary files differnew file mode 100644 index 0000000..13b4907 --- /dev/null +++ b/data/fonts/Exo-SemiBoldItalic.ttf diff --git a/data/img/arrow-left-rounded.png b/data/img/arrow-left-rounded.png Binary files differnew file mode 100644 index 0000000..1036fb5 --- /dev/null +++ b/data/img/arrow-left-rounded.png diff --git a/data/img/arrow-left.png b/data/img/arrow-left.png Binary files differnew file mode 100644 index 0000000..1c9048b --- /dev/null +++ b/data/img/arrow-left.png diff --git a/data/img/arrow-right.png b/data/img/arrow-right.png Binary files differnew file mode 100644 index 0000000..98eee02 --- /dev/null +++ b/data/img/arrow-right.png diff --git a/data/img/back.png b/data/img/back.png Binary files differnew file mode 100644 index 0000000..a3b04da --- /dev/null +++ b/data/img/back.png diff --git a/data/img/bank.png b/data/img/bank.png Binary files differnew file mode 100644 index 0000000..08f8548 --- /dev/null +++ b/data/img/bank.png diff --git a/data/img/boat.png b/data/img/boat.png Binary files differnew file mode 100644 index 0000000..a8b71f5 --- /dev/null +++ b/data/img/boat.png diff --git a/data/img/button_bottom.png b/data/img/button_bottom.png Binary files differnew file mode 100644 index 0000000..4965d4e --- /dev/null +++ b/data/img/button_bottom.png diff --git a/data/img/button_bottomleft.png b/data/img/button_bottomleft.png Binary files differnew file mode 100644 index 0000000..354dafd --- /dev/null +++ b/data/img/button_bottomleft.png diff --git a/data/img/button_bottomright.png b/data/img/button_bottomright.png Binary files differnew file mode 100644 index 0000000..e3de11f --- /dev/null +++ b/data/img/button_bottomright.png diff --git a/data/img/button_left.png b/data/img/button_left.png Binary files differnew file mode 100644 index 0000000..194d8ae --- /dev/null +++ b/data/img/button_left.png diff --git a/data/img/button_right.png b/data/img/button_right.png Binary files differnew file mode 100644 index 0000000..163f85d --- /dev/null +++ b/data/img/button_right.png diff --git a/data/img/button_top.png b/data/img/button_top.png Binary files differnew file mode 100644 index 0000000..398aca3 --- /dev/null +++ b/data/img/button_top.png diff --git a/data/img/button_topleft.png b/data/img/button_topleft.png Binary files differnew file mode 100644 index 0000000..fdb8bc6 --- /dev/null +++ b/data/img/button_topleft.png diff --git a/data/img/button_topright.png b/data/img/button_topright.png Binary files differnew file mode 100644 index 0000000..d465193 --- /dev/null +++ b/data/img/button_topright.png diff --git a/data/img/car-wheel.png b/data/img/car-wheel.png Binary files differnew file mode 100644 index 0000000..f8d98aa --- /dev/null +++ b/data/img/car-wheel.png diff --git a/data/img/checkmark.png b/data/img/checkmark.png Binary files differnew file mode 100644 index 0000000..6f94bfe --- /dev/null +++ b/data/img/checkmark.png diff --git a/data/img/city.png b/data/img/city.png Binary files differnew file mode 100644 index 0000000..5f71ee3 --- /dev/null +++ b/data/img/city.png diff --git a/data/img/close.png b/data/img/close.png Binary files differnew file mode 100644 index 0000000..ec2af21 --- /dev/null +++ b/data/img/close.png diff --git a/data/img/coins.png b/data/img/coins.png Binary files differnew file mode 100644 index 0000000..12b55a1 --- /dev/null +++ b/data/img/coins.png diff --git a/data/img/denied.png b/data/img/denied.png Binary files differnew file mode 100644 index 0000000..f4162c0 --- /dev/null +++ b/data/img/denied.png diff --git a/data/img/dot.png b/data/img/dot.png Binary files differnew file mode 100644 index 0000000..120abfd --- /dev/null +++ b/data/img/dot.png diff --git a/data/img/globe.png b/data/img/globe.png Binary files differnew file mode 100644 index 0000000..28ae02c --- /dev/null +++ b/data/img/globe.png diff --git a/data/img/grid.png b/data/img/grid.png Binary files differnew file mode 100644 index 0000000..2fc522c --- /dev/null +++ b/data/img/grid.png diff --git a/data/img/hired.png b/data/img/hired.png Binary files differnew file mode 100644 index 0000000..b015934 --- /dev/null +++ b/data/img/hired.png diff --git a/data/img/iveco-logo.png b/data/img/iveco-logo.png Binary files differnew file mode 100644 index 0000000..cf022d6 --- /dev/null +++ b/data/img/iveco-logo.png diff --git a/data/img/iveco-stralis-activespace.png b/data/img/iveco-stralis-activespace.png Binary files differnew file mode 100644 index 0000000..d72abbd --- /dev/null +++ b/data/img/iveco-stralis-activespace.png diff --git a/data/img/iveco-stralis-hiway.png b/data/img/iveco-stralis-hiway.png Binary files differnew file mode 100644 index 0000000..3f01f83 --- /dev/null +++ b/data/img/iveco-stralis-hiway.png diff --git a/data/img/list.png b/data/img/list.png Binary files differnew file mode 100644 index 0000000..30db793 --- /dev/null +++ b/data/img/list.png diff --git a/data/img/location-pin.png b/data/img/location-pin.png Binary files differnew file mode 100644 index 0000000..ec06a40 --- /dev/null +++ b/data/img/location-pin.png diff --git a/data/img/location_dot.png b/data/img/location_dot.png Binary files differnew file mode 100644 index 0000000..a3b59fb --- /dev/null +++ b/data/img/location_dot.png diff --git a/data/img/lock.png b/data/img/lock.png Binary files differnew file mode 100644 index 0000000..4f5db35 --- /dev/null +++ b/data/img/lock.png diff --git a/data/img/logo.png b/data/img/logo.png Binary files differnew file mode 100644 index 0000000..97dd758 --- /dev/null +++ b/data/img/logo.png diff --git a/data/img/logo_fruitosis.png b/data/img/logo_fruitosis.png Binary files differnew file mode 100644 index 0000000..118fcb1 --- /dev/null +++ b/data/img/logo_fruitosis.png diff --git a/data/img/mercedes-logo.png b/data/img/mercedes-logo.png Binary files differnew file mode 100644 index 0000000..a1c21bf --- /dev/null +++ b/data/img/mercedes-logo.png diff --git a/data/img/panel_bottom.png b/data/img/panel_bottom.png Binary files differnew file mode 100644 index 0000000..effcad7 --- /dev/null +++ b/data/img/panel_bottom.png diff --git a/data/img/panel_bottomleft.png b/data/img/panel_bottomleft.png Binary files differnew file mode 100644 index 0000000..2a224c4 --- /dev/null +++ b/data/img/panel_bottomleft.png diff --git a/data/img/panel_bottomright.png b/data/img/panel_bottomright.png Binary files differnew file mode 100644 index 0000000..3da5051 --- /dev/null +++ b/data/img/panel_bottomright.png diff --git a/data/img/panel_left.png b/data/img/panel_left.png Binary files differnew file mode 100644 index 0000000..57207f8 --- /dev/null +++ b/data/img/panel_left.png diff --git a/data/img/panel_right.png b/data/img/panel_right.png Binary files differnew file mode 100644 index 0000000..7688684 --- /dev/null +++ b/data/img/panel_right.png diff --git a/data/img/panel_top.png b/data/img/panel_top.png Binary files differnew file mode 100644 index 0000000..a664976 --- /dev/null +++ b/data/img/panel_top.png diff --git a/data/img/panel_topleft.png b/data/img/panel_topleft.png Binary files differnew file mode 100644 index 0000000..18d3315 --- /dev/null +++ b/data/img/panel_topleft.png diff --git a/data/img/panel_topright.png b/data/img/panel_topright.png Binary files differnew file mode 100644 index 0000000..7f92e90 --- /dev/null +++ b/data/img/panel_topright.png diff --git a/data/img/pause.png b/data/img/pause.png Binary files differnew file mode 100644 index 0000000..b2753f1 --- /dev/null +++ b/data/img/pause.png diff --git a/data/img/portrait.png b/data/img/portrait.png Binary files differnew file mode 100644 index 0000000..840b054 --- /dev/null +++ b/data/img/portrait.png diff --git a/data/img/portrait/body.png b/data/img/portrait/body.png Binary files differnew file mode 100644 index 0000000..34369f8 --- /dev/null +++ b/data/img/portrait/body.png diff --git a/data/img/portrait/face.png b/data/img/portrait/face.png Binary files differnew file mode 100644 index 0000000..e76c5b0 --- /dev/null +++ b/data/img/portrait/face.png diff --git a/data/img/portrait/hair/hair1.png b/data/img/portrait/hair/hair1.png Binary files differnew file mode 100644 index 0000000..8fab725 --- /dev/null +++ b/data/img/portrait/hair/hair1.png diff --git a/data/img/portrait/hair/hair2.png b/data/img/portrait/hair/hair2.png Binary files differnew file mode 100644 index 0000000..3ea9865 --- /dev/null +++ b/data/img/portrait/hair/hair2.png diff --git a/data/img/portrait/hair/hair3.png b/data/img/portrait/hair/hair3.png Binary files differnew file mode 100644 index 0000000..c327380 --- /dev/null +++ b/data/img/portrait/hair/hair3.png diff --git a/data/img/portrait/hair/hair4.png b/data/img/portrait/hair/hair4.png Binary files differnew file mode 100644 index 0000000..57f3284 --- /dev/null +++ b/data/img/portrait/hair/hair4.png diff --git a/data/img/portrait/hair/hair5.png b/data/img/portrait/hair/hair5.png Binary files differnew file mode 100644 index 0000000..24dec4f --- /dev/null +++ b/data/img/portrait/hair/hair5.png diff --git a/data/img/question-mark.png b/data/img/question-mark.png Binary files differnew file mode 100644 index 0000000..f30122f --- /dev/null +++ b/data/img/question-mark.png diff --git a/data/img/resume.png b/data/img/resume.png Binary files differnew file mode 100644 index 0000000..4686fa6 --- /dev/null +++ b/data/img/resume.png diff --git a/data/img/road.png b/data/img/road.png Binary files differnew file mode 100644 index 0000000..4274ee8 --- /dev/null +++ b/data/img/road.png diff --git a/data/img/signature.png b/data/img/signature.png Binary files differnew file mode 100644 index 0000000..7a1729f --- /dev/null +++ b/data/img/signature.png diff --git a/data/img/star.png b/data/img/star.png Binary files differnew file mode 100644 index 0000000..ac6b582 --- /dev/null +++ b/data/img/star.png diff --git a/data/img/statistics.png b/data/img/statistics.png Binary files differnew file mode 100644 index 0000000..375d5d5 --- /dev/null +++ b/data/img/statistics.png diff --git a/data/img/tab-item.png b/data/img/tab-item.png Binary files differnew file mode 100644 index 0000000..7d2a601 --- /dev/null +++ b/data/img/tab-item.png diff --git a/data/img/timer.png b/data/img/timer.png Binary files differnew file mode 100644 index 0000000..73bbf03 --- /dev/null +++ b/data/img/timer.png diff --git a/data/img/truck-unknown.png b/data/img/truck-unknown.png Binary files differnew file mode 100644 index 0000000..7ddc679 --- /dev/null +++ b/data/img/truck-unknown.png diff --git a/data/img/volvo-logo.png b/data/img/volvo-logo.png Binary files differnew file mode 100644 index 0000000..897c93f --- /dev/null +++ b/data/img/volvo-logo.png diff --git a/data/img/white.png b/data/img/white.png Binary files differnew file mode 100644 index 0000000..fc25c77 --- /dev/null +++ b/data/img/white.png diff --git a/data/img/world-map.png b/data/img/world-map.png Binary files differnew file mode 100644 index 0000000..ca1c263 --- /dev/null +++ b/data/img/world-map.png diff --git a/data/img/world_background.png b/data/img/world_background.png Binary files differnew file mode 100644 index 0000000..cbfa5de --- /dev/null +++ b/data/img/world_background.png diff --git a/data/music/Meydan - Havor/01 Meydan - Glimpse of Eternity.mp3 b/data/music/Meydan - Havor/01 Meydan - Glimpse of Eternity.mp3 Binary files differnew file mode 100644 index 0000000..0615464 --- /dev/null +++ b/data/music/Meydan - Havor/01 Meydan - Glimpse of Eternity.mp3 diff --git a/data/music/Meydan - Havor/02 Meydan - Please wake up.mp3 b/data/music/Meydan - Havor/02 Meydan - Please wake up.mp3 Binary files differnew file mode 100644 index 0000000..6756684 --- /dev/null +++ b/data/music/Meydan - Havor/02 Meydan - Please wake up.mp3 diff --git a/data/music/Meydan - Havor/03 Meydan - Tired of life.mp3 b/data/music/Meydan - Havor/03 Meydan - Tired of life.mp3 Binary files differnew file mode 100644 index 0000000..f59b1e5 --- /dev/null +++ b/data/music/Meydan - Havor/03 Meydan - Tired of life.mp3 diff --git a/data/music/Meydan - Havor/04 Meydan - Surreal Forest.mp3 b/data/music/Meydan - Havor/04 Meydan - Surreal Forest.mp3 Binary files differnew file mode 100644 index 0000000..f286010 --- /dev/null +++ b/data/music/Meydan - Havor/04 Meydan - Surreal Forest.mp3 diff --git a/data/music/Meydan - Havor/05 Meydan - Rain.mp3 b/data/music/Meydan - Havor/05 Meydan - Rain.mp3 Binary files differnew file mode 100644 index 0000000..47fa9d4 --- /dev/null +++ b/data/music/Meydan - Havor/05 Meydan - Rain.mp3 diff --git a/data/music/Meydan - Havor/06 Meydan - L'Etoile danse (Pt. 1).mp3 b/data/music/Meydan - Havor/06 Meydan - L'Etoile danse (Pt. 1).mp3 Binary files differnew file mode 100644 index 0000000..5fc611a --- /dev/null +++ b/data/music/Meydan - Havor/06 Meydan - L'Etoile danse (Pt. 1).mp3 diff --git a/data/music/Meydan - Havor/07 Meydan - L'Etoile danse (Pt. 2).mp3 b/data/music/Meydan - Havor/07 Meydan - L'Etoile danse (Pt. 2).mp3 Binary files differnew file mode 100644 index 0000000..b4b495a --- /dev/null +++ b/data/music/Meydan - Havor/07 Meydan - L'Etoile danse (Pt. 2).mp3 diff --git a/data/music/Meydan - Havor/08 Meydan - Blind.mp3 b/data/music/Meydan - Havor/08 Meydan - Blind.mp3 Binary files differnew file mode 100644 index 0000000..619b955 --- /dev/null +++ b/data/music/Meydan - Havor/08 Meydan - Blind.mp3 diff --git a/data/music/Meydan - Havor/09 Meydan - Contemplate the stars.mp3 b/data/music/Meydan - Havor/09 Meydan - Contemplate the stars.mp3 Binary files differnew file mode 100644 index 0000000..f9d4f71 --- /dev/null +++ b/data/music/Meydan - Havor/09 Meydan - Contemplate the stars.mp3 diff --git a/data/music/Meydan - Havor/10 Meydan - Story.mp3 b/data/music/Meydan - Havor/10 Meydan - Story.mp3 Binary files differnew file mode 100644 index 0000000..5f7809b --- /dev/null +++ b/data/music/Meydan - Havor/10 Meydan - Story.mp3 diff --git a/data/music/Meydan - Havor/11 Meydan - Chalet.mp3 b/data/music/Meydan - Havor/11 Meydan - Chalet.mp3 Binary files differnew file mode 100644 index 0000000..9a167e9 --- /dev/null +++ b/data/music/Meydan - Havor/11 Meydan - Chalet.mp3 diff --git a/data/music/Meydan - Havor/AUTHOR.txt b/data/music/Meydan - Havor/AUTHOR.txt new file mode 100644 index 0000000..3be1aee --- /dev/null +++ b/data/music/Meydan - Havor/AUTHOR.txt @@ -0,0 +1 @@ +Meydän
\ No newline at end of file diff --git a/data/music/Meydan - Havor/LICENSE.txt b/data/music/Meydan - Havor/LICENSE.txt new file mode 100644 index 0000000..939bca6 --- /dev/null +++ b/data/music/Meydan - Havor/LICENSE.txt @@ -0,0 +1,7 @@ +The songs in this album are licensed under Attribution 4.0 International (CC BY 4.0)
+Artist: https://freemusicarchive.org/music/Meydan
+Album: https://freemusicarchive.org/music/Meydan/Havor
+License: https://creativecommons.org/licenses/by/4.0/
+
+Modifications:
+"01 Meydan - Glimpse of Eternity" has been trimmed to remove periods of no sound.
\ No newline at end of file diff --git a/data/music/Nuno Adelaida - Amentia/01 Nuno Adelaida - Amor e odio.mp3 b/data/music/Nuno Adelaida - Amentia/01 Nuno Adelaida - Amor e odio.mp3 Binary files differnew file mode 100644 index 0000000..64105b7 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/01 Nuno Adelaida - Amor e odio.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/02 Nuno Adelaida - Children - Our Life.mp3 b/data/music/Nuno Adelaida - Amentia/02 Nuno Adelaida - Children - Our Life.mp3 Binary files differnew file mode 100644 index 0000000..1bfc14a --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/02 Nuno Adelaida - Children - Our Life.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/03 Nuno Adelaida - F.Meridian.mp3 b/data/music/Nuno Adelaida - Amentia/03 Nuno Adelaida - F.Meridian.mp3 Binary files differnew file mode 100644 index 0000000..5fe8f97 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/03 Nuno Adelaida - F.Meridian.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/04 Nuno Adelaida - I'm A Monster.mp3 b/data/music/Nuno Adelaida - Amentia/04 Nuno Adelaida - I'm A Monster.mp3 Binary files differnew file mode 100644 index 0000000..f942ea2 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/04 Nuno Adelaida - I'm A Monster.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/05 Nuno Adelaida - Mr.Nobody (B and W).mp3 b/data/music/Nuno Adelaida - Amentia/05 Nuno Adelaida - Mr.Nobody (B and W).mp3 Binary files differnew file mode 100644 index 0000000..3f32974 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/05 Nuno Adelaida - Mr.Nobody (B and W).mp3 diff --git a/data/music/Nuno Adelaida - Amentia/06 Nuno Adelaida - Never Too Late To Change Anything.mp3 b/data/music/Nuno Adelaida - Amentia/06 Nuno Adelaida - Never Too Late To Change Anything.mp3 Binary files differnew file mode 100644 index 0000000..849b5e3 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/06 Nuno Adelaida - Never Too Late To Change Anything.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/07 Nuno Adelaida - S.I.mp3 b/data/music/Nuno Adelaida - Amentia/07 Nuno Adelaida - S.I.mp3 Binary files differnew file mode 100644 index 0000000..9baec6e --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/07 Nuno Adelaida - S.I.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/08 Nuno Adelaida - Save Memories.mp3 b/data/music/Nuno Adelaida - Amentia/08 Nuno Adelaida - Save Memories.mp3 Binary files differnew file mode 100644 index 0000000..53ba951 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/08 Nuno Adelaida - Save Memories.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/09 Nuno Adelaida - Sofia 30.mp3 b/data/music/Nuno Adelaida - Amentia/09 Nuno Adelaida - Sofia 30.mp3 Binary files differnew file mode 100644 index 0000000..6de9e71 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/09 Nuno Adelaida - Sofia 30.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/10 Nuno Adelaida - Zulmira.mp3 b/data/music/Nuno Adelaida - Amentia/10 Nuno Adelaida - Zulmira.mp3 Binary files differnew file mode 100644 index 0000000..60315aa --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/10 Nuno Adelaida - Zulmira.mp3 diff --git a/data/music/Nuno Adelaida - Amentia/AUTHOR.txt b/data/music/Nuno Adelaida - Amentia/AUTHOR.txt new file mode 100644 index 0000000..49bd42f --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/AUTHOR.txt @@ -0,0 +1 @@ +Nuno Adelaida
\ No newline at end of file diff --git a/data/music/Nuno Adelaida - Amentia/LICENSE.txt b/data/music/Nuno Adelaida - Amentia/LICENSE.txt new file mode 100644 index 0000000..bcd3702 --- /dev/null +++ b/data/music/Nuno Adelaida - Amentia/LICENSE.txt @@ -0,0 +1,4 @@ +The songs in this album are licensed under Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
+Artist: https://freemusicarchive.org/music/Nuno_Adelaida
+Album: https://freemusicarchive.org/music/Nuno_Adelaida/none_given_1662
+License: https://creativecommons.org/licenses/by-sa/4.0/
diff --git a/data/sounds/accelerate.wav b/data/sounds/accelerate.wav Binary files differnew file mode 100644 index 0000000..026ea50 --- /dev/null +++ b/data/sounds/accelerate.wav diff --git a/data/sounds/click.wav b/data/sounds/click.wav Binary files differnew file mode 100644 index 0000000..67e627e --- /dev/null +++ b/data/sounds/click.wav diff --git a/data/sounds/click2.wav b/data/sounds/click2.wav Binary files differnew file mode 100644 index 0000000..a92759a --- /dev/null +++ b/data/sounds/click2.wav diff --git a/data/sounds/click3.wav b/data/sounds/click3.wav Binary files differnew file mode 100644 index 0000000..b49ff1e --- /dev/null +++ b/data/sounds/click3.wav diff --git a/data/sounds/event.wav b/data/sounds/event.wav Binary files differnew file mode 100644 index 0000000..a691fe6 --- /dev/null +++ b/data/sounds/event.wav diff --git a/data/sounds/return.wav b/data/sounds/return.wav Binary files differnew file mode 100644 index 0000000..749161e --- /dev/null +++ b/data/sounds/return.wav diff --git a/data/world/boat-routes.json b/data/world/boat-routes.json new file mode 100644 index 0000000..96b5688 --- /dev/null +++ b/data/world/boat-routes.json @@ -0,0 +1,202 @@ +[
+ [
+ 0.479049, 0.271413,
+ 0.475922, 0.271413,
+ 0.468418, 0.271413,
+ 0.456535, 0.276974,
+ 0.442777, 0.289210,
+ 0.434021, 0.300334,
+ 0.422139, 0.317019,
+ 0.412758, 0.335929,
+ 0.403377, 0.353726,
+ 0.395872, 0.368187,
+ 0.384615, 0.387097,
+ 0.374609, 0.404894,
+ 0.367104, 0.419355,
+ 0.357098, 0.430478,
+ 0.348968, 0.436040,
+ 0.343965, 0.438265,
+ 0.338962, 0.438265,
+ 0.332083, 0.438265,
+ 0.321451, 0.438265,
+ 0.313946, 0.430478,
+ 0.307692, 0.427141,
+ 0.301438, 0.423804,
+ 0.290807, 0.423804,
+ 0.284553, 0.424917,
+ 0.275797, 0.434928,
+ 0.260788, 0.462736,
+ 0.240775, 0.506118,
+ 0.222639, 0.540601,
+ 0.197624, 0.561735,
+ 0.165103, 0.567297,
+ 0.131957, 0.570634,
+ 0.098812, 0.570634,
+ 0.072545, 0.570634,
+ 0.052533, 0.570634,
+ 0.037523, 0.570634,
+ 0.025016, 0.568409,
+ 0.015635, 0.568409,
+ 0.005629, 0.567297,
+ 0.000000, 0.567297, -0.0500000, 0.567297
+ ],
+ [
+ 0.516847, 0.213559,
+ 0.515575, 0.211299,
+ 0.514940, 0.210169,
+ 0.512397, 0.207910,
+ 0.510490, 0.207910,
+ 0.509218, 0.207910,
+ 0.508582, 0.207910,
+ 0.507947, 0.210169,
+ 0.507947, 0.210169,
+ 0.507947, 0.211299,
+ 0.507947, 0.211299
+ ],
+ [
+ 0.915592, 0.707292,
+ 0.915592, 0.707292,
+ 0.915592, 0.707292,
+ 0.915006, 0.709375,
+ 0.915006, 0.709375,
+ 0.913833, 0.712500,
+ 0.912075, 0.714583,
+ 0.909144, 0.716667,
+ 0.907386, 0.717708,
+ 0.904455, 0.720833,
+ 0.901524, 0.722917,
+ 0.896249, 0.725000,
+ 0.890973, 0.726042,
+ 0.885698, 0.727083,
+ 0.881594, 0.727083,
+ 0.877491, 0.727083,
+ 0.873974, 0.727083,
+ 0.868699, 0.727083,
+ 0.861665, 0.727083,
+ 0.855217, 0.727083,
+ 0.850528, 0.727083,
+ 0.847011, 0.727083,
+ 0.842907, 0.726042,
+ 0.838804, 0.725000,
+ 0.835287, 0.722917,
+ 0.830012, 0.720833,
+ 0.824736, 0.718750,
+ 0.818875, 0.712500,
+ 0.813013, 0.706250,
+ 0.807737, 0.700000,
+ 0.803048, 0.690625,
+ 0.798945, 0.684375,
+ 0.796014, 0.680208,
+ 0.791911, 0.672917,
+ 0.789566, 0.667708,
+ 0.787222, 0.661458,
+ 0.783705, 0.656250,
+ 0.781360, 0.650000,
+ 0.777843, 0.643750,
+ 0.774912, 0.634375,
+ 0.773154, 0.628125,
+ 0.770809, 0.623958,
+ 0.766120, 0.617708,
+ 0.762603, 0.608333,
+ 0.759672, 0.602083,
+ 0.756741, 0.592708,
+ 0.754396, 0.588542,
+ 0.751465, 0.580208,
+ 0.749121, 0.575000,
+ 0.745604, 0.569792,
+ 0.742087, 0.562500,
+ 0.738570, 0.555208,
+ 0.735053, 0.550000,
+ 0.732122, 0.544792,
+ 0.728019, 0.536458,
+ 0.727433, 0.535417,
+ 0.727433, 0.535417,
+ 0.727433, 0.535417,
+ 0.727433, 0.535417,
+ 0.727433, 0.535417,
+ 0.726260, 0.533333,
+ 0.722743, 0.519792,
+ 0.720985, 0.512500,
+ 0.718640, 0.506250,
+ 0.713951, 0.496875,
+ 0.708089, 0.484375,
+ 0.699883, 0.470833,
+ 0.691676, 0.458333,
+ 0.684056, 0.445833,
+ 0.679953, 0.439583,
+ 0.677022, 0.435417,
+ 0.671747, 0.429167,
+ 0.665299, 0.427083,
+ 0.660610, 0.426042,
+ 0.658265, 0.426042,
+ 0.655334, 0.426042,
+ 0.650059, 0.426042,
+ 0.643611, 0.427083,
+ 0.640094, 0.428125,
+ 0.637163, 0.428125,
+ 0.636577, 0.428125,
+ 0.635404, 0.429167,
+ 0.633646, 0.430208,
+ 0.630129, 0.430208,
+ 0.628957, 0.428125,
+ 0.626612, 0.423958,
+ 0.623095, 0.417708,
+ 0.620750, 0.411458,
+ 0.618406, 0.403125,
+ 0.617819, 0.402083,
+ 0.617233, 0.395833,
+ 0.615475, 0.389583,
+ 0.615475, 0.389583,
+ 0.615475, 0.389583,
+ 0.615475, 0.389583,
+ 0.615475, 0.389583,
+ 0.615475, 0.384375,
+ 0.615475, 0.379167,
+ 0.615475, 0.377083,
+ 0.613716, 0.377083,
+ 0.613130, 0.377083,
+ 0.613130, 0.376042,
+ 0.610785, 0.369792,
+ 0.610199, 0.365625,
+ 0.609613, 0.363542,
+ 0.608441, 0.357292,
+ 0.606096, 0.351042,
+ 0.604338, 0.347917,
+ 0.604338, 0.345833,
+ 0.604338, 0.339583,
+ 0.604338, 0.337500,
+ 0.604924, 0.332292,
+ 0.605510, 0.331250,
+ 0.605510, 0.330208,
+ 0.605510, 0.330208,
+ 0.605510, 0.328125,
+ 0.605510, 0.327083,
+ 0.603751, 0.321875,
+ 0.600234, 0.317708,
+ 0.596717, 0.316667,
+ 0.594959, 0.316667,
+ 0.590856, 0.315625,
+ 0.586167, 0.315625,
+ 0.582649, 0.313542,
+ 0.579132, 0.312500,
+ 0.576202, 0.311458,
+ 0.574443, 0.310417,
+ 0.572098, 0.310417,
+ 0.568581, 0.309375,
+ 0.565064, 0.308333,
+ 0.563306, 0.307292,
+ 0.562720, 0.306250,
+ 0.560375, 0.300000,
+ 0.560375, 0.298958,
+ 0.560375, 0.293750,
+ 0.559789, 0.290625,
+ 0.559789, 0.287500,
+ 0.560375, 0.284375,
+ 0.560375, 0.283333,
+ 0.562134, 0.282292,
+ 0.562134, 0.282292,
+ 0.562134, 0.282292,
+ 0.562134, 0.282292,
+ 0.562134, 0.282292
+ ]
+]
\ No newline at end of file diff --git a/data/world/companies.json b/data/world/companies.json new file mode 100644 index 0000000..65dd232 --- /dev/null +++ b/data/world/companies.json @@ -0,0 +1,52 @@ +[{
+ "name": "Fruitosis",
+ "logo": "data/img/logo_fruitosis.png",
+ "products": [
+ "Bananas",
+ "Apples",
+ "Mangos",
+ "Kiwifruit",
+ "Kumquat",
+ "Lemon",
+ "Lime",
+ "Loganberry",
+ "Pineapple",
+ "Pineberry",
+ "Plumcot",
+ "Pomegranate",
+ "Durian",
+ "Egg Fruit",
+ "Elderberry"
+ ]
+ },
+ {
+ "name": "Chop Inc",
+ "logo": "data/img/logo_fruitosis.png",
+ "products": [
+ "Beech logs",
+ "Ash logs",
+ "Ginkgo logs",
+ "Honey Locust logs",
+ "Walnut logs",
+ "Alders logs",
+ "Snowy Mespils logs",
+ "Birches logs",
+ "Hornbeams logs"
+ ]
+ },
+ {
+ "name": "Chomed Co",
+ "logo": "data/img/logo_fruitosis.png",
+ "products": [
+ "Lisinopril",
+ "Atorvastatin",
+ "Levothyroxine",
+ "Metformin",
+ "Amlodipine",
+ "Metoprolol",
+ "Omeprazole",
+ "Simvastatin",
+ "Losartan"
+ ]
+ }
+]
\ No newline at end of file diff --git a/data/world/dealers.json b/data/world/dealers.json new file mode 100644 index 0000000..714972a --- /dev/null +++ b/data/world/dealers.json @@ -0,0 +1,79 @@ +[{
+ "name": "Mercedes-Benz",
+ "logo": "data/img/mercedes-logo.png",
+ "trucks": [{
+ "name": "Actros",
+ "power": 320,
+ "price": 110000,
+ "fuelcapacity": 600,
+ "torque": 1080,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ },
+ {
+ "name": "New Actros",
+ "power": 517,
+ "price": 220000,
+ "fuelcapacity": 960,
+ "torque": 1100,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ }
+ ]
+ },
+ {
+ "name": "Iveco",
+ "logo": "data/img/iveco-logo.png",
+ "trucks": [{
+ "name": "Stralis Active Space",
+ "power": 310,
+ "price": 90000,
+ "fuelcapacity": 1200,
+ "torque": 1340,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ },
+ {
+ "name": "Stralis Large Space",
+ "power": 310,
+ "price": 90000,
+ "fuelcapacity": 1200,
+ "torque": 1340,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ },
+ {
+ "name": "Stralis Hi-Way",
+ "power": 310,
+ "price": 155000,
+ "fuelcapacity": 1200,
+ "torque": 1400,
+ "logo": "data/img/iveco-stralis-hiway.png",
+ "fuelusage": 30.0
+ }
+ ]
+ },
+ {
+ "name": "Volvo",
+ "logo": "data/img/volvo-logo.png",
+ "trucks": [{
+ "name": "FH Sleeper",
+ "power": 420,
+ "price": 112000,
+ "fuelcapacity": 1400,
+ "torque": 1000,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ },
+ {
+ "name": "FH Globetrotter",
+ "power": 500,
+ "price": 170000,
+ "fuelcapacity": 800,
+ "torque": 1150,
+ "logo": "data/img/iveco-stralis-activespace.png",
+ "fuelusage": 30.0
+ }
+ ]
+ }
+]
\ No newline at end of file diff --git a/data/world/first-names.json b/data/world/first-names.json new file mode 100644 index 0000000..6f961a4 --- /dev/null +++ b/data/world/first-names.json @@ -0,0 +1,4948 @@ +[ + "Aaren", + "Aarika", + "Abagael", + "Abagail", + "Abbe", + "Abbey", + "Abbi", + "Abbie", + "Abby", + "Abbye", + "Abigael", + "Abigail", + "Abigale", + "Abra", + "Ada", + "Adah", + "Adaline", + "Adan", + "Adara", + "Adda", + "Addi", + "Addia", + "Addie", + "Addy", + "Adel", + "Adela", + "Adelaida", + "Adelaide", + "Adele", + "Adelheid", + "Adelice", + "Adelina", + "Adelind", + "Adeline", + "Adella", + "Adelle", + "Adena", + "Adey", + "Adi", + "Adiana", + "Adina", + "Adora", + "Adore", + "Adoree", + "Adorne", + "Adrea", + "Adria", + "Adriaens", + "Adrian", + "Adriana", + "Adriane", + "Adrianna", + "Adrianne", + "Adriena", + "Adrienne", + "Aeriel", + "Aeriela", + "Aeriell", + "Afton", + "Ag", + "Agace", + "Agata", + "Agatha", + "Agathe", + "Aggi", + "Aggie", + "Aggy", + "Agna", + "Agnella", + "Agnes", + "Agnese", + "Agnesse", + "Agneta", + "Agnola", + "Agretha", + "Aida", + "Aidan", + "Aigneis", + "Aila", + "Aile", + "Ailee", + "Aileen", + "Ailene", + "Ailey", + "Aili", + "Ailina", + "Ailis", + "Ailsun", + "Ailyn", + "Aime", + "Aimee", + "Aimil", + "Aindrea", + "Ainslee", + "Ainsley", + "Ainslie", + "Ajay", + "Alaine", + "Alameda", + "Alana", + "Alanah", + "Alane", + "Alanna", + "Alayne", + "Alberta", + "Albertina", + "Albertine", + "Albina", + "Alecia", + "Aleda", + "Aleece", + "Aleen", + "Alejandra", + "Alejandrina", + "Alena", + "Alene", + "Alessandra", + "Aleta", + "Alethea", + "Alex", + "Alexa", + "Alexandra", + "Alexandrina", + "Alexi", + "Alexia", + "Alexina", + "Alexine", + "Alexis", + "Alfi", + "Alfie", + "Alfreda", + "Alfy", + "Ali", + "Alia", + "Alica", + "Alice", + "Alicea", + "Alicia", + "Alida", + "Alidia", + "Alie", + "Alika", + "Alikee", + "Alina", + "Aline", + "Alis", + "Alisa", + "Alisha", + "Alison", + "Alissa", + "Alisun", + "Alix", + "Aliza", + "Alla", + "Alleen", + "Allegra", + "Allene", + "Alli", + "Allianora", + "Allie", + "Allina", + "Allis", + "Allison", + "Allissa", + "Allix", + "Allsun", + "Allx", + "Ally", + "Allyce", + "Allyn", + "Allys", + "Allyson", + "Alma", + "Almeda", + "Almeria", + "Almeta", + "Almira", + "Almire", + "Aloise", + "Aloisia", + "Aloysia", + "Alta", + "Althea", + "Alvera", + "Alverta", + "Alvina", + "Alvinia", + "Alvira", + "Alyce", + "Alyda", + "Alys", + "Alysa", + "Alyse", + "Alysia", + "Alyson", + "Alyss", + "Alyssa", + "Amabel", + "Amabelle", + "Amalea", + "Amalee", + "Amaleta", + "Amalia", + "Amalie", + "Amalita", + "Amalle", + "Amanda", + "Amandi", + "Amandie", + "Amandy", + "Amara", + "Amargo", + "Amata", + "Amber", + "Amberly", + "Ambur", + "Ame", + "Amelia", + "Amelie", + "Amelina", + "Ameline", + "Amelita", + "Ami", + "Amie", + "Amii", + "Amil", + "Amitie", + "Amity", + "Ammamaria", + "Amy", + "Amye", + "Ana", + "Anabal", + "Anabel", + "Anabella", + "Anabelle", + "Analiese", + "Analise", + "Anallese", + "Anallise", + "Anastasia", + "Anastasie", + "Anastassia", + "Anatola", + "Andee", + "Andeee", + "Anderea", + "Andi", + "Andie", + "Andra", + "Andrea", + "Andreana", + "Andree", + "Andrei", + "Andria", + "Andriana", + "Andriette", + "Andromache", + "Andy", + "Anestassia", + "Anet", + "Anett", + "Anetta", + "Anette", + "Ange", + "Angel", + "Angela", + "Angele", + "Angelia", + "Angelica", + "Angelika", + "Angelina", + "Angeline", + "Angelique", + "Angelita", + "Angelle", + "Angie", + "Angil", + "Angy", + "Ania", + "Anica", + "Anissa", + "Anita", + "Anitra", + "Anjanette", + "Anjela", + "Ann", + "Ann-Marie", + "Anna", + "Anna-Diana", + "Anna-Diane", + "Anna-Maria", + "Annabal", + "Annabel", + "Annabela", + "Annabell", + "Annabella", + "Annabelle", + "Annadiana", + "Annadiane", + "Annalee", + "Annaliese", + "Annalise", + "Annamaria", + "Annamarie", + "Anne", + "Anne-Corinne", + "Anne-Marie", + "Annecorinne", + "Anneliese", + "Annelise", + "Annemarie", + "Annetta", + "Annette", + "Anni", + "Annice", + "Annie", + "Annis", + "Annissa", + "Annmaria", + "Annmarie", + "Annnora", + "Annora", + "Anny", + "Anselma", + "Ansley", + "Anstice", + "Anthe", + "Anthea", + "Anthia", + "Anthiathia", + "Antoinette", + "Antonella", + "Antonetta", + "Antonia", + "Antonie", + "Antonietta", + "Antonina", + "Anya", + "Appolonia", + "April", + "Aprilette", + "Ara", + "Arabel", + "Arabela", + "Arabele", + "Arabella", + "Arabelle", + "Arda", + "Ardath", + "Ardeen", + "Ardelia", + "Ardelis", + "Ardella", + "Ardelle", + "Arden", + "Ardene", + "Ardenia", + "Ardine", + "Ardis", + "Ardisj", + "Ardith", + "Ardra", + "Ardyce", + "Ardys", + "Ardyth", + "Aretha", + "Ariadne", + "Ariana", + "Aridatha", + "Ariel", + "Ariela", + "Ariella", + "Arielle", + "Arlana", + "Arlee", + "Arleen", + "Arlen", + "Arlena", + "Arlene", + "Arleta", + "Arlette", + "Arleyne", + "Arlie", + "Arliene", + "Arlina", + "Arlinda", + "Arline", + "Arluene", + "Arly", + "Arlyn", + "Arlyne", + "Aryn", + "Ashely", + "Ashia", + "Ashien", + "Ashil", + "Ashla", + "Ashlan", + "Ashlee", + "Ashleigh", + "Ashlen", + "Ashley", + "Ashli", + "Ashlie", + "Ashly", + "Asia", + "Astra", + "Astrid", + "Astrix", + "Atalanta", + "Athena", + "Athene", + "Atlanta", + "Atlante", + "Auberta", + "Aubine", + "Aubree", + "Aubrette", + "Aubrey", + "Aubrie", + "Aubry", + "Audi", + "Audie", + "Audra", + "Audre", + "Audrey", + "Audrie", + "Audry", + "Audrye", + "Audy", + "Augusta", + "Auguste", + "Augustina", + "Augustine", + "Aundrea", + "Aura", + "Aurea", + "Aurel", + "Aurelea", + "Aurelia", + "Aurelie", + "Auria", + "Aurie", + "Aurilia", + "Aurlie", + "Auroora", + "Aurora", + "Aurore", + "Austin", + "Austina", + "Austine", + "Ava", + "Aveline", + "Averil", + "Averyl", + "Avie", + "Avis", + "Aviva", + "Avivah", + "Avril", + "Avrit", + "Ayn", + "Bab", + "Babara", + "Babb", + "Babbette", + "Babbie", + "Babette", + "Babita", + "Babs", + "Bambi", + "Bambie", + "Bamby", + "Barb", + "Barbabra", + "Barbara", + "Barbara-Anne", + "Barbaraanne", + "Barbe", + "Barbee", + "Barbette", + "Barbey", + "Barbi", + "Barbie", + "Barbra", + "Barby", + "Bari", + "Barrie", + "Barry", + "Basia", + "Bathsheba", + "Batsheva", + "Bea", + "Beatrice", + "Beatrisa", + "Beatrix", + "Beatriz", + "Bebe", + "Becca", + "Becka", + "Becki", + "Beckie", + "Becky", + "Bee", + "Beilul", + "Beitris", + "Bekki", + "Bel", + "Belia", + "Belicia", + "Belinda", + "Belita", + "Bell", + "Bella", + "Bellanca", + "Belle", + "Bellina", + "Belva", + "Belvia", + "Bendite", + "Benedetta", + "Benedicta", + "Benedikta", + "Benetta", + "Benita", + "Benni", + "Bennie", + "Benny", + "Benoite", + "Berenice", + "Beret", + "Berget", + "Berna", + "Bernadene", + "Bernadette", + "Bernadina", + "Bernadine", + "Bernardina", + "Bernardine", + "Bernelle", + "Bernete", + "Bernetta", + "Bernette", + "Berni", + "Bernice", + "Bernie", + "Bernita", + "Berny", + "Berri", + "Berrie", + "Berry", + "Bert", + "Berta", + "Berte", + "Bertha", + "Berthe", + "Berti", + "Bertie", + "Bertina", + "Bertine", + "Berty", + "Beryl", + "Beryle", + "Bess", + "Bessie", + "Bessy", + "Beth", + "Bethanne", + "Bethany", + "Bethena", + "Bethina", + "Betsey", + "Betsy", + "Betta", + "Bette", + "Bette-Ann", + "Betteann", + "Betteanne", + "Betti", + "Bettina", + "Bettine", + "Betty", + "Bettye", + "Beulah", + "Bev", + "Beverie", + "Beverlee", + "Beverley", + "Beverlie", + "Beverly", + "Bevvy", + "Bianca", + "Bianka", + "Bibbie", + "Bibby", + "Bibbye", + "Bibi", + "Biddie", + "Biddy", + "Bidget", + "Bili", + "Bill", + "Billi", + "Billie", + "Billy", + "Billye", + "Binni", + "Binnie", + "Binny", + "Bird", + "Birdie", + "Birgit", + "Birgitta", + "Blair", + "Blaire", + "Blake", + "Blakelee", + "Blakeley", + "Blanca", + "Blanch", + "Blancha", + "Blanche", + "Blinni", + "Blinnie", + "Blinny", + "Bliss", + "Blisse", + "Blithe", + "Blondell", + "Blondelle", + "Blondie", + "Blondy", + "Blythe", + "Bobbe", + "Bobbee", + "Bobbette", + "Bobbi", + "Bobbie", + "Bobby", + "Bobbye", + "Bobette", + "Bobina", + "Bobine", + "Bobinette", + "Bonita", + "Bonnee", + "Bonni", + "Bonnibelle", + "Bonnie", + "Bonny", + "Brana", + "Brandais", + "Brande", + "Brandea", + "Brandi", + "Brandice", + "Brandie", + "Brandise", + "Brandy", + "Breanne", + "Brear", + "Bree", + "Breena", + "Bren", + "Brena", + "Brenda", + "Brenn", + "Brenna", + "Brett", + "Bria", + "Briana", + "Brianna", + "Brianne", + "Bride", + "Bridget", + "Bridgette", + "Bridie", + "Brier", + "Brietta", + "Brigid", + "Brigida", + "Brigit", + "Brigitta", + "Brigitte", + "Brina", + "Briney", + "Brinn", + "Brinna", + "Briny", + "Brit", + "Brita", + "Britney", + "Britni", + "Britt", + "Britta", + "Brittan", + "Brittaney", + "Brittani", + "Brittany", + "Britte", + "Britteny", + "Brittne", + "Brittney", + "Brittni", + "Brook", + "Brooke", + "Brooks", + "Brunhilda", + "Brunhilde", + "Bryana", + "Bryn", + "Bryna", + "Brynn", + "Brynna", + "Brynne", + "Buffy", + "Bunni", + "Bunnie", + "Bunny", + "Cacilia", + "Cacilie", + "Cahra", + "Cairistiona", + "Caitlin", + "Caitrin", + "Cal", + "Calida", + "Calla", + "Calley", + "Calli", + "Callida", + "Callie", + "Cally", + "Calypso", + "Cam", + "Camala", + "Camel", + "Camella", + "Camellia", + "Cami", + "Camila", + "Camile", + "Camilla", + "Camille", + "Cammi", + "Cammie", + "Cammy", + "Candace", + "Candi", + "Candice", + "Candida", + "Candide", + "Candie", + "Candis", + "Candra", + "Candy", + "Caprice", + "Cara", + "Caralie", + "Caren", + "Carena", + "Caresa", + "Caressa", + "Caresse", + "Carey", + "Cari", + "Caria", + "Carie", + "Caril", + "Carilyn", + "Carin", + "Carina", + "Carine", + "Cariotta", + "Carissa", + "Carita", + "Caritta", + "Carla", + "Carlee", + "Carleen", + "Carlen", + "Carlene", + "Carley", + "Carlie", + "Carlin", + "Carlina", + "Carline", + "Carlita", + "Carlota", + "Carlotta", + "Carly", + "Carlye", + "Carlyn", + "Carlynn", + "Carlynne", + "Carma", + "Carmel", + "Carmela", + "Carmelia", + "Carmelina", + "Carmelita", + "Carmella", + "Carmelle", + "Carmen", + "Carmencita", + "Carmina", + "Carmine", + "Carmita", + "Carmon", + "Caro", + "Carol", + "Carol-Jean", + "Carola", + "Carolan", + "Carolann", + "Carole", + "Carolee", + "Carolin", + "Carolina", + "Caroline", + "Caroljean", + "Carolyn", + "Carolyne", + "Carolynn", + "Caron", + "Carree", + "Carri", + "Carrie", + "Carrissa", + "Carroll", + "Carry", + "Cary", + "Caryl", + "Caryn", + "Casandra", + "Casey", + "Casi", + "Casie", + "Cass", + "Cassandra", + "Cassandre", + "Cassandry", + "Cassaundra", + "Cassey", + "Cassi", + "Cassie", + "Cassondra", + "Cassy", + "Catarina", + "Cate", + "Caterina", + "Catha", + "Catharina", + "Catharine", + "Cathe", + "Cathee", + "Catherin", + "Catherina", + "Catherine", + "Cathi", + "Cathie", + "Cathleen", + "Cathlene", + "Cathrin", + "Cathrine", + "Cathryn", + "Cathy", + "Cathyleen", + "Cati", + "Catie", + "Catina", + "Catlaina", + "Catlee", + "Catlin", + "Catrina", + "Catriona", + "Caty", + "Caye", + "Cayla", + "Cecelia", + "Cecil", + "Cecile", + "Ceciley", + "Cecilia", + "Cecilla", + "Cecily", + "Ceil", + "Cele", + "Celene", + "Celesta", + "Celeste", + "Celestia", + "Celestina", + "Celestine", + "Celestyn", + "Celestyna", + "Celia", + "Celie", + "Celina", + "Celinda", + "Celine", + "Celinka", + "Celisse", + "Celka", + "Celle", + "Cesya", + "Chad", + "Chanda", + "Chandal", + "Chandra", + "Channa", + "Chantal", + "Chantalle", + "Charil", + "Charin", + "Charis", + "Charissa", + "Charisse", + "Charita", + "Charity", + "Charla", + "Charlean", + "Charleen", + "Charlena", + "Charlene", + "Charline", + "Charlot", + "Charlotta", + "Charlotte", + "Charmain", + "Charmaine", + "Charmane", + "Charmian", + "Charmine", + "Charmion", + "Charo", + "Charyl", + "Chastity", + "Chelsae", + "Chelsea", + "Chelsey", + "Chelsie", + "Chelsy", + "Cher", + "Chere", + "Cherey", + "Cheri", + "Cherianne", + "Cherice", + "Cherida", + "Cherie", + "Cherilyn", + "Cherilynn", + "Cherin", + "Cherise", + "Cherish", + "Cherlyn", + "Cherri", + "Cherrita", + "Cherry", + "Chery", + "Cherye", + "Cheryl", + "Cheslie", + "Chiarra", + "Chickie", + "Chicky", + "Chiquia", + "Chiquita", + "Chlo", + "Chloe", + "Chloette", + "Chloris", + "Chris", + "Chrissie", + "Chrissy", + "Christa", + "Christabel", + "Christabella", + "Christal", + "Christalle", + "Christan", + "Christean", + "Christel", + "Christen", + "Christi", + "Christian", + "Christiana", + "Christiane", + "Christie", + "Christin", + "Christina", + "Christine", + "Christy", + "Christye", + "Christyna", + "Chrysa", + "Chrysler", + "Chrystal", + "Chryste", + "Chrystel", + "Cicely", + "Cicily", + "Ciel", + "Cilka", + "Cinda", + "Cindee", + "Cindelyn", + "Cinderella", + "Cindi", + "Cindie", + "Cindra", + "Cindy", + "Cinnamon", + "Cissiee", + "Cissy", + "Clair", + "Claire", + "Clara", + "Clarabelle", + "Clare", + "Claresta", + "Clareta", + "Claretta", + "Clarette", + "Clarey", + "Clari", + "Claribel", + "Clarice", + "Clarie", + "Clarinda", + "Clarine", + "Clarissa", + "Clarisse", + "Clarita", + "Clary", + "Claude", + "Claudelle", + "Claudetta", + "Claudette", + "Claudia", + "Claudie", + "Claudina", + "Claudine", + "Clea", + "Clem", + "Clemence", + "Clementia", + "Clementina", + "Clementine", + "Clemmie", + "Clemmy", + "Cleo", + "Cleopatra", + "Clerissa", + "Clio", + "Clo", + "Cloe", + "Cloris", + "Clotilda", + "Clovis", + "Codee", + "Codi", + "Codie", + "Cody", + "Coleen", + "Colene", + "Coletta", + "Colette", + "Colleen", + "Collen", + "Collete", + "Collette", + "Collie", + "Colline", + "Colly", + "Con", + "Concettina", + "Conchita", + "Concordia", + "Conni", + "Connie", + "Conny", + "Consolata", + "Constance", + "Constancia", + "Constancy", + "Constanta", + "Constantia", + "Constantina", + "Constantine", + "Consuela", + "Consuelo", + "Cookie", + "Cora", + "Corabel", + "Corabella", + "Corabelle", + "Coral", + "Coralie", + "Coraline", + "Coralyn", + "Cordelia", + "Cordelie", + "Cordey", + "Cordi", + "Cordie", + "Cordula", + "Cordy", + "Coreen", + "Corella", + "Corenda", + "Corene", + "Coretta", + "Corette", + "Corey", + "Cori", + "Corie", + "Corilla", + "Corina", + "Corine", + "Corinna", + "Corinne", + "Coriss", + "Corissa", + "Corliss", + "Corly", + "Cornela", + "Cornelia", + "Cornelle", + "Cornie", + "Corny", + "Correna", + "Correy", + "Corri", + "Corrianne", + "Corrie", + "Corrina", + "Corrine", + "Corrinne", + "Corry", + "Cortney", + "Cory", + "Cosetta", + "Cosette", + "Costanza", + "Courtenay", + "Courtnay", + "Courtney", + "Crin", + "Cris", + "Crissie", + "Crissy", + "Crista", + "Cristabel", + "Cristal", + "Cristen", + "Cristi", + "Cristie", + "Cristin", + "Cristina", + "Cristine", + "Cristionna", + "Cristy", + "Crysta", + "Crystal", + "Crystie", + "Cthrine", + "Cyb", + "Cybil", + "Cybill", + "Cymbre", + "Cynde", + "Cyndi", + "Cyndia", + "Cyndie", + "Cyndy", + "Cynthea", + "Cynthia", + "Cynthie", + "Cynthy", + "Dacey", + "Dacia", + "Dacie", + "Dacy", + "Dael", + "Daffi", + "Daffie", + "Daffy", + "Dagmar", + "Dahlia", + "Daile", + "Daisey", + "Daisi", + "Daisie", + "Daisy", + "Dale", + "Dalenna", + "Dalia", + "Dalila", + "Dallas", + "Daloris", + "Damara", + "Damaris", + "Damita", + "Dana", + "Danell", + "Danella", + "Danette", + "Dani", + "Dania", + "Danica", + "Danice", + "Daniela", + "Daniele", + "Daniella", + "Danielle", + "Danika", + "Danila", + "Danit", + "Danita", + "Danna", + "Danni", + "Dannie", + "Danny", + "Dannye", + "Danya", + "Danyelle", + "Danyette", + "Daphene", + "Daphna", + "Daphne", + "Dara", + "Darb", + "Darbie", + "Darby", + "Darcee", + "Darcey", + "Darci", + "Darcie", + "Darcy", + "Darda", + "Dareen", + "Darell", + "Darelle", + "Dari", + "Daria", + "Darice", + "Darla", + "Darleen", + "Darlene", + "Darline", + "Darlleen", + "Daron", + "Darrelle", + "Darryl", + "Darsey", + "Darsie", + "Darya", + "Daryl", + "Daryn", + "Dasha", + "Dasi", + "Dasie", + "Dasya", + "Datha", + "Daune", + "Daveen", + "Daveta", + "Davida", + "Davina", + "Davine", + "Davita", + "Dawn", + "Dawna", + "Dayle", + "Dayna", + "Ddene", + "De", + "Deana", + "Deane", + "Deanna", + "Deanne", + "Deb", + "Debbi", + "Debbie", + "Debby", + "Debee", + "Debera", + "Debi", + "Debor", + "Debora", + "Deborah", + "Debra", + "Dede", + "Dedie", + "Dedra", + "Dee", + "Dee Dee", + "Deeann", + "Deeanne", + "Deedee", + "Deena", + "Deerdre", + "Deeyn", + "Dehlia", + "Deidre", + "Deina", + "Deirdre", + "Del", + "Dela", + "Delcina", + "Delcine", + "Delia", + "Delila", + "Delilah", + "Delinda", + "Dell", + "Della", + "Delly", + "Delora", + "Delores", + "Deloria", + "Deloris", + "Delphine", + "Delphinia", + "Demeter", + "Demetra", + "Demetria", + "Demetris", + "Dena", + "Deni", + "Denice", + "Denise", + "Denna", + "Denni", + "Dennie", + "Denny", + "Deny", + "Denys", + "Denyse", + "Deonne", + "Desdemona", + "Desirae", + "Desiree", + "Desiri", + "Deva", + "Devan", + "Devi", + "Devin", + "Devina", + "Devinne", + "Devon", + "Devondra", + "Devonna", + "Devonne", + "Devora", + "Di", + "Diahann", + "Dian", + "Diana", + "Diandra", + "Diane", + "Diane-Marie", + "Dianemarie", + "Diann", + "Dianna", + "Dianne", + "Diannne", + "Didi", + "Dido", + "Diena", + "Dierdre", + "Dina", + "Dinah", + "Dinnie", + "Dinny", + "Dion", + "Dione", + "Dionis", + "Dionne", + "Dita", + "Dix", + "Dixie", + "Dniren", + "Dode", + "Dodi", + "Dodie", + "Dody", + "Doe", + "Doll", + "Dolley", + "Dolli", + "Dollie", + "Dolly", + "Dolores", + "Dolorita", + "Doloritas", + "Domeniga", + "Dominga", + "Domini", + "Dominica", + "Dominique", + "Dona", + "Donella", + "Donelle", + "Donetta", + "Donia", + "Donica", + "Donielle", + "Donna", + "Donnamarie", + "Donni", + "Donnie", + "Donny", + "Dora", + "Doralia", + "Doralin", + "Doralyn", + "Doralynn", + "Doralynne", + "Dore", + "Doreen", + "Dorelia", + "Dorella", + "Dorelle", + "Dorena", + "Dorene", + "Doretta", + "Dorette", + "Dorey", + "Dori", + "Doria", + "Dorian", + "Dorice", + "Dorie", + "Dorine", + "Doris", + "Dorisa", + "Dorise", + "Dorita", + "Doro", + "Dorolice", + "Dorolisa", + "Dorotea", + "Doroteya", + "Dorothea", + "Dorothee", + "Dorothy", + "Dorree", + "Dorri", + "Dorrie", + "Dorris", + "Dorry", + "Dorthea", + "Dorthy", + "Dory", + "Dosi", + "Dot", + "Doti", + "Dotti", + "Dottie", + "Dotty", + "Dre", + "Dreddy", + "Dredi", + "Drona", + "Dru", + "Druci", + "Drucie", + "Drucill", + "Drucy", + "Drusi", + "Drusie", + "Drusilla", + "Drusy", + "Dulce", + "Dulcea", + "Dulci", + "Dulcia", + "Dulciana", + "Dulcie", + "Dulcine", + "Dulcinea", + "Dulcy", + "Dulsea", + "Dusty", + "Dyan", + "Dyana", + "Dyane", + "Dyann", + "Dyanna", + "Dyanne", + "Dyna", + "Dynah", + "Eachelle", + "Eada", + "Eadie", + "Eadith", + "Ealasaid", + "Eartha", + "Easter", + "Eba", + "Ebba", + "Ebonee", + "Ebony", + "Eda", + "Eddi", + "Eddie", + "Eddy", + "Ede", + "Edee", + "Edeline", + "Eden", + "Edi", + "Edie", + "Edin", + "Edita", + "Edith", + "Editha", + "Edithe", + "Ediva", + "Edna", + "Edwina", + "Edy", + "Edyth", + "Edythe", + "Effie", + "Eileen", + "Eilis", + "Eimile", + "Eirena", + "Ekaterina", + "Elaina", + "Elaine", + "Elana", + "Elane", + "Elayne", + "Elberta", + "Elbertina", + "Elbertine", + "Eleanor", + "Eleanora", + "Eleanore", + "Electra", + "Eleen", + "Elena", + "Elene", + "Eleni", + "Elenore", + "Eleonora", + "Eleonore", + "Elfie", + "Elfreda", + "Elfrida", + "Elfrieda", + "Elga", + "Elianora", + "Elianore", + "Elicia", + "Elie", + "Elinor", + "Elinore", + "Elisa", + "Elisabet", + "Elisabeth", + "Elisabetta", + "Elise", + "Elisha", + "Elissa", + "Elita", + "Eliza", + "Elizabet", + "Elizabeth", + "Elka", + "Elke", + "Ella", + "Elladine", + "Elle", + "Ellen", + "Ellene", + "Ellette", + "Elli", + "Ellie", + "Ellissa", + "Elly", + "Ellyn", + "Ellynn", + "Elmira", + "Elna", + "Elnora", + "Elnore", + "Eloisa", + "Eloise", + "Elonore", + "Elora", + "Elsa", + "Elsbeth", + "Else", + "Elset", + "Elsey", + "Elsi", + "Elsie", + "Elsinore", + "Elspeth", + "Elsy", + "Elva", + "Elvera", + "Elvina", + "Elvira", + "Elwira", + "Elyn", + "Elyse", + "Elysee", + "Elysha", + "Elysia", + "Elyssa", + "Em", + "Ema", + "Emalee", + "Emalia", + "Emelda", + "Emelia", + "Emelina", + "Emeline", + "Emelita", + "Emelyne", + "Emera", + "Emilee", + "Emili", + "Emilia", + "Emilie", + "Emiline", + "Emily", + "Emlyn", + "Emlynn", + "Emlynne", + "Emma", + "Emmalee", + "Emmaline", + "Emmalyn", + "Emmalynn", + "Emmalynne", + "Emmeline", + "Emmey", + "Emmi", + "Emmie", + "Emmy", + "Emmye", + "Emogene", + "Emyle", + "Emylee", + "Engracia", + "Enid", + "Enrica", + "Enrichetta", + "Enrika", + "Enriqueta", + "Eolanda", + "Eolande", + "Eran", + "Erda", + "Erena", + "Erica", + "Ericha", + "Ericka", + "Erika", + "Erin", + "Erina", + "Erinn", + "Erinna", + "Erma", + "Ermengarde", + "Ermentrude", + "Ermina", + "Erminia", + "Erminie", + "Erna", + "Ernaline", + "Ernesta", + "Ernestine", + "Ertha", + "Eryn", + "Esma", + "Esmaria", + "Esme", + "Esmeralda", + "Essa", + "Essie", + "Essy", + "Esta", + "Estel", + "Estele", + "Estell", + "Estella", + "Estelle", + "Ester", + "Esther", + "Estrella", + "Estrellita", + "Ethel", + "Ethelda", + "Ethelin", + "Ethelind", + "Etheline", + "Ethelyn", + "Ethyl", + "Etta", + "Etti", + "Ettie", + "Etty", + "Eudora", + "Eugenia", + "Eugenie", + "Eugine", + "Eula", + "Eulalie", + "Eunice", + "Euphemia", + "Eustacia", + "Eva", + "Evaleen", + "Evangelia", + "Evangelin", + "Evangelina", + "Evangeline", + "Evania", + "Evanne", + "Eve", + "Eveleen", + "Evelina", + "Eveline", + "Evelyn", + "Evey", + "Evie", + "Evita", + "Evonne", + "Evvie", + "Evvy", + "Evy", + "Eyde", + "Eydie", + "Ezmeralda", + "Fae", + "Faina", + "Faith", + "Fallon", + "Fan", + "Fanchette", + "Fanchon", + "Fancie", + "Fancy", + "Fanechka", + "Fania", + "Fanni", + "Fannie", + "Fanny", + "Fanya", + "Fara", + "Farah", + "Farand", + "Farica", + "Farra", + "Farrah", + "Farrand", + "Faun", + "Faunie", + "Faustina", + "Faustine", + "Fawn", + "Fawne", + "Fawnia", + "Fay", + "Faydra", + "Faye", + "Fayette", + "Fayina", + "Fayre", + "Fayth", + "Faythe", + "Federica", + "Fedora", + "Felecia", + "Felicdad", + "Felice", + "Felicia", + "Felicity", + "Felicle", + "Felipa", + "Felisha", + "Felita", + "Feliza", + "Fenelia", + "Feodora", + "Ferdinanda", + "Ferdinande", + "Fern", + "Fernanda", + "Fernande", + "Fernandina", + "Ferne", + "Fey", + "Fiann", + "Fianna", + "Fidela", + "Fidelia", + "Fidelity", + "Fifi", + "Fifine", + "Filia", + "Filide", + "Filippa", + "Fina", + "Fiona", + "Fionna", + "Fionnula", + "Fiorenze", + "Fleur", + "Fleurette", + "Flo", + "Flor", + "Flora", + "Florance", + "Flore", + "Florella", + "Florence", + "Florencia", + "Florentia", + "Florenza", + "Florette", + "Flori", + "Floria", + "Florida", + "Florie", + "Florina", + "Florinda", + "Floris", + "Florri", + "Florrie", + "Florry", + "Flory", + "Flossi", + "Flossie", + "Flossy", + "Flss", + "Fran", + "Francene", + "Frances", + "Francesca", + "Francine", + "Francisca", + "Franciska", + "Francoise", + "Francyne", + "Frank", + "Frankie", + "Franky", + "Franni", + "Frannie", + "Franny", + "Frayda", + "Fred", + "Freda", + "Freddi", + "Freddie", + "Freddy", + "Fredelia", + "Frederica", + "Fredericka", + "Frederique", + "Fredi", + "Fredia", + "Fredra", + "Fredrika", + "Freida", + "Frieda", + "Friederike", + "Fulvia", + "Gabbey", + "Gabbi", + "Gabbie", + "Gabey", + "Gabi", + "Gabie", + "Gabriel", + "Gabriela", + "Gabriell", + "Gabriella", + "Gabrielle", + "Gabriellia", + "Gabrila", + "Gaby", + "Gae", + "Gael", + "Gail", + "Gale", + "Gale", + "Galina", + "Garland", + "Garnet", + "Garnette", + "Gates", + "Gavra", + "Gavrielle", + "Gay", + "Gaye", + "Gayel", + "Gayla", + "Gayle", + "Gayleen", + "Gaylene", + "Gaynor", + "Gelya", + "Gena", + "Gene", + "Geneva", + "Genevieve", + "Genevra", + "Genia", + "Genna", + "Genni", + "Gennie", + "Gennifer", + "Genny", + "Genovera", + "Genvieve", + "George", + "Georgeanna", + "Georgeanne", + "Georgena", + "Georgeta", + "Georgetta", + "Georgette", + "Georgia", + "Georgiana", + "Georgianna", + "Georgianne", + "Georgie", + "Georgina", + "Georgine", + "Geralda", + "Geraldine", + "Gerda", + "Gerhardine", + "Geri", + "Gerianna", + "Gerianne", + "Gerladina", + "Germain", + "Germaine", + "Germana", + "Gerri", + "Gerrie", + "Gerrilee", + "Gerry", + "Gert", + "Gerta", + "Gerti", + "Gertie", + "Gertrud", + "Gertruda", + "Gertrude", + "Gertrudis", + "Gerty", + "Giacinta", + "Giana", + "Gianina", + "Gianna", + "Gigi", + "Gilberta", + "Gilberte", + "Gilbertina", + "Gilbertine", + "Gilda", + "Gilemette", + "Gill", + "Gillan", + "Gilli", + "Gillian", + "Gillie", + "Gilligan", + "Gilly", + "Gina", + "Ginelle", + "Ginevra", + "Ginger", + "Ginni", + "Ginnie", + "Ginnifer", + "Ginny", + "Giorgia", + "Giovanna", + "Gipsy", + "Giralda", + "Gisela", + "Gisele", + "Gisella", + "Giselle", + "Giuditta", + "Giulia", + "Giulietta", + "Giustina", + "Gizela", + "Glad", + "Gladi", + "Gladys", + "Gleda", + "Glen", + "Glenda", + "Glenine", + "Glenn", + "Glenna", + "Glennie", + "Glennis", + "Glori", + "Gloria", + "Gloriana", + "Gloriane", + "Glory", + "Glyn", + "Glynda", + "Glynis", + "Glynnis", + "Gnni", + "Godiva", + "Golda", + "Goldarina", + "Goldi", + "Goldia", + "Goldie", + "Goldina", + "Goldy", + "Grace", + "Gracia", + "Gracie", + "Grata", + "Gratia", + "Gratiana", + "Gray", + "Grayce", + "Grazia", + "Greer", + "Greta", + "Gretal", + "Gretchen", + "Grete", + "Gretel", + "Grethel", + "Gretna", + "Gretta", + "Grier", + "Griselda", + "Grissel", + "Guendolen", + "Guenevere", + "Guenna", + "Guglielma", + "Gui", + "Guillema", + "Guillemette", + "Guinevere", + "Guinna", + "Gunilla", + "Gus", + "Gusella", + "Gussi", + "Gussie", + "Gussy", + "Gusta", + "Gusti", + "Gustie", + "Gusty", + "Gwen", + "Gwendolen", + "Gwendolin", + "Gwendolyn", + "Gweneth", + "Gwenette", + "Gwenneth", + "Gwenni", + "Gwennie", + "Gwenny", + "Gwenora", + "Gwenore", + "Gwyn", + "Gwyneth", + "Gwynne", + "Gypsy", + "Hadria", + "Hailee", + "Haily", + "Haleigh", + "Halette", + "Haley", + "Hali", + "Halie", + "Halimeda", + "Halley", + "Halli", + "Hallie", + "Hally", + "Hana", + "Hanna", + "Hannah", + "Hanni", + "Hannie", + "Hannis", + "Hanny", + "Happy", + "Harlene", + "Harley", + "Harli", + "Harlie", + "Harmonia", + "Harmonie", + "Harmony", + "Harri", + "Harrie", + "Harriet", + "Harriett", + "Harrietta", + "Harriette", + "Harriot", + "Harriott", + "Hatti", + "Hattie", + "Hatty", + "Hayley", + "Hazel", + "Heath", + "Heather", + "Heda", + "Hedda", + "Heddi", + "Heddie", + "Hedi", + "Hedvig", + "Hedvige", + "Hedwig", + "Hedwiga", + "Hedy", + "Heida", + "Heidi", + "Heidie", + "Helaina", + "Helaine", + "Helen", + "Helen-Elizabeth", + "Helena", + "Helene", + "Helenka", + "Helga", + "Helge", + "Helli", + "Heloise", + "Helsa", + "Helyn", + "Hendrika", + "Henka", + "Henrie", + "Henrieta", + "Henrietta", + "Henriette", + "Henryetta", + "Hephzibah", + "Hermia", + "Hermina", + "Hermine", + "Herminia", + "Hermione", + "Herta", + "Hertha", + "Hester", + "Hesther", + "Hestia", + "Hetti", + "Hettie", + "Hetty", + "Hilary", + "Hilda", + "Hildagard", + "Hildagarde", + "Hilde", + "Hildegaard", + "Hildegarde", + "Hildy", + "Hillary", + "Hilliary", + "Hinda", + "Holli", + "Hollie", + "Holly", + "Holly-Anne", + "Hollyanne", + "Honey", + "Honor", + "Honoria", + "Hope", + "Horatia", + "Hortense", + "Hortensia", + "Hulda", + "Hyacinth", + "Hyacintha", + "Hyacinthe", + "Hyacinthia", + "Hyacinthie", + "Hynda", + "Ianthe", + "Ibbie", + "Ibby", + "Ida", + "Idalia", + "Idalina", + "Idaline", + "Idell", + "Idelle", + "Idette", + "Ileana", + "Ileane", + "Ilene", + "Ilise", + "Ilka", + "Illa", + "Ilsa", + "Ilse", + "Ilysa", + "Ilyse", + "Ilyssa", + "Imelda", + "Imogen", + "Imogene", + "Imojean", + "Ina", + "Indira", + "Ines", + "Inesita", + "Inessa", + "Inez", + "Inga", + "Ingaberg", + "Ingaborg", + "Inge", + "Ingeberg", + "Ingeborg", + "Inger", + "Ingrid", + "Ingunna", + "Inna", + "Iolande", + "Iolanthe", + "Iona", + "Iormina", + "Ira", + "Irena", + "Irene", + "Irina", + "Iris", + "Irita", + "Irma", + "Isa", + "Isabel", + "Isabelita", + "Isabella", + "Isabelle", + "Isadora", + "Isahella", + "Iseabal", + "Isidora", + "Isis", + "Isobel", + "Issi", + "Issie", + "Issy", + "Ivett", + "Ivette", + "Ivie", + "Ivonne", + "Ivory", + "Ivy", + "Izabel", + "Jacenta", + "Jacinda", + "Jacinta", + "Jacintha", + "Jacinthe", + "Jackelyn", + "Jacki", + "Jackie", + "Jacklin", + "Jacklyn", + "Jackquelin", + "Jackqueline", + "Jacky", + "Jaclin", + "Jaclyn", + "Jacquelin", + "Jacqueline", + "Jacquelyn", + "Jacquelynn", + "Jacquenetta", + "Jacquenette", + "Jacquetta", + "Jacquette", + "Jacqui", + "Jacquie", + "Jacynth", + "Jada", + "Jade", + "Jaime", + "Jaimie", + "Jaine", + "Jami", + "Jamie", + "Jamima", + "Jammie", + "Jan", + "Jana", + "Janaya", + "Janaye", + "Jandy", + "Jane", + "Janean", + "Janeczka", + "Janeen", + "Janel", + "Janela", + "Janella", + "Janelle", + "Janene", + "Janenna", + "Janessa", + "Janet", + "Janeta", + "Janetta", + "Janette", + "Janeva", + "Janey", + "Jania", + "Janice", + "Janie", + "Janifer", + "Janina", + "Janine", + "Janis", + "Janith", + "Janka", + "Janna", + "Jannel", + "Jannelle", + "Janot", + "Jany", + "Jaquelin", + "Jaquelyn", + "Jaquenetta", + "Jaquenette", + "Jaquith", + "Jasmin", + "Jasmina", + "Jasmine", + "Jayme", + "Jaymee", + "Jayne", + "Jaynell", + "Jazmin", + "Jean", + "Jeana", + "Jeane", + "Jeanelle", + "Jeanette", + "Jeanie", + "Jeanine", + "Jeanna", + "Jeanne", + "Jeannette", + "Jeannie", + "Jeannine", + "Jehanna", + "Jelene", + "Jemie", + "Jemima", + "Jemimah", + "Jemmie", + "Jemmy", + "Jen", + "Jena", + "Jenda", + "Jenelle", + "Jeni", + "Jenica", + "Jeniece", + "Jenifer", + "Jeniffer", + "Jenilee", + "Jenine", + "Jenn", + "Jenna", + "Jennee", + "Jennette", + "Jenni", + "Jennica", + "Jennie", + "Jennifer", + "Jennilee", + "Jennine", + "Jenny", + "Jeralee", + "Jere", + "Jeri", + "Jermaine", + "Jerrie", + "Jerrilee", + "Jerrilyn", + "Jerrine", + "Jerry", + "Jerrylee", + "Jess", + "Jessa", + "Jessalin", + "Jessalyn", + "Jessamine", + "Jessamyn", + "Jesse", + "Jesselyn", + "Jessi", + "Jessica", + "Jessie", + "Jessika", + "Jessy", + "Jewel", + "Jewell", + "Jewelle", + "Jill", + "Jillana", + "Jillane", + "Jillayne", + "Jilleen", + "Jillene", + "Jilli", + "Jillian", + "Jillie", + "Jilly", + "Jinny", + "Jo", + "Jo Ann", + "Jo-Ann", + "Jo-Anne", + "Joan", + "Joana", + "Joane", + "Joanie", + "Joann", + "Joanna", + "Joanne", + "Joannes", + "Jobey", + "Jobi", + "Jobie", + "Jobina", + "Joby", + "Jobye", + "Jobyna", + "Jocelin", + "Joceline", + "Jocelyn", + "Jocelyne", + "Jodee", + "Jodi", + "Jodie", + "Jody", + "Joeann", + "Joela", + "Joelie", + "Joell", + "Joella", + "Joelle", + "Joellen", + "Joelly", + "Joellyn", + "Joelynn", + "Joete", + "Joey", + "Johanna", + "Johannah", + "Johna", + "Johnath", + "Johnette", + "Johnna", + "Joice", + "Jojo", + "Jolee", + "Joleen", + "Jolene", + "Joletta", + "Joli", + "Jolie", + "Joline", + "Joly", + "Jolyn", + "Jolynn", + "Jonell", + "Joni", + "Jonie", + "Jonis", + "Jordain", + "Jordan", + "Jordana", + "Jordanna", + "Jorey", + "Jori", + "Jorie", + "Jorrie", + "Jorry", + "Joscelin", + "Josee", + "Josefa", + "Josefina", + "Josepha", + "Josephina", + "Josephine", + "Josey", + "Josi", + "Josie", + "Josselyn", + "Josy", + "Jourdan", + "Joy", + "Joya", + "Joyan", + "Joyann", + "Joyce", + "Joycelin", + "Joye", + "Jsandye", + "Juana", + "Juanita", + "Judi", + "Judie", + "Judith", + "Juditha", + "Judy", + "Judye", + "Juieta", + "Julee", + "Juli", + "Julia", + "Juliana", + "Juliane", + "Juliann", + "Julianna", + "Julianne", + "Julie", + "Julienne", + "Juliet", + "Julieta", + "Julietta", + "Juliette", + "Julina", + "Juline", + "Julissa", + "Julita", + "June", + "Junette", + "Junia", + "Junie", + "Junina", + "Justina", + "Justine", + "Justinn", + "Jyoti", + "Kacey", + "Kacie", + "Kacy", + "Kaela", + "Kai", + "Kaia", + "Kaila", + "Kaile", + "Kailey", + "Kaitlin", + "Kaitlyn", + "Kaitlynn", + "Kaja", + "Kakalina", + "Kala", + "Kaleena", + "Kali", + "Kalie", + "Kalila", + "Kalina", + "Kalinda", + "Kalindi", + "Kalli", + "Kally", + "Kameko", + "Kamila", + "Kamilah", + "Kamillah", + "Kandace", + "Kandy", + "Kania", + "Kanya", + "Kara", + "Kara-Lynn", + "Karalee", + "Karalynn", + "Kare", + "Karee", + "Karel", + "Karen", + "Karena", + "Kari", + "Karia", + "Karie", + "Karil", + "Karilynn", + "Karin", + "Karina", + "Karine", + "Kariotta", + "Karisa", + "Karissa", + "Karita", + "Karla", + "Karlee", + "Karleen", + "Karlen", + "Karlene", + "Karlie", + "Karlotta", + "Karlotte", + "Karly", + "Karlyn", + "Karmen", + "Karna", + "Karol", + "Karola", + "Karole", + "Karolina", + "Karoline", + "Karoly", + "Karon", + "Karrah", + "Karrie", + "Karry", + "Kary", + "Karyl", + "Karylin", + "Karyn", + "Kasey", + "Kass", + "Kassandra", + "Kassey", + "Kassi", + "Kassia", + "Kassie", + "Kat", + "Kata", + "Katalin", + "Kate", + "Katee", + "Katerina", + "Katerine", + "Katey", + "Kath", + "Katha", + "Katharina", + "Katharine", + "Katharyn", + "Kathe", + "Katherina", + "Katherine", + "Katheryn", + "Kathi", + "Kathie", + "Kathleen", + "Kathlin", + "Kathrine", + "Kathryn", + "Kathryne", + "Kathy", + "Kathye", + "Kati", + "Katie", + "Katina", + "Katine", + "Katinka", + "Katleen", + "Katlin", + "Katrina", + "Katrine", + "Katrinka", + "Katti", + "Kattie", + "Katuscha", + "Katusha", + "Katy", + "Katya", + "Kay", + "Kaycee", + "Kaye", + "Kayla", + "Kayle", + "Kaylee", + "Kayley", + "Kaylil", + "Kaylyn", + "Keeley", + "Keelia", + "Keely", + "Kelcey", + "Kelci", + "Kelcie", + "Kelcy", + "Kelila", + "Kellen", + "Kelley", + "Kelli", + "Kellia", + "Kellie", + "Kellina", + "Kellsie", + "Kelly", + "Kellyann", + "Kelsey", + "Kelsi", + "Kelsy", + "Kendra", + "Kendre", + "Kenna", + "Keri", + "Keriann", + "Kerianne", + "Kerri", + "Kerrie", + "Kerrill", + "Kerrin", + "Kerry", + "Kerstin", + "Kesley", + "Keslie", + "Kessia", + "Kessiah", + "Ketti", + "Kettie", + "Ketty", + "Kevina", + "Kevyn", + "Ki", + "Kiah", + "Kial", + "Kiele", + "Kiersten", + "Kikelia", + "Kiley", + "Kim", + "Kimberlee", + "Kimberley", + "Kimberli", + "Kimberly", + "Kimberlyn", + "Kimbra", + "Kimmi", + "Kimmie", + "Kimmy", + "Kinna", + "Kip", + "Kipp", + "Kippie", + "Kippy", + "Kira", + "Kirbee", + "Kirbie", + "Kirby", + "Kiri", + "Kirsten", + "Kirsteni", + "Kirsti", + "Kirstin", + "Kirstyn", + "Kissee", + "Kissiah", + "Kissie", + "Kit", + "Kitti", + "Kittie", + "Kitty", + "Kizzee", + "Kizzie", + "Klara", + "Klarika", + "Klarrisa", + "Konstance", + "Konstanze", + "Koo", + "Kora", + "Koral", + "Koralle", + "Kordula", + "Kore", + "Korella", + "Koren", + "Koressa", + "Kori", + "Korie", + "Korney", + "Korrie", + "Korry", + "Kris", + "Krissie", + "Krissy", + "Krista", + "Kristal", + "Kristan", + "Kriste", + "Kristel", + "Kristen", + "Kristi", + "Kristien", + "Kristin", + "Kristina", + "Kristine", + "Kristy", + "Kristyn", + "Krysta", + "Krystal", + "Krystalle", + "Krystle", + "Krystyna", + "Kyla", + "Kyle", + "Kylen", + "Kylie", + "Kylila", + "Kylynn", + "Kym", + "Kynthia", + "Kyrstin", + "La Verne", + "Lacee", + "Lacey", + "Lacie", + "Lacy", + "Ladonna", + "Laetitia", + "Laina", + "Lainey", + "Lana", + "Lanae", + "Lane", + "Lanette", + "Laney", + "Lani", + "Lanie", + "Lanita", + "Lanna", + "Lanni", + "Lanny", + "Lara", + "Laraine", + "Lari", + "Larina", + "Larine", + "Larisa", + "Larissa", + "Lark", + "Laryssa", + "Latashia", + "Latia", + "Latisha", + "Latrena", + "Latrina", + "Laura", + "Lauraine", + "Laural", + "Lauralee", + "Laure", + "Lauree", + "Laureen", + "Laurel", + "Laurella", + "Lauren", + "Laurena", + "Laurene", + "Lauretta", + "Laurette", + "Lauri", + "Laurianne", + "Laurice", + "Laurie", + "Lauryn", + "Lavena", + "Laverna", + "Laverne", + "Lavina", + "Lavinia", + "Lavinie", + "Layla", + "Layne", + "Layney", + "Lea", + "Leah", + "Leandra", + "Leann", + "Leanna", + "Leanor", + "Leanora", + "Lebbie", + "Leda", + "Lee", + "Leeann", + "Leeanne", + "Leela", + "Leelah", + "Leena", + "Leesa", + "Leese", + "Legra", + "Leia", + "Leigh", + "Leigha", + "Leila", + "Leilah", + "Leisha", + "Lela", + "Lelah", + "Leland", + "Lelia", + "Lena", + "Lenee", + "Lenette", + "Lenka", + "Lenna", + "Lenora", + "Lenore", + "Leodora", + "Leoine", + "Leola", + "Leoline", + "Leona", + "Leonanie", + "Leone", + "Leonelle", + "Leonie", + "Leonora", + "Leonore", + "Leontine", + "Leontyne", + "Leora", + "Leshia", + "Lesley", + "Lesli", + "Leslie", + "Lesly", + "Lesya", + "Leta", + "Lethia", + "Leticia", + "Letisha", + "Letitia", + "Letizia", + "Letta", + "Letti", + "Lettie", + "Letty", + "Lexi", + "Lexie", + "Lexine", + "Lexis", + "Lexy", + "Leyla", + "Lezlie", + "Lia", + "Lian", + "Liana", + "Liane", + "Lianna", + "Lianne", + "Lib", + "Libbey", + "Libbi", + "Libbie", + "Libby", + "Licha", + "Lida", + "Lidia", + "Liesa", + "Lil", + "Lila", + "Lilah", + "Lilas", + "Lilia", + "Lilian", + "Liliane", + "Lilias", + "Lilith", + "Lilla", + "Lilli", + "Lillian", + "Lillis", + "Lilllie", + "Lilly", + "Lily", + "Lilyan", + "Lin", + "Lina", + "Lind", + "Linda", + "Lindi", + "Lindie", + "Lindsay", + "Lindsey", + "Lindsy", + "Lindy", + "Linea", + "Linell", + "Linet", + "Linette", + "Linn", + "Linnea", + "Linnell", + "Linnet", + "Linnie", + "Linzy", + "Lira", + "Lisa", + "Lisabeth", + "Lisbeth", + "Lise", + "Lisetta", + "Lisette", + "Lisha", + "Lishe", + "Lissa", + "Lissi", + "Lissie", + "Lissy", + "Lita", + "Liuka", + "Liv", + "Liva", + "Livia", + "Livvie", + "Livvy", + "Livvyy", + "Livy", + "Liz", + "Liza", + "Lizabeth", + "Lizbeth", + "Lizette", + "Lizzie", + "Lizzy", + "Loella", + "Lois", + "Loise", + "Lola", + "Loleta", + "Lolita", + "Lolly", + "Lona", + "Lonee", + "Loni", + "Lonna", + "Lonni", + "Lonnie", + "Lora", + "Lorain", + "Loraine", + "Loralee", + "Loralie", + "Loralyn", + "Loree", + "Loreen", + "Lorelei", + "Lorelle", + "Loren", + "Lorena", + "Lorene", + "Lorenza", + "Loretta", + "Lorette", + "Lori", + "Loria", + "Lorianna", + "Lorianne", + "Lorie", + "Lorilee", + "Lorilyn", + "Lorinda", + "Lorine", + "Lorita", + "Lorna", + "Lorne", + "Lorraine", + "Lorrayne", + "Lorri", + "Lorrie", + "Lorrin", + "Lorry", + "Lory", + "Lotta", + "Lotte", + "Lotti", + "Lottie", + "Lotty", + "Lou", + "Louella", + "Louisa", + "Louise", + "Louisette", + "Loutitia", + "Lu", + "Luce", + "Luci", + "Lucia", + "Luciana", + "Lucie", + "Lucienne", + "Lucila", + "Lucilia", + "Lucille", + "Lucina", + "Lucinda", + "Lucine", + "Lucita", + "Lucky", + "Lucretia", + "Lucy", + "Ludovika", + "Luella", + "Luelle", + "Luisa", + "Luise", + "Lula", + "Lulita", + "Lulu", + "Lura", + "Lurette", + "Lurleen", + "Lurlene", + "Lurline", + "Lusa", + "Luz", + "Lyda", + "Lydia", + "Lydie", + "Lyn", + "Lynda", + "Lynde", + "Lyndel", + "Lyndell", + "Lyndsay", + "Lyndsey", + "Lyndsie", + "Lyndy", + "Lynea", + "Lynelle", + "Lynett", + "Lynette", + "Lynn", + "Lynna", + "Lynne", + "Lynnea", + "Lynnell", + "Lynnelle", + "Lynnet", + "Lynnett", + "Lynnette", + "Lynsey", + "Lyssa", + "Mab", + "Mabel", + "Mabelle", + "Mable", + "Mada", + "Madalena", + "Madalyn", + "Maddalena", + "Maddi", + "Maddie", + "Maddy", + "Madel", + "Madelaine", + "Madeleine", + "Madelena", + "Madelene", + "Madelin", + "Madelina", + "Madeline", + "Madella", + "Madelle", + "Madelon", + "Madelyn", + "Madge", + "Madlen", + "Madlin", + "Madonna", + "Mady", + "Mae", + "Maegan", + "Mag", + "Magda", + "Magdaia", + "Magdalen", + "Magdalena", + "Magdalene", + "Maggee", + "Maggi", + "Maggie", + "Maggy", + "Mahala", + "Mahalia", + "Maia", + "Maible", + "Maiga", + "Maighdiln", + "Mair", + "Maire", + "Maisey", + "Maisie", + "Maitilde", + "Mala", + "Malanie", + "Malena", + "Malia", + "Malina", + "Malinda", + "Malinde", + "Malissa", + "Malissia", + "Mallissa", + "Mallorie", + "Mallory", + "Malorie", + "Malory", + "Malva", + "Malvina", + "Malynda", + "Mame", + "Mamie", + "Manda", + "Mandi", + "Mandie", + "Mandy", + "Manon", + "Manya", + "Mara", + "Marabel", + "Marcela", + "Marcelia", + "Marcella", + "Marcelle", + "Marcellina", + "Marcelline", + "Marchelle", + "Marci", + "Marcia", + "Marcie", + "Marcile", + "Marcille", + "Marcy", + "Mareah", + "Maren", + "Marena", + "Maressa", + "Marga", + "Margalit", + "Margalo", + "Margaret", + "Margareta", + "Margarete", + "Margaretha", + "Margarethe", + "Margaretta", + "Margarette", + "Margarita", + "Margaux", + "Marge", + "Margeaux", + "Margery", + "Marget", + "Margette", + "Margi", + "Margie", + "Margit", + "Margo", + "Margot", + "Margret", + "Marguerite", + "Margy", + "Mari", + "Maria", + "Mariam", + "Marian", + "Mariana", + "Mariann", + "Marianna", + "Marianne", + "Maribel", + "Maribelle", + "Maribeth", + "Marice", + "Maridel", + "Marie", + "Marie-Ann", + "Marie-Jeanne", + "Marieann", + "Mariejeanne", + "Mariel", + "Mariele", + "Marielle", + "Mariellen", + "Marietta", + "Mariette", + "Marigold", + "Marijo", + "Marika", + "Marilee", + "Marilin", + "Marillin", + "Marilyn", + "Marin", + "Marina", + "Marinna", + "Marion", + "Mariquilla", + "Maris", + "Marisa", + "Mariska", + "Marissa", + "Marita", + "Maritsa", + "Mariya", + "Marj", + "Marja", + "Marje", + "Marji", + "Marjie", + "Marjorie", + "Marjory", + "Marjy", + "Marketa", + "Marla", + "Marlane", + "Marleah", + "Marlee", + "Marleen", + "Marlena", + "Marlene", + "Marley", + "Marlie", + "Marline", + "Marlo", + "Marlyn", + "Marna", + "Marne", + "Marney", + "Marni", + "Marnia", + "Marnie", + "Marquita", + "Marrilee", + "Marris", + "Marrissa", + "Marsha", + "Marsiella", + "Marta", + "Martelle", + "Martguerita", + "Martha", + "Marthe", + "Marthena", + "Marti", + "Martica", + "Martie", + "Martina", + "Martita", + "Marty", + "Martynne", + "Mary", + "Marya", + "Maryann", + "Maryanna", + "Maryanne", + "Marybelle", + "Marybeth", + "Maryellen", + "Maryjane", + "Maryjo", + "Maryl", + "Marylee", + "Marylin", + "Marylinda", + "Marylou", + "Marylynne", + "Maryrose", + "Marys", + "Marysa", + "Masha", + "Matelda", + "Mathilda", + "Mathilde", + "Matilda", + "Matilde", + "Matti", + "Mattie", + "Matty", + "Maud", + "Maude", + "Maudie", + "Maura", + "Maure", + "Maureen", + "Maureene", + "Maurene", + "Maurine", + "Maurise", + "Maurita", + "Maurizia", + "Mavis", + "Mavra", + "Max", + "Maxi", + "Maxie", + "Maxine", + "Maxy", + "May", + "Maybelle", + "Maye", + "Mead", + "Meade", + "Meagan", + "Meaghan", + "Meara", + "Mechelle", + "Meg", + "Megan", + "Megen", + "Meggi", + "Meggie", + "Meggy", + "Meghan", + "Meghann", + "Mehetabel", + "Mei", + "Mel", + "Mela", + "Melamie", + "Melania", + "Melanie", + "Melantha", + "Melany", + "Melba", + "Melesa", + "Melessa", + "Melicent", + "Melina", + "Melinda", + "Melinde", + "Melisa", + "Melisande", + "Melisandra", + "Melisenda", + "Melisent", + "Melissa", + "Melisse", + "Melita", + "Melitta", + "Mella", + "Melli", + "Mellicent", + "Mellie", + "Mellisa", + "Mellisent", + "Melloney", + "Melly", + "Melodee", + "Melodie", + "Melody", + "Melonie", + "Melony", + "Melosa", + "Melva", + "Mercedes", + "Merci", + "Mercie", + "Mercy", + "Meredith", + "Meredithe", + "Meridel", + "Meridith", + "Meriel", + "Merilee", + "Merilyn", + "Meris", + "Merissa", + "Merl", + "Merla", + "Merle", + "Merlina", + "Merline", + "Merna", + "Merola", + "Merralee", + "Merridie", + "Merrie", + "Merrielle", + "Merrile", + "Merrilee", + "Merrili", + "Merrill", + "Merrily", + "Merry", + "Mersey", + "Meryl", + "Meta", + "Mia", + "Micaela", + "Michaela", + "Michaelina", + "Michaeline", + "Michaella", + "Michal", + "Michel", + "Michele", + "Michelina", + "Micheline", + "Michell", + "Michelle", + "Micki", + "Mickie", + "Micky", + "Midge", + "Mignon", + "Mignonne", + "Miguela", + "Miguelita", + "Mikaela", + "Mil", + "Mildred", + "Mildrid", + "Milena", + "Milicent", + "Milissent", + "Milka", + "Milli", + "Millicent", + "Millie", + "Millisent", + "Milly", + "Milzie", + "Mimi", + "Min", + "Mina", + "Minda", + "Mindy", + "Minerva", + "Minetta", + "Minette", + "Minna", + "Minnaminnie", + "Minne", + "Minni", + "Minnie", + "Minnnie", + "Minny", + "Minta", + "Miof Mela", + "Miquela", + "Mira", + "Mirabel", + "Mirabella", + "Mirabelle", + "Miran", + "Miranda", + "Mireielle", + "Mireille", + "Mirella", + "Mirelle", + "Miriam", + "Mirilla", + "Mirna", + "Misha", + "Missie", + "Missy", + "Misti", + "Misty", + "Mitzi", + "Modesta", + "Modestia", + "Modestine", + "Modesty", + "Moina", + "Moira", + "Moll", + "Mollee", + "Molli", + "Mollie", + "Molly", + "Mommy", + "Mona", + "Monah", + "Monica", + "Monika", + "Monique", + "Mora", + "Moreen", + "Morena", + "Morgan", + "Morgana", + "Morganica", + "Morganne", + "Morgen", + "Moria", + "Morissa", + "Morna", + "Moselle", + "Moyna", + "Moyra", + "Mozelle", + "Muffin", + "Mufi", + "Mufinella", + "Muire", + "Mureil", + "Murial", + "Muriel", + "Murielle", + "Myra", + "Myrah", + "Myranda", + "Myriam", + "Myrilla", + "Myrle", + "Myrlene", + "Myrna", + "Myrta", + "Myrtia", + "Myrtice", + "Myrtie", + "Myrtle", + "Nada", + "Nadean", + "Nadeen", + "Nadia", + "Nadine", + "Nadiya", + "Nady", + "Nadya", + "Nalani", + "Nan", + "Nana", + "Nananne", + "Nance", + "Nancee", + "Nancey", + "Nanci", + "Nancie", + "Nancy", + "Nanete", + "Nanette", + "Nani", + "Nanice", + "Nanine", + "Nannette", + "Nanni", + "Nannie", + "Nanny", + "Nanon", + "Naoma", + "Naomi", + "Nara", + "Nari", + "Nariko", + "Nat", + "Nata", + "Natala", + "Natalee", + "Natalie", + "Natalina", + "Nataline", + "Natalya", + "Natasha", + "Natassia", + "Nathalia", + "Nathalie", + "Natividad", + "Natka", + "Natty", + "Neala", + "Neda", + "Nedda", + "Nedi", + "Neely", + "Neila", + "Neile", + "Neilla", + "Neille", + "Nelia", + "Nelie", + "Nell", + "Nelle", + "Nelli", + "Nellie", + "Nelly", + "Nerissa", + "Nerita", + "Nert", + "Nerta", + "Nerte", + "Nerti", + "Nertie", + "Nerty", + "Nessa", + "Nessi", + "Nessie", + "Nessy", + "Nesta", + "Netta", + "Netti", + "Nettie", + "Nettle", + "Netty", + "Nevsa", + "Neysa", + "Nichol", + "Nichole", + "Nicholle", + "Nicki", + "Nickie", + "Nicky", + "Nicol", + "Nicola", + "Nicole", + "Nicolea", + "Nicolette", + "Nicoli", + "Nicolina", + "Nicoline", + "Nicolle", + "Nikaniki", + "Nike", + "Niki", + "Nikki", + "Nikkie", + "Nikoletta", + "Nikolia", + "Nina", + "Ninetta", + "Ninette", + "Ninnetta", + "Ninnette", + "Ninon", + "Nissa", + "Nisse", + "Nissie", + "Nissy", + "Nita", + "Nixie", + "Noami", + "Noel", + "Noelani", + "Noell", + "Noella", + "Noelle", + "Noellyn", + "Noelyn", + "Noemi", + "Nola", + "Nolana", + "Nolie", + "Nollie", + "Nomi", + "Nona", + "Nonah", + "Noni", + "Nonie", + "Nonna", + "Nonnah", + "Nora", + "Norah", + "Norean", + "Noreen", + "Norene", + "Norina", + "Norine", + "Norma", + "Norri", + "Norrie", + "Norry", + "Novelia", + "Nydia", + "Nyssa", + "Octavia", + "Odele", + "Odelia", + "Odelinda", + "Odella", + "Odelle", + "Odessa", + "Odetta", + "Odette", + "Odilia", + "Odille", + "Ofelia", + "Ofella", + "Ofilia", + "Ola", + "Olenka", + "Olga", + "Olia", + "Olimpia", + "Olive", + "Olivette", + "Olivia", + "Olivie", + "Oliy", + "Ollie", + "Olly", + "Olva", + "Olwen", + "Olympe", + "Olympia", + "Olympie", + "Ondrea", + "Oneida", + "Onida", + "Oona", + "Opal", + "Opalina", + "Opaline", + "Ophelia", + "Ophelie", + "Ora", + "Oralee", + "Oralia", + "Oralie", + "Oralla", + "Oralle", + "Orel", + "Orelee", + "Orelia", + "Orelie", + "Orella", + "Orelle", + "Oriana", + "Orly", + "Orsa", + "Orsola", + "Ortensia", + "Otha", + "Othelia", + "Othella", + "Othilia", + "Othilie", + "Ottilie", + "Page", + "Paige", + "Paloma", + "Pam", + "Pamela", + "Pamelina", + "Pamella", + "Pammi", + "Pammie", + "Pammy", + "Pandora", + "Pansie", + "Pansy", + "Paola", + "Paolina", + "Papagena", + "Pat", + "Patience", + "Patrica", + "Patrice", + "Patricia", + "Patrizia", + "Patsy", + "Patti", + "Pattie", + "Patty", + "Paula", + "Paule", + "Pauletta", + "Paulette", + "Pauli", + "Paulie", + "Paulina", + "Pauline", + "Paulita", + "Pauly", + "Pavia", + "Pavla", + "Pearl", + "Pearla", + "Pearle", + "Pearline", + "Peg", + "Pegeen", + "Peggi", + "Peggie", + "Peggy", + "Pen", + "Penelopa", + "Penelope", + "Penni", + "Pennie", + "Penny", + "Pepi", + "Pepita", + "Peri", + "Peria", + "Perl", + "Perla", + "Perle", + "Perri", + "Perrine", + "Perry", + "Persis", + "Pet", + "Peta", + "Petra", + "Petrina", + "Petronella", + "Petronia", + "Petronilla", + "Petronille", + "Petunia", + "Phaedra", + "Phaidra", + "Phebe", + "Phedra", + "Phelia", + "Phil", + "Philipa", + "Philippa", + "Philippe", + "Philippine", + "Philis", + "Phillida", + "Phillie", + "Phillis", + "Philly", + "Philomena", + "Phoebe", + "Phylis", + "Phyllida", + "Phyllis", + "Phyllys", + "Phylys", + "Pia", + "Pier", + "Pierette", + "Pierrette", + "Pietra", + "Piper", + "Pippa", + "Pippy", + "Polly", + "Pollyanna", + "Pooh", + "Poppy", + "Portia", + "Pris", + "Prisca", + "Priscella", + "Priscilla", + "Prissie", + "Pru", + "Prudence", + "Prudi", + "Prudy", + "Prue", + "Queenie", + "Quentin", + "Querida", + "Quinn", + "Quinta", + "Quintana", + "Quintilla", + "Quintina", + "Rachael", + "Rachel", + "Rachele", + "Rachelle", + "Rae", + "Raeann", + "Raf", + "Rafa", + "Rafaela", + "Rafaelia", + "Rafaelita", + "Rahal", + "Rahel", + "Raina", + "Raine", + "Rakel", + "Ralina", + "Ramona", + "Ramonda", + "Rana", + "Randa", + "Randee", + "Randene", + "Randi", + "Randie", + "Randy", + "Ranee", + "Rani", + "Rania", + "Ranice", + "Ranique", + "Ranna", + "Raphaela", + "Raquel", + "Raquela", + "Rasia", + "Rasla", + "Raven", + "Ray", + "Raychel", + "Raye", + "Rayna", + "Raynell", + "Rayshell", + "Rea", + "Reba", + "Rebbecca", + "Rebe", + "Rebeca", + "Rebecca", + "Rebecka", + "Rebeka", + "Rebekah", + "Rebekkah", + "Ree", + "Reeba", + "Reena", + "Reeta", + "Reeva", + "Regan", + "Reggi", + "Reggie", + "Regina", + "Regine", + "Reiko", + "Reina", + "Reine", + "Remy", + "Rena", + "Renae", + "Renata", + "Renate", + "Rene", + "Renee", + "Renell", + "Renelle", + "Renie", + "Rennie", + "Reta", + "Retha", + "Revkah", + "Rey", + "Reyna", + "Rhea", + "Rheba", + "Rheta", + "Rhetta", + "Rhiamon", + "Rhianna", + "Rhianon", + "Rhoda", + "Rhodia", + "Rhodie", + "Rhody", + "Rhona", + "Rhonda", + "Riane", + "Riannon", + "Rianon", + "Rica", + "Ricca", + "Rici", + "Ricki", + "Rickie", + "Ricky", + "Riki", + "Rikki", + "Rina", + "Risa", + "Rita", + "Riva", + "Rivalee", + "Rivi", + "Rivkah", + "Rivy", + "Roana", + "Roanna", + "Roanne", + "Robbi", + "Robbie", + "Robbin", + "Robby", + "Robbyn", + "Robena", + "Robenia", + "Roberta", + "Robin", + "Robina", + "Robinet", + "Robinett", + "Robinetta", + "Robinette", + "Robinia", + "Roby", + "Robyn", + "Roch", + "Rochell", + "Rochella", + "Rochelle", + "Rochette", + "Roda", + "Rodi", + "Rodie", + "Rodina", + "Rois", + "Romola", + "Romona", + "Romonda", + "Romy", + "Rona", + "Ronalda", + "Ronda", + "Ronica", + "Ronna", + "Ronni", + "Ronnica", + "Ronnie", + "Ronny", + "Roobbie", + "Rora", + "Rori", + "Rorie", + "Rory", + "Ros", + "Rosa", + "Rosabel", + "Rosabella", + "Rosabelle", + "Rosaleen", + "Rosalia", + "Rosalie", + "Rosalind", + "Rosalinda", + "Rosalinde", + "Rosaline", + "Rosalyn", + "Rosalynd", + "Rosamond", + "Rosamund", + "Rosana", + "Rosanna", + "Rosanne", + "Rose", + "Roseann", + "Roseanna", + "Roseanne", + "Roselia", + "Roselin", + "Roseline", + "Rosella", + "Roselle", + "Rosemaria", + "Rosemarie", + "Rosemary", + "Rosemonde", + "Rosene", + "Rosetta", + "Rosette", + "Roshelle", + "Rosie", + "Rosina", + "Rosita", + "Roslyn", + "Rosmunda", + "Rosy", + "Row", + "Rowe", + "Rowena", + "Roxana", + "Roxane", + "Roxanna", + "Roxanne", + "Roxi", + "Roxie", + "Roxine", + "Roxy", + "Roz", + "Rozalie", + "Rozalin", + "Rozamond", + "Rozanna", + "Rozanne", + "Roze", + "Rozele", + "Rozella", + "Rozelle", + "Rozina", + "Rubetta", + "Rubi", + "Rubia", + "Rubie", + "Rubina", + "Ruby", + "Ruperta", + "Ruth", + "Ruthann", + "Ruthanne", + "Ruthe", + "Ruthi", + "Ruthie", + "Ruthy", + "Ryann", + "Rycca", + "Saba", + "Sabina", + "Sabine", + "Sabra", + "Sabrina", + "Sacha", + "Sada", + "Sadella", + "Sadie", + "Sadye", + "Saidee", + "Sal", + "Salaidh", + "Sallee", + "Salli", + "Sallie", + "Sally", + "Sallyann", + "Sallyanne", + "Saloma", + "Salome", + "Salomi", + "Sam", + "Samantha", + "Samara", + "Samaria", + "Sammy", + "Sande", + "Sandi", + "Sandie", + "Sandra", + "Sandy", + "Sandye", + "Sapphira", + "Sapphire", + "Sara", + "Sara-Ann", + "Saraann", + "Sarah", + "Sarajane", + "Saree", + "Sarena", + "Sarene", + "Sarette", + "Sari", + "Sarina", + "Sarine", + "Sarita", + "Sascha", + "Sasha", + "Sashenka", + "Saudra", + "Saundra", + "Savina", + "Sayre", + "Scarlet", + "Scarlett", + "Sean", + "Seana", + "Seka", + "Sela", + "Selena", + "Selene", + "Selestina", + "Selia", + "Selie", + "Selina", + "Selinda", + "Seline", + "Sella", + "Selle", + "Selma", + "Sena", + "Sephira", + "Serena", + "Serene", + "Shae", + "Shaina", + "Shaine", + "Shalna", + "Shalne", + "Shana", + "Shanda", + "Shandee", + "Shandeigh", + "Shandie", + "Shandra", + "Shandy", + "Shane", + "Shani", + "Shanie", + "Shanna", + "Shannah", + "Shannen", + "Shannon", + "Shanon", + "Shanta", + "Shantee", + "Shara", + "Sharai", + "Shari", + "Sharia", + "Sharity", + "Sharl", + "Sharla", + "Sharleen", + "Sharlene", + "Sharline", + "Sharon", + "Sharona", + "Sharron", + "Sharyl", + "Shaun", + "Shauna", + "Shawn", + "Shawna", + "Shawnee", + "Shay", + "Shayla", + "Shaylah", + "Shaylyn", + "Shaylynn", + "Shayna", + "Shayne", + "Shea", + "Sheba", + "Sheela", + "Sheelagh", + "Sheelah", + "Sheena", + "Sheeree", + "Sheila", + "Sheila-Kathryn", + "Sheilah", + "Shel", + "Shela", + "Shelagh", + "Shelba", + "Shelbi", + "Shelby", + "Shelia", + "Shell", + "Shelley", + "Shelli", + "Shellie", + "Shelly", + "Shena", + "Sher", + "Sheree", + "Sheri", + "Sherie", + "Sherill", + "Sherilyn", + "Sherline", + "Sherri", + "Sherrie", + "Sherry", + "Sherye", + "Sheryl", + "Shina", + "Shir", + "Shirl", + "Shirlee", + "Shirleen", + "Shirlene", + "Shirley", + "Shirline", + "Shoshana", + "Shoshanna", + "Siana", + "Sianna", + "Sib", + "Sibbie", + "Sibby", + "Sibeal", + "Sibel", + "Sibella", + "Sibelle", + "Sibilla", + "Sibley", + "Sibyl", + "Sibylla", + "Sibylle", + "Sidoney", + "Sidonia", + "Sidonnie", + "Sigrid", + "Sile", + "Sileas", + "Silva", + "Silvana", + "Silvia", + "Silvie", + "Simona", + "Simone", + "Simonette", + "Simonne", + "Sindee", + "Siobhan", + "Sioux", + "Siouxie", + "Sisely", + "Sisile", + "Sissie", + "Sissy", + "Siusan", + "Sofia", + "Sofie", + "Sondra", + "Sonia", + "Sonja", + "Sonni", + "Sonnie", + "Sonnnie", + "Sonny", + "Sonya", + "Sophey", + "Sophi", + "Sophia", + "Sophie", + "Sophronia", + "Sorcha", + "Sosanna", + "Stace", + "Stacee", + "Stacey", + "Staci", + "Stacia", + "Stacie", + "Stacy", + "Stafani", + "Star", + "Starla", + "Starlene", + "Starlin", + "Starr", + "Stefa", + "Stefania", + "Stefanie", + "Steffane", + "Steffi", + "Steffie", + "Stella", + "Stepha", + "Stephana", + "Stephani", + "Stephanie", + "Stephannie", + "Stephenie", + "Stephi", + "Stephie", + "Stephine", + "Stesha", + "Stevana", + "Stevena", + "Stoddard", + "Storm", + "Stormi", + "Stormie", + "Stormy", + "Sue", + "Suellen", + "Sukey", + "Suki", + "Sula", + "Sunny", + "Sunshine", + "Susan", + "Susana", + "Susanetta", + "Susann", + "Susanna", + "Susannah", + "Susanne", + "Susette", + "Susi", + "Susie", + "Susy", + "Suzann", + "Suzanna", + "Suzanne", + "Suzette", + "Suzi", + "Suzie", + "Suzy", + "Sybil", + "Sybila", + "Sybilla", + "Sybille", + "Sybyl", + "Sydel", + "Sydelle", + "Sydney", + "Sylvia", + "Tabatha", + "Tabbatha", + "Tabbi", + "Tabbie", + "Tabbitha", + "Tabby", + "Tabina", + "Tabitha", + "Taffy", + "Talia", + "Tallia", + "Tallie", + "Tallou", + "Tallulah", + "Tally", + "Talya", + "Talyah", + "Tamar", + "Tamara", + "Tamarah", + "Tamarra", + "Tamera", + "Tami", + "Tamiko", + "Tamma", + "Tammara", + "Tammi", + "Tammie", + "Tammy", + "Tamqrah", + "Tamra", + "Tana", + "Tandi", + "Tandie", + "Tandy", + "Tanhya", + "Tani", + "Tania", + "Tanitansy", + "Tansy", + "Tanya", + "Tara", + "Tarah", + "Tarra", + "Tarrah", + "Taryn", + "Tasha", + "Tasia", + "Tate", + "Tatiana", + "Tatiania", + "Tatum", + "Tawnya", + "Tawsha", + "Ted", + "Tedda", + "Teddi", + "Teddie", + "Teddy", + "Tedi", + "Tedra", + "Teena", + "TEirtza", + "Teodora", + "Tera", + "Teresa", + "Terese", + "Teresina", + "Teresita", + "Teressa", + "Teri", + "Teriann", + "Terra", + "Terri", + "Terrie", + "Terrijo", + "Terry", + "Terrye", + "Tersina", + "Terza", + "Tess", + "Tessa", + "Tessi", + "Tessie", + "Tessy", + "Thalia", + "Thea", + "Theadora", + "Theda", + "Thekla", + "Thelma", + "Theo", + "Theodora", + "Theodosia", + "Theresa", + "Therese", + "Theresina", + "Theresita", + "Theressa", + "Therine", + "Thia", + "Thomasa", + "Thomasin", + "Thomasina", + "Thomasine", + "Tiena", + "Tierney", + "Tiertza", + "Tiff", + "Tiffani", + "Tiffanie", + "Tiffany", + "Tiffi", + "Tiffie", + "Tiffy", + "Tilda", + "Tildi", + "Tildie", + "Tildy", + "Tillie", + "Tilly", + "Tim", + "Timi", + "Timmi", + "Timmie", + "Timmy", + "Timothea", + "Tina", + "Tine", + "Tiphani", + "Tiphanie", + "Tiphany", + "Tish", + "Tisha", + "Tobe", + "Tobey", + "Tobi", + "Toby", + "Tobye", + "Toinette", + "Toma", + "Tomasina", + "Tomasine", + "Tomi", + "Tommi", + "Tommie", + "Tommy", + "Toni", + "Tonia", + "Tonie", + "Tony", + "Tonya", + "Tonye", + "Tootsie", + "Torey", + "Tori", + "Torie", + "Torrie", + "Tory", + "Tova", + "Tove", + "Tracee", + "Tracey", + "Traci", + "Tracie", + "Tracy", + "Trenna", + "Tresa", + "Trescha", + "Tressa", + "Tricia", + "Trina", + "Trish", + "Trisha", + "Trista", + "Trix", + "Trixi", + "Trixie", + "Trixy", + "Truda", + "Trude", + "Trudey", + "Trudi", + "Trudie", + "Trudy", + "Trula", + "Tuesday", + "Twila", + "Twyla", + "Tybi", + "Tybie", + "Tyne", + "Ula", + "Ulla", + "Ulrica", + "Ulrika", + "Ulrikaumeko", + "Ulrike", + "Umeko", + "Una", + "Ursa", + "Ursala", + "Ursola", + "Ursula", + "Ursulina", + "Ursuline", + "Uta", + "Val", + "Valaree", + "Valaria", + "Vale", + "Valeda", + "Valencia", + "Valene", + "Valenka", + "Valentia", + "Valentina", + "Valentine", + "Valera", + "Valeria", + "Valerie", + "Valery", + "Valerye", + "Valida", + "Valina", + "Valli", + "Vallie", + "Vally", + "Valma", + "Valry", + "Van", + "Vanda", + "Vanessa", + "Vania", + "Vanna", + "Vanni", + "Vannie", + "Vanny", + "Vanya", + "Veda", + "Velma", + "Velvet", + "Venita", + "Venus", + "Vera", + "Veradis", + "Vere", + "Verena", + "Verene", + "Veriee", + "Verile", + "Verina", + "Verine", + "Verla", + "Verna", + "Vernice", + "Veronica", + "Veronika", + "Veronike", + "Veronique", + "Vevay", + "Vi", + "Vicki", + "Vickie", + "Vicky", + "Victoria", + "Vida", + "Viki", + "Vikki", + "Vikky", + "Vilhelmina", + "Vilma", + "Vin", + "Vina", + "Vinita", + "Vinni", + "Vinnie", + "Vinny", + "Viola", + "Violante", + "Viole", + "Violet", + "Violetta", + "Violette", + "Virgie", + "Virgina", + "Virginia", + "Virginie", + "Vita", + "Vitia", + "Vitoria", + "Vittoria", + "Viv", + "Viva", + "Vivi", + "Vivia", + "Vivian", + "Viviana", + "Vivianna", + "Vivianne", + "Vivie", + "Vivien", + "Viviene", + "Vivienne", + "Viviyan", + "Vivyan", + "Vivyanne", + "Vonni", + "Vonnie", + "Vonny", + "Vyky", + "Wallie", + "Wallis", + "Walliw", + "Wally", + "Waly", + "Wanda", + "Wandie", + "Wandis", + "Waneta", + "Wanids", + "Wenda", + "Wendeline", + "Wendi", + "Wendie", + "Wendy", + "Wendye", + "Wenona", + "Wenonah", + "Whitney", + "Wileen", + "Wilhelmina", + "Wilhelmine", + "Wilie", + "Willa", + "Willabella", + "Willamina", + "Willetta", + "Willette", + "Willi", + "Willie", + "Willow", + "Willy", + "Willyt", + "Wilma", + "Wilmette", + "Wilona", + "Wilone", + "Wilow", + "Windy", + "Wini", + "Winifred", + "Winna", + "Winnah", + "Winne", + "Winni", + "Winnie", + "Winnifred", + "Winny", + "Winona", + "Winonah", + "Wren", + "Wrennie", + "Wylma", + "Wynn", + "Wynne", + "Wynnie", + "Wynny", + "Xaviera", + "Xena", + "Xenia", + "Xylia", + "Xylina", + "Yalonda", + "Yasmeen", + "Yasmin", + "Yelena", + "Yetta", + "Yettie", + "Yetty", + "Yevette", + "Ynes", + "Ynez", + "Yoko", + "Yolanda", + "Yolande", + "Yolane", + "Yolanthe", + "Yoshi", + "Yoshiko", + "Yovonnda", + "Ysabel", + "Yvette", + "Yvonne", + "Zabrina", + "Zahara", + "Zandra", + "Zaneta", + "Zara", + "Zarah", + "Zaria", + "Zarla", + "Zea", + "Zelda", + "Zelma", + "Zena", + "Zenia", + "Zia", + "Zilvia", + "Zita", + "Zitella", + "Zoe", + "Zola", + "Zonda", + "Zondra", + "Zonnya", + "Zora", + "Zorah", + "Zorana", + "Zorina", + "Zorine", + "Zsa Zsa", + "Zsazsa", + "Zulema", + "Zuzana" +]
\ No newline at end of file diff --git a/data/world/last-names.json b/data/world/last-names.json new file mode 100644 index 0000000..4ea9acb --- /dev/null +++ b/data/world/last-names.json @@ -0,0 +1,4948 @@ +[ + "Aaberg", + "Aalst", + "Aara", + "Aaren", + "Aarika", + "Aaron", + "Aaronson", + "Ab", + "Aba", + "Abad", + "Abagael", + "Abagail", + "Abana", + "Abate", + "Abba", + "Abbate", + "Abbe", + "Abbey", + "Abbi", + "Abbie", + "Abbot", + "Abbotsen", + "Abbotson", + "Abbotsun", + "Abbott", + "Abbottson", + "Abby", + "Abbye", + "Abdel", + "Abdella", + "Abdu", + "Abdul", + "Abdulla", + "Abe", + "Abebi", + "Abel", + "Abelard", + "Abell", + "Abercromby", + "Abernathy", + "Abernon", + "Abert", + "Abeu", + "Abey", + "Abie", + "Abigael", + "Abigail", + "Abigale", + "Abijah", + "Abisha", + "Abisia", + "Abixah", + "Abner", + "Aborn", + "Abott", + "Abra", + "Abraham", + "Abrahams", + "Abrahamsen", + "Abrahan", + "Abram", + "Abramo", + "Abrams", + "Abramson", + "Abran", + "Abroms", + "Absa", + "Absalom", + "Abshier", + "Acacia", + "Acalia", + "Accalia", + "Ace", + "Acey", + "Acherman", + "Achilles", + "Achorn", + "Acie", + "Acima", + "Acker", + "Ackerley", + "Ackerman", + "Ackler", + "Ackley", + "Acquah", + "Acus", + "Ad", + "Ada", + "Adabel", + "Adabelle", + "Adachi", + "Adah", + "Adaha", + "Adai", + "Adaiha", + "Adair", + "Adal", + "Adala", + "Adalai", + "Adalard", + "Adalbert", + "Adalheid", + "Adali", + "Adalia", + "Adaliah", + "Adalie", + "Adaline", + "Adall", + "Adallard", + "Adam", + "Adama", + "Adamec", + "Adamek", + "Adamik", + "Adamina", + "Adaminah", + "Adamis", + "Adamo", + "Adamok", + "Adams", + "Adamsen", + "Adamski", + "Adamson", + "Adamsun", + "Adan", + "Adao", + "Adar", + "Adara", + "Adaurd", + "Aday", + "Adda", + "Addam", + "Addi", + "Addia", + "Addie", + "Addiego", + "Addiel", + "Addis", + "Addison", + "Addy", + "Ade", + "Adebayo", + "Adel", + "Adela", + "Adelaida", + "Adelaide", + "Adelaja", + "Adelbert", + "Adele", + "Adelheid", + "Adelia", + "Adelice", + "Adelina", + "Adelind", + "Adeline", + "Adella", + "Adelle", + "Adelpho", + "Adelric", + "Adena", + "Ader", + "Adest", + "Adey", + "Adham", + "Adhamh", + "Adhern", + "Adi", + "Adiana", + "Adiel", + "Adiell", + "Adigun", + "Adila", + "Adim", + "Adin", + "Adina", + "Adine", + "Adis", + "Adkins", + "Adlai", + "Adlar", + "Adlare", + "Adlay", + "Adlee", + "Adlei", + "Adler", + "Adley", + "Adna", + "Adnah", + "Adne", + "Adnopoz", + "Ado", + "Adolf", + "Adolfo", + "Adolph", + "Adolphe", + "Adolpho", + "Adolphus", + "Adon", + "Adonis", + "Adora", + "Adore", + "Adoree", + "Adorl", + "Adorne", + "Adrea", + "Adrell", + "Adria", + "Adriaens", + "Adrial", + "Adrian", + "Adriana", + "Adriane", + "Adrianna", + "Adrianne", + "Adriano", + "Adriel", + "Adriell", + "Adrien", + "Adriena", + "Adriene", + "Adrienne", + "Adur", + "Aekerly", + "Aelber", + "Aenea", + "Aeneas", + "Aeneus", + "Aeniah", + "Aenneea", + "Aeriel", + "Aeriela", + "Aeriell", + "Affer", + "Affra", + "Affrica", + "Afra", + "Africa", + "Africah", + "Afrika", + "Afrikah", + "Afton", + "Ag", + "Agace", + "Agamemnon", + "Agan", + "Agata", + "Agate", + "Agatha", + "Agathe", + "Agathy", + "Agbogla", + "Agee", + "Aggappe", + "Aggappera", + "Aggappora", + "Aggarwal", + "Aggi", + "Aggie", + "Aggri", + "Aggy", + "Agle", + "Agler", + "Agna", + "Agnella", + "Agnes", + "Agnese", + "Agnesse", + "Agneta", + "Agnew", + "Agnola", + "Agostino", + "Agosto", + "Agretha", + "Agripina", + "Agrippina", + "Aguayo", + "Agueda", + "Aguie", + "Aguste", + "Agustin", + "Ahab", + "Aharon", + "Ahasuerus", + "Ahders", + "Ahearn", + "Ahern", + "Ahl", + "Ahlgren", + "Ahmad", + "Ahmar", + "Ahmed", + "Ahola", + "Aholah", + "Aholla", + "Ahoufe", + "Ahouh", + "Ahrendt", + "Ahrens", + "Ahron", + "Aia", + "Aida", + "Aidan", + "Aiden", + "Aiello", + "Aigneis", + "Aiken", + "Aila", + "Ailbert", + "Aile", + "Ailee", + "Aileen", + "Ailene", + "Ailey", + "Aili", + "Ailin", + "Ailina", + "Ailis", + "Ailsa", + "Ailssa", + "Ailsun", + "Ailyn", + "Aime", + "Aimee", + "Aimil", + "Aimo", + "Aindrea", + "Ainslee", + "Ainsley", + "Ainslie", + "Ainsworth", + "Airel", + "Aires", + "Airla", + "Airlee", + "Airlia", + "Airliah", + "Airlie", + "Aisha", + "Ajani", + "Ajax", + "Ajay", + "Ajit", + "Akanke", + "Akel", + "Akela", + "Aker", + "Akerboom", + "Akerley", + "Akers", + "Akeyla", + "Akeylah", + "Akili", + "Akim", + "Akin", + "Akins", + "Akira", + "Aklog", + "Aksel", + "Aksoyn", + "Al", + "Alabaster", + "Alage", + "Alain", + "Alaine", + "Alair", + "Alake", + "Alameda", + "Alan", + "Alana", + "Alanah", + "Aland", + "Alane", + "Alanna", + "Alano", + "Alansen", + "Alanson", + "Alard", + "Alaric", + "Alarice", + "Alarick", + "Alarise", + "Alasdair", + "Alastair", + "Alasteir", + "Alaster", + "Alatea", + "Alathia", + "Alayne", + "Alba", + "Alban", + "Albarran", + "Albemarle", + "Alben", + "Alber", + "Alberic", + "Alberik", + "Albers", + "Albert", + "Alberta", + "Albertina", + "Albertine", + "Alberto", + "Albertson", + "Albie", + "Albin", + "Albina", + "Albion", + "Alboran", + "Albrecht", + "Albric", + "Albright", + "Albur", + "Alburg", + "Alburga", + "Alby", + "Alcina", + "Alcine", + "Alcinia", + "Alcock", + "Alcot", + "Alcott", + "Alcus", + "Alda", + "Aldarcie", + "Aldarcy", + "Aldas", + "Alded", + "Alden", + "Aldercy", + "Alderman", + "Alderson", + "Aldin", + "Aldis", + "Aldo", + "Aldon", + "Aldora", + "Aldos", + "Aldous", + "Aldred", + "Aldredge", + "Aldric", + "Aldrich", + "Aldridge", + "Alduino", + "Aldus", + "Aldwin", + "Aldwon", + "Alec", + "Alecia", + "Aleck", + "Aleda", + "Aleece", + "Aleedis", + "Aleen", + "Aleetha", + "Alegre", + "Alejandra", + "Alejandrina", + "Alejandro", + "Alejo", + "Alejoa", + "Alek", + "Aleksandr", + "Alena", + "Alene", + "Alenson", + "Aleras", + "Aleris", + "Aleron", + "Alesandrini", + "Alessandra", + "Alessandro", + "Aleta", + "Aletha", + "Alethea", + "Alethia", + "Aletta", + "Alex", + "Alexa", + "Alexander", + "Alexandr", + "Alexandra", + "Alexandre", + "Alexandria", + "Alexandrina", + "Alexandro", + "Alexandros", + "Alexei", + "Alexi", + "Alexia", + "Alexina", + "Alexine", + "Alexio", + "Alexis", + "Aley", + "Aleydis", + "Alf", + "Alfeus", + "Alfi", + "Alfie", + "Alfons", + "Alfonse", + "Alfonso", + "Alfonzo", + "Alford", + "Alfred", + "Alfreda", + "Alfredo", + "Alfy", + "Algar", + "Alger", + "Algernon", + "Algie", + "Alguire", + "Algy", + "Ali", + "Alia", + "Aliber", + "Alic", + "Alica", + "Alice", + "Alicea", + "Alicia", + "Alick", + "Alida", + "Alidia", + "Alidis", + "Alidus", + "Alie", + "Alika", + "Alikee", + "Alina", + "Aline", + "Alinna", + "Alis", + "Alisa", + "Alisan", + "Alisander", + "Alisen", + "Alisha", + "Alisia", + "Alison", + "Alissa", + "Alistair", + "Alister", + "Alisun", + "Alita", + "Alitha", + "Alithea", + "Alithia", + "Alitta", + "Alius", + "Alix", + "Aliza", + "Alla", + "Allain", + "Allan", + "Allana", + "Allanson", + "Allard", + "Allare", + "Allayne", + "Allbee", + "Allcot", + "Alleen", + "Allegra", + "Allen", + "Allene", + "Alleras", + "Allerie", + "Alleris", + "Allerus", + "Alley", + "Alleyn", + "Alleyne", + "Alli", + "Allianora", + "Alliber", + "Allie", + "Allin", + "Allina", + "Allis", + "Allisan", + "Allison", + "Allissa", + "Allista", + "Allister", + "Allistir", + "Allix", + "Allmon", + "Allred", + "Allrud", + "Allsopp", + "Allsun", + "Allveta", + "Allwein", + "Allx", + "Ally", + "Allyce", + "Allyn", + "Allys", + "Allyson", + "Alma", + "Almallah", + "Almeda", + "Almeeta", + "Almeida", + "Almena", + "Almeria", + "Almeta", + "Almira", + "Almire", + "Almita", + "Almond", + "Almund", + "Alo", + "Alodee", + "Alodi", + "Alodie", + "Aloin", + "Aloise", + "Aloisia", + "Aloisius", + "Aloke", + "Alon", + "Alonso", + "Alonzo", + "Aloysia", + "Aloysius", + "Alper", + "Alpers", + "Alpert", + "Alphard", + "Alpheus", + "Alphonsa", + "Alphonse", + "Alphonsine", + "Alphonso", + "AlrZc", + "Alric", + "Alrich", + "Alrick", + "Alroi", + "Alroy", + "Also", + "Alston", + "Alsworth", + "Alta", + "Altaf", + "Alten", + "Althea", + "Althee", + "Altheta", + "Altis", + "Altman", + "Alton", + "Aluin", + "Aluino", + "Alurd", + "Alurta", + "Alva", + "Alvan", + "Alvar", + "Alvarez", + "Alver", + "Alvera", + "Alverson", + "Alverta", + "Alves", + "Alveta", + "Alviani", + "Alvie", + "Alvin", + "Alvina", + "Alvinia", + "Alvira", + "Alvis", + "Alvita", + "Alvord", + "Alvy", + "Alwin", + "Alwitt", + "Alwyn", + "Alyce", + "Alyda", + "Alyose", + "Alyosha", + "Alys", + "Alysa", + "Alyse", + "Alysia", + "Alyson", + "Alysoun", + "Alyss", + "Alyssa", + "Alyworth", + "Ama", + "Amabel", + "Amabelle", + "Amabil", + "Amadas", + "Amadeo", + "Amadeus", + "Amadis", + "Amado", + "Amador", + "Amadus", + "Amal", + "Amalbena", + "Amalberga", + "Amalbergas", + "Amalburga", + "Amalea", + "Amalee", + "Amaleta", + "Amalia", + "Amalie", + "Amalita", + "Amalle", + "Aman", + "Amand", + "Amanda", + "Amandi", + "Amandie", + "Amando", + "Amandy", + "Amann", + "Amar", + "Amara", + "Amaral", + "Amaras", + "Amarette", + "Amargo", + "Amari", + "Amarillas", + "Amarillis", + "Amaris", + "Amary", + "Amaryl", + "Amaryllis", + "Amasa", + "Amata", + "Amathist", + "Amathiste", + "Amati", + "Amato", + "Amatruda", + "Amaty", + "Amber", + "Amberly", + "Ambert", + "Ambie", + "Amble", + "Ambler", + "Ambrogino", + "Ambrogio", + "Ambros", + "Ambrosane", + "Ambrose", + "Ambrosi", + "Ambrosia", + "Ambrosine", + "Ambrosio", + "Ambrosius", + "Ambur", + "Amby", + "Ame", + "Amedeo", + "Amelia", + "Amelie", + "Amelina", + "Ameline", + "Amelita", + "Amena", + "Amend", + "Amerigo", + "Amero", + "Amersham", + "Amery", + "Ames", + "Amethist", + "Amethyst", + "Ami", + "Amias", + "Amice", + "Amick", + "Amie", + "Amiel", + "Amieva", + "Amii", + "Amil", + "Amin", + "Aminta", + "Amir", + "Amitie", + "Amity", + "Amling", + "Ammadas", + "Ammadis", + "Ammamaria", + "Ammann", + "Ammon", + "Amoakuh", + "Amor", + "Amora", + "Amoreta", + "Amorete", + "Amorette", + "Amorita", + "Amoritta", + "Amory", + "Amos", + "Amr", + "Amrita", + "Amsden", + "Amund", + "Amy", + "Amyas", + "Amye", + "Am�lie", + "An", + "Ana", + "Anabal", + "Anabel", + "Anabella", + "Anabelle", + "Anagnos", + "Analiese", + "Analise", + "Anallese", + "Anallise", + "Anana", + "Ananna", + "Anastas", + "Anastase", + "Anastasia", + "Anastasie", + "Anastasio", + "Anastasius", + "Anastassia", + "Anastatius", + "Anastice", + "Anastos", + "Anatol", + "Anatola", + "Anatole", + "Anatolio", + "Anatollo", + "Ancalin", + "Ancel", + "Ancelin", + "Anceline", + "Ancell", + "Anchie", + "Ancier", + "Ancilin", + "Andee", + "Andeee", + "Andel", + "Ander", + "Anderea", + "Anderegg", + "Anderer", + "Anders", + "Andersen", + "Anderson", + "Andert", + "Andi", + "Andie", + "Andonis", + "Andra", + "Andrade", + "Andras", + "Andre", + "Andrea", + "Andreana", + "Andreas", + "Andree", + "Andrei", + "Andrej", + "Andrel", + "Andres", + "Andrew", + "Andrews", + "Andrey", + "Andri", + "Andria", + "Andriana", + "Andrien", + "Andriette", + "Andris", + "Andromache", + "Andromada", + "Andromeda", + "Andromede", + "Andros", + "Androw", + "Andrus", + "Andryc", + "Andy", + "Anestassia", + "Anet", + "Anett", + "Anetta", + "Anette", + "Aney", + "Angadreme", + "Angadresma", + "Ange", + "Angel", + "Angela", + "Angele", + "Angeli", + "Angelia", + "Angelica", + "Angelico", + "Angelika", + "Angelina", + "Angeline", + "Angelique", + "Angelis", + "Angelita", + "Angell", + "Angelle", + "Angelo", + "Angi", + "Angie", + "Angil", + "Angle", + "Anglim", + "Anglo", + "Angrist", + "Angus", + "Angy", + "Anh", + "Ania", + "Aniakudo", + "Anica", + "Aniela", + "Anil", + "Anis", + "Anissa", + "Anita", + "Anitra", + "Aniweta", + "Anjali", + "Anjanette", + "Anjela", + "Ankeny", + "Ankney", + "Ann", + "Ann-Marie", + "Anna", + "Anna-Diana", + "Anna-Diane", + "Anna-Maria", + "Annabal", + "Annabel", + "Annabela", + "Annabell", + "Annabella", + "Annabelle", + "Annadiana", + "Annadiane", + "Annalee", + "Annaliese", + "Annalise", + "Annamaria", + "Annamarie", + "Anne", + "Anne-Corinne", + "Anne-Marie", + "Annecorinne", + "Anneliese", + "Annelise", + "Annemarie", + "Annetta", + "Annette", + "Anni", + "Annia", + "Annice", + "Annie", + "Anniken", + "Annis", + "Annissa", + "Annmaria", + "Annmarie", + "Annnora", + "Annora", + "Annorah", + "Annunciata", + "Anny", + "Anora", + "Anse", + "Ansel", + "Ansela", + "Ansell", + "Anselm", + "Anselma", + "Anselme", + "Anselmi", + "Anselmo", + "Ansilma", + "Ansilme", + "Ansley", + "Anson", + "Anstice", + "Anstus", + "Antebi", + "Anthe", + "Anthea", + "Anthia", + "Anthiathia", + "Anthony", + "Antin", + "Antipas", + "Antipus", + "Antoine", + "Antoinetta", + "Antoinette", + "Anton", + "Antone", + "Antonella", + "Antonetta", + "Antoni", + "Antonia", + "Antonie", + "Antonietta", + "Antonin", + "Antonina", + "Antonino", + "Antonio", + "Antonius", + "Antons", + "Antony", + "Antrim", + "Anurag", + "Anuska", + "Any", + "Anya", + "Anyah", + "Anzovin", + "Apfel", + "Apfelstadt", + "Apgar", + "Aphra", + "Aphrodite", + "Apicella", + "Apollo", + "Apollus", + "Apostles", + "Appel", + "Apple", + "Appleby", + "Appledorf", + "Applegate", + "Appleton", + "Appolonia", + "Apps", + "April", + "Aprile", + "Aprilette", + "Apthorp", + "Apul", + "Ara", + "Arabeila", + "Arabel", + "Arabela", + "Arabele", + "Arabella", + "Arabelle", + "Arad", + "Arakawa", + "Araldo", + "Aramanta", + "Aramen", + "Aramenta", + "Araminta", + "Aran", + "Arand", + "Arathorn", + "Arbe", + "Arber", + "Arbuckle", + "Arch", + "Archaimbaud", + "Archambault", + "Archangel", + "Archer", + "Archibald", + "Archibaldo", + "Archibold", + "Archie", + "Archle", + "Archy", + "Ard", + "Arda", + "Ardath", + "Arde", + "Ardeen", + "Ardeha", + "Ardehs", + "Ardel", + "Ardelia", + "Ardelis", + "Ardell", + "Ardella", + "Ardelle", + "Arden", + "Ardene", + "Ardenia", + "Ardeth", + "Ardie", + "Ardin", + "Ardine", + "Ardis", + "Ardisj", + "Ardith", + "Ardme", + "Ardolino", + "Ardra", + "Ardrey", + "Ardussi", + "Ardy", + "Ardyce", + "Ardys", + "Ardyth", + "Arel", + "Arela", + "Arella", + "Arelus", + "Aret", + "Areta", + "Aretha", + "Aretina", + "Aretta", + "Arette", + "Arezzini", + "Argent", + "Argile", + "Argus", + "Argyle", + "Argyres", + "Arhna", + "Ari", + "Aria", + "Ariadne", + "Ariana", + "Ariane", + "Arianie", + "Arianna", + "Arianne", + "Aribold", + "Aric", + "Arica", + "Arick", + "Aridatha", + "Arie", + "Ariel", + "Ariela", + "Ariella", + "Arielle", + "Ariew", + "Arin", + "Ario", + "Arissa", + "Aristotle", + "Arita", + "Arjan", + "Arjun", + "Ark", + "Arlan", + "Arlana", + "Arlee", + "Arleen", + "Arlen", + "Arlena", + "Arlene", + "Arleta", + "Arlette", + "Arley", + "Arleyne", + "Arlie", + "Arliene", + "Arlin", + "Arlina", + "Arlinda", + "Arline", + "Arlo", + "Arlon", + "Arluene", + "Arly", + "Arlyn", + "Arlyne", + "Arlynne", + "Armalda", + "Armalla", + "Armallas", + "Arman", + "Armand", + "Armanda", + "Armando", + "Armbrecht", + "Armbruster", + "Armelda", + "Armil", + "Armilda", + "Armilla", + "Armillas", + "Armillda", + "Armillia", + "Armin", + "Armington", + "Armitage", + "Armond", + "Armstrong", + "Armyn", + "Arnaldo", + "Arnaud", + "Arndt", + "Arne", + "Arnelle", + "Arney", + "Arni", + "Arnie", + "Arno", + "Arnold", + "Arnoldo", + "Arnon", + "Arnst", + "Arnuad", + "Arnulfo", + "Arny", + "Arola", + "Aron", + "Arondel", + "Arondell", + "Aronoff", + "Aronow", + "Aronson", + "Arquit", + "Arratoon", + "Arri", + "Arria", + "Arrio", + "Arron", + "Arst", + "Art", + "Arta", + "Artair", + "Artamas", + "Arte", + "Artema", + "Artemas", + "Artemis", + "Artemisa", + "Artemisia", + "Artemus", + "Arther", + "Arthur", + "Artie", + "Artima", + "Artimas", + "Artina", + "Artur", + "Arturo", + "Artus", + "Arty", + "Aruabea", + "Arun", + "Arundel", + "Arundell", + "Arv", + "Arva", + "Arvad", + "Arvell", + "Arvid", + "Arvie", + "Arvin", + "Arvind", + "Arvo", + "Arvonio", + "Arvy", + "Ary", + "Aryn", + "As", + "Asa", + "Asabi", + "Asante", + "Asaph", + "Asare", + "Aschim", + "Ase", + "Asel", + "Ash", + "Asha", + "Ashbaugh", + "Ashbey", + "Ashby", + "Ashelman", + "Ashely", + "Asher", + "Ashford", + "Ashia", + "Ashien", + "Ashil", + "Ashjian", + "Ashla", + "Ashlan", + "Ashlee", + "Ashleigh", + "Ashlen", + "Ashley", + "Ashli", + "Ashlie", + "Ashlin", + "Ashling", + "Ashly", + "Ashman", + "Ashmead", + "Ashok", + "Ashraf", + "Ashti", + "Ashton", + "Ashwell", + "Ashwin", + "Asia", + "Askari", + "Askwith", + "Aslam", + "Asp", + "Aspa", + "Aspasia", + "Aspia", + "Asquith", + "Assisi", + "Asta", + "Astera", + "Asteria", + "Astor", + "Astra", + "Astraea", + "Astrahan", + "Astrea", + "Astred", + "Astri", + "Astrid", + "Astrix", + "Astto", + "Asuncion", + "Atal", + "Atalanta", + "Atalante", + "Atalanti", + "Atalaya", + "Atalayah", + "Atalee", + "Ataliah", + "Atalie", + "Atalya", + "Atcliffe", + "Athal", + "Athalee", + "Athalia", + "Athalie", + "Athalla", + "Athallia", + "Athelstan", + "Athena", + "Athene", + "Athenian", + "Athey", + "Athiste", + "Atiana", + "Atkins", + "Atkinson", + "Atlanta", + "Atlante", + "Atlas", + "Atlee", + "Atonsah", + "Atrice", + "Atronna", + "Attah", + "Attalanta", + "Attalie", + "Attenborough", + "Attenweiler", + "Atterbury", + "Atthia", + "Attlee", + "Attwood", + "Atul", + "Atwater", + "Atwekk", + "Atwood", + "Atworth", + "Au", + "Aubarta", + "Aube", + "Auberbach", + "Auberon", + "Aubert", + "Auberta", + "Aubigny", + "Aubin", + "Aubine", + "Aubree", + "Aubreir", + "Aubrette", + "Aubrey", + "Aubrie", + "Aubry", + "Auburn", + "Auburta", + "Aubyn", + "Audette", + "Audi", + "Audie", + "Audley", + "Audly", + "Audra", + "Audras", + "Audre", + "Audres", + "Audrey", + "Audri", + "Audrie", + "Audris", + "Audrit", + "Audry", + "Audrye", + "Audsley", + "Audun", + "Audwen", + "Audwin", + "Audy", + "Auerbach", + "Aufmann", + "Augie", + "August", + "Augusta", + "Auguste", + "Augustin", + "Augustina", + "Augustine", + "Augusto", + "Augustus", + "Augy", + "Aulea", + "Auliffe", + "Aun", + "Aundrea", + "Aunson", + "Aura", + "Aurea", + "Aurel", + "Aurelea", + "Aurelia", + "Aurelie", + "Aurelio", + "Aurelius", + "Auria", + "Auric", + "Aurie", + "Aurilia", + "Aurita", + "Aurlie", + "Auroora", + "Aurora", + "Aurore", + "Aurthur", + "Ause", + "Austen", + "Austin", + "Austina", + "Austine", + "Auston", + "Australia", + "Austreng", + "Autrey", + "Autry", + "Autum", + "Autumn", + "Auvil", + "Av", + "Ava", + "Avan", + "Avaria", + "Ave", + "Avelin", + "Aveline", + "Avera", + "Averell", + "Averi", + "Averil", + "Averill", + "Averir", + "Avery", + "Averyl", + "Avi", + "Avictor", + "Avie", + "Avigdor", + "Avilla", + "Avis", + "Avitzur", + "Aviv", + "Aviva", + "Avivah", + "Avner", + "Avra", + "Avraham", + "Avram", + "Avril", + "Avrit", + "Avrom", + "Avron", + "Avruch", + "Awad", + "Ax", + "Axe", + "Axel", + "Aylmar", + "Aylmer", + "Aylsworth", + "Aylward", + "Aymer", + "Ayn", + "Aynat", + "Ayo", + "Ayres", + "Azal", + "Azalea", + "Azaleah", + "Azar", + "Azarcon", + "Azaria", + "Azarria", + "Azelea", + "Azeria", + "Aziza", + "Azpurua", + "Azral", + "Azriel", + "Baal", + "Baalbeer", + "Baalman", + "Bab", + "Babara", + "Babb", + "Babbette", + "Babbie", + "Babby", + "Babcock", + "Babette", + "Babita", + "Babs", + "Bac", + "Bacchus", + "Bach", + "Bachman", + "Backer", + "Backler", + "Bacon", + "Badger", + "Badr", + "Baecher", + "Bael", + "Baelbeer", + "Baer", + "Baerl", + "Baerman", + "Baese", + "Bagger", + "Baggett", + "Baggott", + "Baggs", + "Bagley", + "Bahner", + "Bahr", + "Baiel", + "Bail", + "Bailar", + "Bailey", + "Bailie", + "Baillie", + "Baillieu", + "Baily", + "Bain", + "Bainbridge", + "Bainbrudge", + "Bainter", + "Baird", + "Baiss", + "Bajaj", + "Bak", + "Bakeman", + "Bakemeier", + "Baker", + "Bakerman", + "Bakki", + "Bal", + "Bala", + "Balas", + "Balbinder", + "Balbur", + "Balcer", + "Balch", + "Balcke", + "Bald", + "Baldridge", + "Balduin", + "Baldwin", + "Bale", + "Baler", + "Balf", + "Balfore", + "Balfour", + "Balkin", + "Ball", + "Ballard", + "Balliett", + "Balling", + "Ballinger", + "Balliol", + "Ballman", + "Ballou", + "Balmuth", + "Balough", + "Balsam", + "Balthasar", + "Balthazar", + "Bamberger", + "Bambi", + "Bambie", + "Bamby", + "Bamford", + "Ban", + "Bancroft", + "Bandeen", + "Bander", + "Bandler", + "Bandur", + "Banebrudge", + "Banerjee", + "Bang", + "Bank", + "Banks", + "Banky", + "Banna", + "Bannasch", + "Bannerman", + "Bannister", + "Bannon", + "Banquer", + "Banwell", + "Baptist", + "Baptista", + "Baptiste", + "Baptlsta", + "Bar", + "Bara", + "Barabas", + "Barabbas", + "Baram", + "Baras", + "Barayon", + "Barb", + "Barbabas", + "Barbabra", + "Barbara", + "Barbara-Anne", + "Barbaraanne", + "Barbarese", + "Barbaresi", + "Barbe", + "Barbee", + "Barber", + "Barbette", + "Barbey", + "Barbi", + "Barbie", + "Barbour", + "Barboza", + "Barbra", + "Barbur", + "Barbuto", + "Barby", + "Barcellona", + "Barclay", + "Barcot", + "Barcroft", + "Barcus", + "Bard", + "Barde", + "Barden", + "Bardo", + "Barfuss", + "Barger", + "Bari", + "Barimah", + "Barina", + "Barker", + "Barkley", + "Barling", + "Barlow", + "Barmen", + "Barn", + "Barna", + "Barnaba", + "Barnabas", + "Barnabe", + "Barnaby", + "Barnard", + "Barncard", + "Barnebas", + "Barnes", + "Barnet", + "Barnett", + "Barney", + "Barnie", + "Barnum", + "Barny", + "Barolet", + "Baron", + "Barr", + "Barra", + "Barrada", + "Barram", + "Barraza", + "Barren", + "Barret", + "Barrett", + "Barri", + "Barrie", + "Barrington", + "Barris", + "Barron", + "Barrow", + "Barrus", + "Barry", + "Barsky", + "Barstow", + "Bart", + "Barta", + "Bartel", + "Barth", + "Barthel", + "Barthelemy", + "Barthol", + "Barthold", + "Bartholemy", + "Bartholomeo", + "Bartholomeus", + "Bartholomew", + "Bartie", + "Bartko", + "Bartle", + "Bartlet", + "Bartlett", + "Bartley", + "Bartolemo", + "Bartolome", + "Bartolomeo", + "Barton", + "Bartosch", + "Bartram", + "Barty", + "Baruch", + "Barvick", + "Bary", + "Baryram", + "Bascio", + "Bascomb", + "Base", + "Baseler", + "Basham", + "Bashee", + "Bashemath", + "Bashemeth", + "Bashuk", + "Basia", + "Basil", + "Basile", + "Basilio", + "Basilius", + "Basir", + "Baskett", + "Bass", + "Basset", + "Bassett", + "Basso", + "Bast", + "Bastian", + "Bastien", + "Bat", + "Batchelor", + "Bate", + "Baten", + "Bates", + "Batha", + "Bathelda", + "Bathesda", + "Bathilda", + "Batholomew", + "Bathsheb", + "Bathsheba", + "Bathsheeb", + "Bathulda", + "Batish", + "Batista", + "Batory", + "Batruk", + "Batsheva", + "Battat", + "Battista", + "Battiste", + "Batty", + "Baudelaire", + "Baudin", + "Baudoin", + "Bauer", + "Baugh", + "Baum", + "Baumann", + "Baumbaugh", + "Baun", + "Bausch", + "Bauske", + "Bautista", + "Bautram", + "Bax", + "Baxie", + "Baxter", + "Baxy", + "Bay", + "Bayard", + "Bayer", + "Bayless", + "Baylor", + "Bayly", + "Baynebridge", + "Bazar", + "Bazil", + "Bazluke", + "Bea", + "Beach", + "Beacham", + "Beal", + "Beale", + "Beall", + "Bealle", + "Bean", + "Beane", + "Beaner", + "Bear", + "Bearce", + "Beard", + "Beare", + "Bearnard", + "Beasley", + "Beaston", + "Beata", + "Beatrice", + "Beatrisa", + "Beatrix", + "Beatriz", + "Beattie", + "Beatty", + "Beau", + "Beauchamp", + "Beaudoin", + "Beaufert", + "Beaufort", + "Beaulieu", + "Beaumont", + "Beauregard", + "Beauvais", + "Beaver", + "Bebe", + "Beberg", + "Becca", + "Bechler", + "Becht", + "Beck", + "Becka", + "Becker", + "Beckerman", + "Becket", + "Beckett", + "Becki", + "Beckie", + "Beckman", + "Becky", + "Bedad", + "Bedelia", + "Bedell", + "Bedwell", + "Bee", + "Beebe", + "Beeck", + "Beedon", + "Beekman", + "Beera", + "Beesley", + "Beeson", + "Beetner", + "Beffrey", + "Bega", + "Begga", + "Beghtol", + "Behah", + "Behka", + "Behl", + "Behlau", + "Behlke", + "Behm", + "Behn", + "Behnken", + "Behre", + "Behrens", + "Beichner", + "Beilul", + "Bein", + "Beisel", + "Beitch", + "Beitnes", + "Beitris", + "Beitz", + "Beka", + "Bekah", + "Bekelja", + "Beker", + "Bekha", + "Bekki", + "Bel", + "Bela", + "Belak", + "Belamy", + "Belanger", + "Belayneh", + "Belcher", + "Belda", + "Belden", + "Belding", + "Belen", + "Belford", + "Belia", + "Belicia", + "Belier", + "Belinda", + "Belita", + "Bell", + "Bella", + "Bellamy", + "Bellanca", + "Bellaude", + "Bellda", + "Belldame", + "Belldas", + "Belle", + "Beller", + "Bellew", + "Bellina", + "Bellis", + "Bello", + "Belloir", + "Belmonte", + "Belshin", + "Belsky", + "Belter", + "Beltran", + "Belva", + "Belvia", + "Ben", + "Bena", + "Bencion", + "Benco", + "Bender", + "Bendick", + "Bendicta", + "Bendicty", + "Bendite", + "Bendix", + "Benedetta", + "Benedetto", + "Benedic", + "Benedick", + "Benedict", + "Benedicta", + "Benedicto", + "Benedikt", + "Benedikta", + "Benedix", + "Benenson", + "Benetta", + "Benge", + "Bengt", + "Benia", + "Beniamino", + "Benil", + "Benilda", + "Benildas", + "Benildis", + "Benioff", + "Benis", + "Benisch", + "Benita", + "Benito", + "Benjamen", + "Benjamin", + "Benji", + "Benjie", + "Benjy", + "Benkley", + "Benn", + "Bennet", + "Bennett", + "Benni", + "Bennie", + "Bennink", + "Bennion", + "Bennir", + "Benny", + "Benoit", + "Benoite", + "Bensen", + "Bensky", + "Benson", + "Bent", + "Bentlee", + "Bentley", + "Bently", + "Benton", + "Benyamin", + "Benzel", + "Beora", + "Beore", + "Ber", + "Berard", + "Berardo", + "Berck", + "Berenice", + "Beret", + "Berey", + "Berfield", + "Berg", + "Berga", + "Bergeman", + "Bergen", + "Berger", + "Bergerac", + "Bergeron", + "Bergess", + "Berget", + "Bergh", + "Berghoff", + "Bergin", + "Berglund", + "Bergman", + "Bergmann", + "Bergmans", + "Bergquist", + "Bergren", + "Bergstein", + "Bergstrom", + "Bergwall", + "Berhley", + "Berk", + "Berke", + "Berkeley", + "Berkie", + "Berkin", + "Berkley", + "Berkly", + "Berkman", + "Berkow", + "Berkshire", + "Berky", + "Berl", + "Berlauda", + "Berlin", + "Berlinda", + "Berliner", + "Berlyn", + "Berman", + "Bern", + "Berna", + "Bernadene", + "Bernadette", + "Bernadina", + "Bernadine", + "Bernard", + "Bernardi", + "Bernardina", + "Bernardine", + "Bernardo", + "Bernarr", + "Bernat", + "Berne", + "Bernelle", + "Berner", + "Berners", + "Berneta", + "Bernete", + "Bernetta", + "Bernette", + "Bernhard", + "Berni", + "Bernice", + "Bernie", + "Bernita", + "Bernj", + "Berns", + "Bernstein", + "Bernt", + "Berny", + "Berri", + "Berrie", + "Berriman", + "Berry", + "Berstine", + "Bert", + "Berta", + "Bertasi", + "Berte", + "Bertelli", + "Bertero", + "Bertha", + "Berthe", + "Berthold", + "Berthoud", + "Berti", + "Bertie", + "Bertila", + "Bertilla", + "Bertina", + "Bertine", + "Bertle", + "Bertold", + "Bertolde", + "Berton", + "Bertram", + "Bertrand", + "Bertrando", + "Bertsche", + "Berty", + "Berwick", + "Beryl", + "Beryle", + "Beshore", + "Besnard", + "Bess", + "Besse", + "Bessie", + "Bessy", + "Best", + "Beth", + "Bethanne", + "Bethany", + "Bethel", + "Bethena", + "Bethesda", + "Bethesde", + "Bethezel", + "Bethina", + "Betsey", + "Betsy", + "Betta", + "Bette", + "Bette-Ann", + "Betteann", + "Betteanne", + "Bettencourt", + "Betthel", + "Betthezel", + "Betthezul", + "Betti", + "Bettina", + "Bettine", + "Betty", + "Bettye", + "Bettzel", + "Betz", + "Beulah", + "Beuthel", + "Beutler", + "Beutner", + "Bev", + "Bevan", + "Bevash", + "Bever", + "Beverie", + "Beverle", + "Beverlee", + "Beverley", + "Beverlie", + "Beverly", + "Bevers", + "Bevin", + "Bevis", + "Bevon", + "Bevus", + "Bevvy", + "Beyer", + "Bezanson", + "Bhatt", + "Bhayani", + "Biagi", + "Biagio", + "Biamonte", + "Bianca", + "Biancha", + "Bianchi", + "Bianka", + "Bibbie", + "Bibby", + "Bibbye", + "Bibeau", + "Bibi", + "Bible", + "Bick", + "Bickart", + "Bicknell", + "Biddick", + "Biddie", + "Biddle", + "Biddy", + "Bidget", + "Bidle", + "Biebel", + "Biegel", + "Bierman", + "Biernat", + "Bigelow", + "Bigford", + "Bigg", + "Biggs", + "Bigler", + "Bigner", + "Bigod", + "Bigot", + "Bik", + "Bikales", + "Bil", + "Bilbe", + "Bilek", + "Biles", + "Bili", + "Bilicki", + "Bill", + "Billat", + "Bille", + "Billen", + "Billi", + "Billie", + "Billmyre", + "Bills", + "Billy", + "Billye", + "Bilow", + "Bilski", + "Bina", + "Binah", + "Bindman", + "Binetta", + "Binette", + "Bing", + "Bink", + "Binky", + "Binni", + "Binnie", + "Binnings", + "Binny", + "Biondo", + "Birch", + "Birchard", + "Birck", + "Bird", + "Birdella", + "Birdie", + "Birdt", + "Birecree", + "Birgit", + "Birgitta", + "Birk", + "Birkett", + "Birkle", + "Birkner", + "Birmingham", + "Biron", + "Bish", + "Bishop", + "Bissell", + "Bisset", + "Bithia", + "Bittencourt", + "Bitthia", + "Bittner", + "Bivins", + "Bixby", + "Bixler", + "Bjork", + "Bjorn", + "Black", + "Blackburn", + "Blackington", + "Blackman", + "Blackmore", + "Blackmun", + "Blackstock", + "Blackwell", + "Blader", + "Blain", + "Blaine", + "Blainey", + "Blair", + "Blaire", + "Blaise", + "Blake", + "Blakelee", + "Blakeley", + "Blakely", + "Blalock", + "Blanc", + "Blanca", + "Blanch", + "Blancha", + "Blanchard", + "Blanche", + "Blanchette", + "Bland", + "Blandina", + "Blanding", + "Blane", + "Blank", + "Blanka", + "Blankenship", + "Blas", + "Blase", + "Blaseio", + "Blasien", + "Blasius", + "Blatman", + "Blatt", + "Blau", + "Blayne", + "Blayze", + "Blaze", + "Bledsoe", + "Bleier", + "Blen", + "Blessington", + "Blight", + "Blim", + "Blinni", + "Blinnie", + "Blinny", + "Bliss", + "Blisse", + "Blithe", + "Bloch", + "Block", + "Blockus", + "Blodget", + "Blodgett", + "Bloem", + "Blondell", + "Blondelle", + "Blondie", + "Blondy", + "Blood", + "Bloom", + "Bloomer", + "Blossom", + "Blount", + "Bloxberg", + "Bluefarb", + "Bluefield", + "Bluh", + "Bluhm", + "Blum", + "Bluma", + "Blumenfeld", + "Blumenthal", + "Blunk", + "Blunt", + "Blus", + "Blynn", + "Blythe", + "Bo", + "Boak", + "Boar", + "Boardman", + "Boarer", + "Boaten", + "Boatwright", + "Bob", + "Bobbe", + "Bobbee", + "Bobbette", + "Bobbi", + "Bobbie", + "Bobby", + "Bobbye", + "Bobette", + "Bobina", + "Bobine", + "Bobinette", + "Bobker", + "Bobseine", + "Bock", + "Bocock", + "Bodi", + "Bodkin", + "Bodnar", + "Bodrogi", + "Bodwell", + "Body", + "Boehike", + "Boehmer", + "Boeke", + "Boelter", + "Boesch", + "Boeschen", + "Boff", + "Boffa", + "Bogart", + "Bogey", + "Boggers", + "Boggs", + "Bogie", + "Bogoch", + "Bogosian", + "Bogusz", + "Bohannon", + "Bohaty", + "Bohi", + "Bohlen", + "Bohlin", + "Bohman", + "Bohner", + "Bohon", + "Bohrer", + "Bohs", + "Bohun", + "Boice", + "Boigie", + "Boiney", + "Bois", + "Bolan", + "Boland", + "Bolanger", + "Bolen", + "Boles", + "Boleslaw", + "Boleyn", + "Bolger", + "Bolitho", + "Bollay", + "Bollen", + "Bolling", + "Bollinger", + "Bolme", + "Bolt", + "Bolte", + "Bolten", + "Bolton", + "Bomke", + "Bonacci", + "Bonaparte", + "Bonar", + "Bond", + "Bondie", + "Bondon", + "Bondy", + "Bone", + "Boni", + "Boniface", + "Bonilla", + "Bonina", + "Bonine", + "Bonis", + "Bonita", + "Bonn", + "Bonne", + "Bonneau", + "Bonnee", + "Bonnell", + "Bonner", + "Bonnes", + "Bonnette", + "Bonney", + "Bonni", + "Bonnibelle", + "Bonnice", + "Bonnie", + "Bonns", + "Bonny", + "Bonucci", + "Booker", + "Booma", + "Boone", + "Boonie", + "Boony", + "Boor", + "Boorer", + "Boorman", + "Boot", + "Boote", + "Booth", + "Boothe", + "Boothman", + "Booze", + "Bopp", + "Bor", + "Bora", + "Borchers", + "Borchert", + "Bord", + "Borden", + "Bordie", + "Bordiuk", + "Bordy", + "Bore", + "Borek", + "Borer", + "Bores", + "Borg", + "Borgeson", + "Boris", + "Bork", + "Borlase", + "Borlow", + "Borman", + "Born", + "Bornie", + "Bornstein", + "Borras", + "Borrell", + "Borreri", + "Borries", + "Borroff", + "Borszcz", + "Bortman", + "Bortz", + "Boru", + "Bosch", + "Bose", + "Boser", + "Bosson", + "Bostow", + "Boswall", + "Boswell", + "Botnick", + "Botsford", + "Bottali", + "Botti", + "Botzow", + "Bouchard", + "Boucher", + "Bouchier", + "Boudreaux", + "Bough", + "Boulanger", + "Bouldon", + "Bouley", + "Bound", + "Bounds", + "Bourgeois", + "Bourke", + "Bourn", + "Bourne", + "Bourque", + "Boutis", + "Bouton", + "Bouzoun", + "Bove", + "Bovill", + "Bow", + "Bowden", + "Bowe", + "Bowen", + "Bower", + "Bowerman", + "Bowers", + "Bowes", + "Bowie", + "Bowlds", + "Bowler", + "Bowles", + "Bowman", + "Bowne", + "Bowra", + "Bowrah", + "Bowyer", + "Box", + "Boy", + "Boyce", + "Boycey", + "Boycie", + "Boyd", + "Boyden", + "Boyer", + "Boyes", + "Boykins", + "Boylan", + "Boylston", + "Boynton", + "Boys", + "Boyse", + "Boyt", + "Bozovich", + "Bozuwa", + "Braasch", + "Brabazon", + "Braca", + "Bracci", + "Brace", + "Brackely", + "Brackett", + "Brad", + "Bradan", + "Brade", + "Braden", + "Bradeord", + "Brader", + "Bradford", + "Bradlee", + "Bradleigh", + "Bradley", + "Bradly", + "Bradman", + "Bradney", + "Bradshaw", + "Bradski", + "Bradstreet", + "Bradway", + "Bradwell", + "Brady", + "Braeunig", + "Brag", + "Brahear", + "Brainard", + "Bram", + "Bramwell", + "Bran", + "Brana", + "Branca", + "Branch", + "Brand", + "Brandais", + "Brande", + "Brandea", + "Branden", + "Brandenburg", + "Brander", + "Brandes", + "Brandi", + "Brandice", + "Brandie", + "Brandise", + "Brandon", + "Brandt", + "Brandtr", + "Brandwein", + "Brandy", + "Brandyn", + "Branen", + "Branham", + "Brannon", + "Branscum", + "Brant", + "Brantley", + "Brasca", + "Brass", + "Braswell", + "Brathwaite", + "Bratton", + "Braun", + "Braunstein", + "Brause", + "Bravar", + "Bravin", + "Brawley", + "Brawner", + "Bray", + "Braynard", + "Brazee", + "Breana", + "Breanne", + "Brear", + "Breban", + "Brebner", + "Brecher", + "Brechtel", + "Bred", + "Bree", + "Breech", + "Breed", + "Breen", + "Breena", + "Breeze", + "Breger", + "Brelje", + "Bremble", + "Bremen", + "Bremer", + "Bremser", + "Bren", + "Brena", + "Brenan", + "Brenda", + "Brendan", + "Brenden", + "Brendin", + "Brendis", + "Brendon", + "Brenk", + "Brenn", + "Brenna", + "Brennan", + "Brennen", + "Brenner", + "Brent", + "Brenton", + "Brentt", + "Brenza", + "Bresee", + "Breskin", + "Brest", + "Bret", + "Brett", + "Brew", + "Brewer", + "Brewster", + "Brey", + "Brezin", + "Bria", + "Brian", + "Briana", + "Brianna", + "Brianne", + "Briano", + "Briant", + "Brice", + "Brick", + "Bricker", + "Bride", + "Bridge", + "Bridges", + "Bridget", + "Bridgette", + "Bridgid", + "Bridie", + "Bridwell", + "Brie", + "Brien", + "Brier", + "Brieta", + "Brietta", + "Brig", + "Brigette", + "Brigg", + "Briggs", + "Brigham", + "Bright", + "Brightman", + "Brighton", + "Brigid", + "Brigida", + "Brigit", + "Brigitta", + "Brigitte", + "Brill", + "Brina", + "Brindell", + "Brindle", + "Brine", + "Briney", + "Bringhurst", + "Brink", + "Brinkema", + "Brinn", + "Brinna", + "Brinson", + "Briny", + "Brion", + "Briscoe", + "Bristow", + "Brit", + "Brita", + "Britney", + "Britni", + "Britt", + "Britta", + "Brittain", + "Brittan", + "Brittaney", + "Brittani", + "Brittany", + "Britte", + "Britteny", + "Brittne", + "Brittnee", + "Brittney", + "Brittni", + "Britton", + "Brnaba", + "Brnaby", + "Broadbent", + "Brock", + "Brockie", + "Brocklin", + "Brockwell", + "Brocky", + "Brod", + "Broddie", + "Broddy", + "Brodench", + "Broder", + "Broderic", + "Broderick", + "Brodeur", + "Brodie", + "Brodsky", + "Brody", + "Broeder", + "Broek", + "Broeker", + "Brogle", + "Broida", + "Brok", + "Brom", + "Bromleigh", + "Bromley", + "Bron", + "Bronder", + "Bronez", + "Bronk", + "Bronnie", + "Bronny", + "Bronson", + "Bronwen", + "Bronwyn", + "Brook", + "Brooke", + "Brookes", + "Brookhouse", + "Brooking", + "Brookner", + "Brooks", + "Broome", + "Brose", + "Brosine", + "Brost", + "Brosy", + "Brote", + "Brothers", + "Brotherson", + "Brott", + "Brottman", + "Broucek", + "Brout", + "Brouwer", + "Brower", + "Brown", + "Browne", + "Browning", + "Brownley", + "Brownson", + "Brozak", + "Brubaker", + "Bruce", + "Brucie", + "Bruckner", + "Bruell", + "Brufsky", + "Bruis", + "Brunell", + "Brunella", + "Brunelle", + "Bruner", + "Brunhild", + "Brunhilda", + "Brunhilde", + "Bruni", + "Bruning", + "Brunk", + "Brunn", + "Bruno", + "Bruns", + "Bruyn", + "Bryan", + "Bryana", + "Bryant", + "Bryanty", + "Bryce", + "Bryn", + "Bryna", + "Bryner", + "Brynn", + "Brynna", + "Brynne", + "Bryon", + "Buatti", + "Bubalo", + "Bubb", + "Bucella", + "Buchalter", + "Buchanan", + "Buchbinder", + "Bucher", + "Buchheim", + "Buck", + "Buckden", + "Buckels", + "Buckie", + "Buckingham", + "Buckler", + "Buckley", + "Bucky", + "Bud", + "Budd", + "Budde", + "Buddie", + "Budding", + "Buddy", + "Buderus", + "Budge", + "Budwig", + "Budworth", + "Buehler", + "Buehrer", + "Buell", + "Buerger", + "Bueschel", + "Buff", + "Buffo", + "Buffum", + "Buffy", + "Buford", + "Bugbee", + "Buhler", + "Bui", + "Buine", + "Buiron", + "Buke", + "Bull", + "Bullard", + "Bullen", + "Buller", + "Bulley", + "Bullion", + "Bullis", + "Bullivant", + "Bullock", + "Bullough", + "Bully", + "Bultman", + "Bum", + "Bumgardner", + "Buna", + "Bunce", + "Bunch", + "Bunde", + "Bunder", + "Bundy", + "Bunker", + "Bunni", + "Bunnie", + "Bunns", + "Bunny", + "Bunow", + "Bunting", + "Buonomo", + "Buote", + "Burack", + "Burbank", + "Burch", + "Burchett", + "Burck", + "Burd", + "Burdelle", + "Burdett", + "Burford", + "Burg", + "Burgener", + "Burger", + "Burgess", + "Burget", + "Burgwell", + "Burhans", + "Burk", + "Burke", + "Burkhard", + "Burkhardt", + "Burkhart", + "Burkitt", + "Burkle", + "Burkley", + "Burl", + "Burleigh", + "Burley", + "Burlie", + "Burman", + "Burn", + "Burnaby", + "Burnard", + "Burne", + "Burner", + "Burnett", + "Burney", + "Burnham", + "Burnie", + "Burnight", + "Burnley", + "Burns", + "Burnsed", + "Burnside", + "Burny", + "Buroker", + "Burr", + "Burra", + "Burrell", + "Burrill", + "Burris", + "Burroughs", + "Burrow", + "Burrows", + "Burrton", + "Burrus", + "Burt", + "Burta", + "Burtie", + "Burtis", + "Burton", + "Burty", + "Burwell", + "Bury", + "Busby", + "Busch", + "Buschi", + "Buseck", + "Busey", + "Bush", + "Bushey", + "Bushore", + "Bushweller", + "Busiek", + "Buskirk", + "Buskus", + "Bussey", + "Bussy", + "Bust", + "Butch", + "Butcher", + "Butler", + "Butta", + "Buttaro", + "Butte", + "Butterfield", + "Butterworth", + "Button", + "Buxton", + "Buyer", + "Buyers", + "Buyse", + "Buzz", + "Buzzell", + "Byers", + "Byler", + "Byram", + "Byran", + "Byrann", + "Byrd", + "Byrdie", + "Byrle", + "Byrn", + "Byrne", + "Byrom", + "Byron", + "Bysshe", + "Bywaters", + "Bywoods", + "Cacia", + "Cacie", + "Cacilia", + "Cacilie", + "Cacka", + "Cad", + "Cadal", + "Caddaric", + "Caddric", + "Cade", + "Cadel", + "Cadell", + "Cadman", + "Cadmann", + "Cadmar", + "Cadmarr", + "Caesar", + "Caesaria", + "Caffrey", + "Cagle", + "Cahan", + "Cahilly", + "Cahn", + "Cahra", + "Cai", + "Caia", + "Caiaphas", + "Cailean", + "Cailly", + "Cain", + "Caine", + "Caines", + "Cairistiona", + "Cairns", + "Caitlin", + "Caitrin", + "Cal", + "Calabrese", + "Calabresi", + "Calan", + "Calandra", + "Calandria", + "Calbert", + "Caldeira", + "Calder", + "Caldera", + "Calderon", + "Caldwell", + "Cale", + "Caleb", + "Calen", + "Calendra", + "Calendre", + "Calesta", + "Calhoun", + "Calia", + "Calica", + "Calida", + "Calie", + "Calisa", + "Calise", + "Calista", + "Call", + "Calla", + "Callahan", + "Callan", + "Callas", + "Calle", + "Callean", + "Callery", + "Calley", + "Calli", + "Callida", + "Callie", + "Callista", + "Calloway", + "Callum", + "Cally", + "Calmas", + "Calondra", + "Calore", + "Calv", + "Calva", + "Calvano", + "Calvert", + "Calvin", + "Calvina", + "Calvinna", + "Calvo", + "Calypso", + "Calysta", + "Cam", + "Camala", + "Camarata", + "Camden", + "Camel", + "Camella", + "Camellia", + "Cameron", + "Camey", + "Camfort", + "Cami", + "Camila", + "Camile", + "Camilia", + "Camilla", + "Camille", + "Camilo", + "Camm", + "Cammi", + "Cammie", + "Cammy", + "Camp", + "Campagna", + "Campball", + "Campbell", + "Campman", + "Campney", + "Campos", + "Campy", + "Camus", + "Can", + "Canada", + "Canale", + "Cand", + "Candace", + "Candi", + "Candice", + "Candida", + "Candide", + "Candie", + "Candis", + "Candless", + "Candra", + "Candy", + "Candyce", + "Caneghem", + "Canfield", + "Canica", + "Canice", + "Caniff", + "Cann", + "Cannell", + "Cannice", + "Canning", + "Cannon", + "Canon", + "Canotas", + "Canter", + "Cantlon", + "Cantone", + "Cantu", + "Canty", + "Canute", + "Capello", + "Caplan", + "Capon", + "Capone", + "Capp", + "Cappella", + "Cappello", + "Capps", + "Caprice", + "Capriola", + "Caputo", + "Caputto", + "Capwell", + "Car", + "Cara", + "Caralie", + "Caras", + "Caravette", + "Caraviello", + "Carberry", + "Carbo", + "Carbone", + "Carboni", + "Carbrey", + "Carce", + "Card", + "Carder", + "Cardew", + "Cardie", + "Cardinal", + "Cardon", + "Cardwell", + "Care", + "Careaga", + "Caren", + "Carena", + "Caresa", + "Caressa", + "Caresse", + "Carew", + "Carey", + "Cargian", + "Carhart", + "Cari", + "Caria", + "Carie", + "Caril", + "Carilla", + "Carilyn", + "Carin", + "Carina", + "Carine", + "Cariotta", + "Carisa", + "Carissa", + "Carita", + "Caritta", + "Carl", + "Carla", + "Carlee", + "Carleen", + "Carlen", + "Carlene", + "Carleton", + "Carley", + "Carli", + "Carlick", + "Carlie", + "Carlile", + "Carlin", + "Carlina", + "Carline", + "Carling", + "Carlisle", + "Carlita", + "Carlo", + "Carlock", + "Carlos", + "Carlota", + "Carlotta", + "Carlson", + "Carlstrom", + "Carlton", + "Carly", + "Carlye", + "Carlyle", + "Carlyn", + "Carlynn", + "Carlynne", + "Carma", + "Carman", + "Carmel", + "Carmela", + "Carmelia", + "Carmelina", + "Carmelita", + "Carmella", + "Carmelle", + "Carmelo", + "Carmen", + "Carmena", + "Carmencita", + "Carmina", + "Carmine", + "Carmita", + "Carmon", + "Carn", + "Carnahan", + "Carnay", + "Carnes", + "Carney", + "Carny", + "Caro", + "Carol", + "Carol-Jean", + "Carola", + "Carolan", + "Carolann", + "Carole", + "Carolee", + "Carolin", + "Carolina", + "Caroline", + "Carolle", + "Carolus", + "Carolyn", + "Carolyne", + "Carolynn", + "Carolynne", + "Caron", + "Carothers", + "Carpenter", + "Carper", + "Carpet", + "Carpio", + "Carr", + "Carree", + "Carrel", + "Carrelli", + "Carrew", + "Carri", + "Carrick", + "Carrie", + "Carrillo", + "Carrington", + "Carrissa", + "Carrnan", + "Carrol", + "Carroll", + "Carry", + "Carson", + "Cart", + "Cartan", + "Carter", + "Carthy", + "Cartie", + "Cartwell", + "Cartwright", + "Caruso", + "Carver", + "Carvey", + "Cary", + "Caryl", + "Caryn", + "Cas", + "Casabonne", + "Casady", + "Casaleggio", + "Casandra", + "Casanova", + "Casar", + "Casavant", + "Case", + "Casey", + "Cash", + "Casi", + "Casia", + "Casie", + "Casilda", + "Casilde", + "Casimir", + "Casimire", + "Casmey", + "Caspar", + "Casper", + "Cass", + "Cassady", + "Cassandra", + "Cassandre", + "Cassandry", + "Cassaundra", + "Cassell", + "Cassella", + "Cassey", + "Cassi", + "Cassiani", + "Cassidy", + "Cassie", + "Cassil", + "Cassilda", + "Cassius", + "Cassondra", + "Cassy", + "Casta", + "Castara", + "Casteel", + "Castera", + "Castillo", + "Castle", + "Castor", + "Castora", + "Castorina", + "Castra", + "Castro", + "Caswell", + "Cataldo", + "Catarina", + "Cate", + "Caterina", + "Cates", + "Cath", + "Catha", + "Catharina", + "Catharine", + "Cathe", + "Cathee", + "Catherin", + "Catherina", + "Catherine", + "Cathey", + "Cathi", + "Cathie", + "Cathleen", + "Cathlene", + "Cathrin", + "Cathrine", + "Cathryn", + "Cathy", + "Cathyleen", + "Cati", + "Catie", + "Catima", + "Catina", + "Catlaina", + "Catlee", + "Catlin", + "Cato", + "Caton", + "Catrina", + "Catriona", + "Catt", + "Cattan", + "Cattier", + "Cattima", + "Catto", + "Catton", + "Caty", + "Caughey", + "Caundra", + "Cavallaro", + "Cavan", + "Cavanagh", + "Cavanaugh", + "Cave", + "Caves", + "Cavil", + "Cavill", + "Cavit", + "Cavuoto", + "Cawley", + "Caye", + "Cayla", + "Caylor", + "Cayser", + "Caz", + "Cazzie", + "Cchaddie", + "Cece", + "Cecelia", + "Cecil", + "Cecile", + "Ceciley", + "Cecilia", + "Cecilio", + "Cecilius", + "Cecilla", + "Cecily", + "Ced", + "Cedar", + "Cedell", + "Cedric", + "Ceevah", + "Ceil", + "Cele", + "Celene", + "Celeski", + "Celesta", + "Celeste", + "Celestia", + "Celestina", + "Celestine", + "Celestyn", + "Celestyna", + "Celia", + "Celie", + "Celik", + "Celin", + "Celina", + "Celinda", + "Celine", + "Celinka", + "Celio", + "Celisse", + "Celka", + "Celle", + "Cello", + "Celtic", + "Cenac", + "Cence", + "Centeno", + "Center", + "Centonze", + "Ceporah", + "Cerallua", + "Cerelia", + "Cerell", + "Cerellia", + "Cerelly", + "Cerf", + "Cerracchio", + "Certie", + "Cerveny", + "Cerys", + "Cesar", + "Cesare", + "Cesaria", + "Cesaro", + "Cestar", + "Cesya", + "Cha", + "Chabot", + "Chace", + "Chad", + "Chadabe", + "Chadbourne", + "Chadburn", + "Chadd", + "Chaddie", + "Chaddy", + "Chader", + "Chadwick", + "Chae", + "Chafee", + "Chaffee", + "Chaffin", + "Chaffinch", + "Chaiken", + "Chaille", + "Chaim", + "Chainey", + "Chaing", + "Chak", + "Chaker", + "Chally", + "Chalmer", + "Chalmers", + "Chamberlain", + "Chamberlin", + "Chambers", + "Chamkis", + "Champ", + "Champagne", + "Champaigne", + "Chan", + "Chance", + "Chancellor", + "Chancelor", + "Chancey", + "Chanda", + "Chandal", + "Chandler", + "Chandless", + "Chandos", + "Chandra", + "Chane", + "Chaney", + "Chang", + "Changaris", + "Channa", + "Channing", + "Chansoo", + "Chantal", + "Chantalle", + "Chao", + "Chap", + "Chapa", + "Chapel", + "Chapell", + "Chapen", + "Chapin", + "Chapland", + "Chapman", + "Chapnick", + "Chappelka", + "Chappell", + "Chappie", + "Chappy", + "Chara", + "Charbonneau", + "Charbonnier", + "Chard", + "Chari", + "Charie", + "Charil", + "Charin", + "Chariot", + "Charis", + "Charissa", + "Charisse", + "Charita", + "Charity", + "Charla", + "Charlean", + "Charleen", + "Charlena", + "Charlene", + "Charles", + "Charlet", + "Charleton", + "Charley", + "Charlie", + "Charline", + "Charlot", + "Charlotta", + "Charlotte", + "Charlton", + "Charmain", + "Charmaine", + "Charmane", + "Charmian", + "Charmine", + "Charmion", + "Charo", + "Charpentier", + "Charron", + "Charry", + "Charteris", + "Charters", + "Charyl", + "Chas", + "Chase", + "Chasse", + "Chassin", + "Chastain", + "Chastity", + "Chatav", + "Chatterjee", + "Chatwin", + "Chaudoin", + "Chaunce", + "Chauncey", + "Chavaree", + "Chaves", + "Chavey", + "Chavez", + "Chaworth", + "Che", + "Cheadle", + "Cheatham", + "Checani", + "Chee", + "Cheffetz", + "Cheke", + "Chellman", + "Chelsae", + "Chelsea", + "Chelsey", + "Chelsie", + "Chelsy", + "Chelton", + "Chem", + "Chema", + "Chemar", + "Chemaram", + "Chemarin", + "Chemash", + "Chemesh", + "Chemosh", + "Chemush", + "Chen", + "Chenay", + "Chenee", + "Cheney", + "Cheng", + "Cher", + "Chere", + "Cherey", + "Cheri", + "Cheria", + "Cherian", + "Cherianne", + "Cherice", + "Cherida", + "Cherie", + "Cherilyn", + "Cherilynn", + "Cherin", + "Cherise", + "Cherish", + "Cherlyn", + "Chernow", + "Cherri", + "Cherrita", + "Cherry", + "Chery", + "Cherye", + "Cheryl", + "Ches", + "Cheshire", + "Cheslie", + "Chesna", + "Chesney", + "Chesnut", + "Chessa", + "Chessy", + "Chester", + "Cheston", + "Chet", + "Cheung", + "Chev", + "Chevalier", + "Chevy", + "Chew", + "Cheyne", + "Cheyney", + "Chi", + "Chiaki", + "Chiang", + "Chiarra", + "Chic", + "Chick", + "Chickie", + "Chicky", + "Chico", + "Chicoine", + "Chien", + "Chil", + "Chilcote", + "Child", + "Childers", + "Childs", + "Chiles", + "Chill", + "Chilson", + "Chilt", + "Chilton", + "Chimene", + "Chin", + "China", + "Ching", + "Chinua", + "Chiou", + "Chip", + "Chipman", + "Chiquia", + "Chiquita", + "Chirlin", + "Chisholm", + "Chita", + "Chitkara", + "Chivers", + "Chladek", + "Chlo", + "Chloe", + "Chloette", + "Chloras", + "Chlores", + "Chlori", + "Chloris", + "Cho", + "Chobot", + "Chon", + "Chong", + "Choo", + "Choong", + "Chor", + "Chouest", + "Chow", + "Chretien", + "Chris", + "Chrisman", + "Chrisoula", + "Chrissa", + "Chrisse", + "Chrissie", + "Chrissy", + "Christa", + "Christabel", + "Christabella", + "Christabelle", + "Christal", + "Christalle", + "Christan", + "Christean", + "Christel", + "Christen", + "Christensen", + "Christenson", + "Christi", + "Christian", + "Christiana", + "Christiane", + "Christianity", + "Christianna", + "Christiano", + "Christiansen", + "Christianson", + "Christie", + "Christin", + "Christina", + "Christine", + "Christis", + "Christmann", + "Christmas", + "Christoffer", + "Christoforo", + "Christoper", + "Christoph", + "Christophe", + "Christopher", + "Christos", + "Christy", + "Christye", + "Christyna", + "Chrisy", + "Chrotoem", + "Chrysa", + "Chrysler", + "Chrystal", + "Chryste", + "Chrystel", + "Chu", + "Chuah", + "Chubb", + "Chuch", + "Chucho", + "Chuck", + "Chud", + "Chui", + "Chuipek", + "Chun", + "Chung", + "Chura", + "Church", + "Churchill", + "Chute", + "Chuu", + "Chyou", + "Cia", + "Cianca", + "Ciapas", + "Ciapha", + "Ciaphus", + "Cibis", + "Ciccia", + "Cicely", + "Cicenia", + "Cicero", + "Cichocki", + "Cicily", + "Cid", + "Cida", + "Ciel", + "Cila", + "Cilka", + "Cilla", + "Cilo", + "Cilurzo", + "Cima", + "Cimah", + "Cimbura", + "Cinda", + "Cindee", + "Cindelyn", + "Cinderella", + "Cindi", + "Cindie", + "Cindra", + "Cindy", + "Cinelli", + "Cini", + "Cinnamon", + "Cioban", + "Cioffred", + "Ciprian", + "Circosta", + "Ciri", + "Cirilla", + "Cirillo", + "Cirilo", + "Ciro", + "Cirone", + "Cirri", + "Cis", + "Cissie", + "Cissiee", + "Cissy", + "Cita", + "Citarella", + "Citron", + "Clabo", + "Claiborn", + "Claiborne", + "Clair", + "Claire", + "Claman", + "Clance", + "Clancy", + "Clapp", + "Clapper", + "Clara", + "Clarabelle", + "Clarance", + "Clardy", + "Clare", + "Clarence", + "Claresta", + "Clareta", + "Claretta", + "Clarette", + "Clarey", + "Clarhe", + "Clari", + "Claribel", + "Clarice", + "Clarie", + "Clarinda", + "Clarine", + "Clarisa", + "Clarise", + "Clarissa", + "Clarisse", + "Clarita", + "Clark", + "Clarke", + "Clarkin", + "Clarkson", + "Clary", + "Claud", + "Clauddetta", + "Claude", + "Claudell", + "Claudelle", + "Claudetta", + "Claudette", + "Claudia", + "Claudian", + "Claudianus", + "Claudie", + "Claudina", + "Claudine", + "Claudio", + "Claudius", + "Claudy", + "Claus", + "Clausen", + "Clava", + "Clawson", + "Clay", + "Clayberg", + "Clayborn", + "Clayborne", + "Claybourne", + "Clayson", + "Clayton", + "Clea", + "Cleary", + "Cleasta", + "Cleave", + "Cleaves", + "Cleavland", + "Clein", + "Cleland", + "Clellan", + "Clem", + "Clemen", + "Clemence", + "Clemens", + "Clement", + "Clementas", + "Clemente", + "Clementi", + "Clementia", + "Clementina", + "Clementine", + "Clementis", + "Clementius", + "Clements", + "Clemmie", + "Clemmy", + "Cleo", + "Cleodal", + "Cleodel", + "Cleodell", + "Cleon", + "Cleopatra", + "Cleopatre", + "Clerc", + "Clercq", + "Clere", + "Cleres", + "Clerissa", + "Clerk", + "Cleti", + "Cletis", + "Cletus", + "Cleve", + "Cleveland", + "Clevey", + "Clevie", + "Clie", + "Cliff", + "Cliffes", + "Clifford", + "Clift", + "Clifton", + "Clim", + "Cline", + "Clint", + "Clintock", + "Clinton", + "Clio", + "Clippard", + "Clite", + "Clive", + "Clo", + "Cloe", + "Cloots", + "Clorinda", + "Clorinde", + "Cloris", + "Close", + "Clothilde", + "Clotilda", + "Clotilde", + "Clough", + "Clougher", + "Cloutman", + "Clova", + "Clovah", + "Clover", + "Clovis", + "Clower", + "Clute", + "Cly", + "Clyde", + "Clymer", + "Clynes", + "Clyte", + "Clyve", + "Clywd", + "Cnut", + "Coad", + "Coady", + "Coates", + "Coats", + "Cob", + "Cobb", + "Cobbie", + "Cobby", + "Coben", + "Cochard", + "Cochran", + "Cochrane", + "Cock", + "Cockburn", + "Cocke", + "Cocks", + "Coco", + "Codd", + "Codding", + "Codee", + "Codel", + "Codi", + "Codie", + "Cody", + "Coe", + "Coffee", + "Coffeng", + "Coffey", + "Coffin", + "Cofsky", + "Cogan", + "Cogen", + "Cogswell", + "Coh", + "Cohbath", + "Cohberg", + "Cohbert", + "Cohby", + "Cohdwell", + "Cohe", + "Coheman", + "Cohen", + "Cohette", + "Cohin", + "Cohl", + "Cohla", + "Cohleen", + "Cohlette", + "Cohlier", + "Cohligan", + "Cohn", + "Cointon", + "Coit", + "Coke", + "Col", + "Colan", + "Colas", + "Colb", + "Colbert", + "Colburn", + "Colby", + "Colbye", + "Cole", + "Coleen", + "Coleman", + "Colene", + "Colet", + "Coletta", + "Colette", + "Coleville", + "Colfin", + "Colier", + "Colin", + "Colinson", + "Colis", + "Collar", + "Collayer", + "Collbaith", + "Colleen", + "Collen", + "Collete", + "Collette", + "Colley", + "Collie", + "Collier", + "Colligan", + "Collimore", + "Collin", + "Colline", + "Collins", + "Collis", + "Collum", + "Colly", + "Collyer", + "Colman", + "Colner", + "Colombi", + "Colon", + "Colp", + "Colpin", + "Colson", + "Colston", + "Colt", + "Coltin", + "Colton", + "Coltson", + "Coltun", + "Columba", + "Columbine", + "Columbus", + "Columbyne", + "Colver", + "Colvert", + "Colville", + "Colvin", + "Colwell", + "Colwen", + "Colwin", + "Colyer", + "Combe", + "Combes", + "Combs", + "Comfort", + "Compte", + "Comptom", + "Compton", + "Comras", + "Comstock", + "Comyns", + "Con", + "Conah", + "Conal", + "Conall", + "Conan", + "Conant", + "Conard", + "Concepcion", + "Concettina", + "Concha", + "Conchita", + "Concoff", + "Concordia", + "Condon", + "Coney", + "Congdon", + "Conger", + "Coniah", + "Conias", + "Conlan", + "Conlee", + "Conlen", + "Conley", + "Conlin", + "Conlon", + "Conn", + "Connel", + "Connell", + "Connelley", + "Connelly", + "Conner", + "Conners", + "Connett", + "Conney", + "Conni", + "Connie", + "Connolly", + "Connor", + "Connors", + "Conny", + "Conover", + "Conrad", + "Conrade", + "Conrado", + "Conroy", + "Consalve", + "Consolata", + "Constance", + "Constancia", + "Constancy", + "Constant", + "Constanta", + "Constantia", + "Constantin", + "Constantina", + "Constantine", + "Constantino", + "Consuela", + "Consuelo", + "Conte", + "Conti", + "Converse", + "Convery", + "Conway", + "Cony", + "Conyers", + "Cooe", + "Cook", + "Cooke", + "Cookie", + "Cooley", + "Coombs", + "Coonan", + "Coop", + "Cooper", + "Cooperman", + "Coopersmith", + "Cooperstein", + "Cope", + "Copeland", + "Copland", + "Coplin", + "Copp", + "Coppinger", + "Coppins", + "Coppock", + "Coppola", + "Cora", + "Corabel", + "Corabella", + "Corabelle", + "Coral", + "Coralie", + "Coraline", + "Coralyn", + "Coray", + "Corbet", + "Corbett", + "Corbie", + "Corbin", + "Corby", + "Cord", + "Cordalia", + "Cordeelia", + "Cordelia", + "Cordelie", + "Cordell", + "Corder", + "Cordey", + "Cordi", + "Cordie", + "Cordier", + "Cordle", + "Cordova", + "Cordula", + "Cordy", + "Coreen", + "Corel", + "Corell", + "Corella", + "Corena", + "Corenda", + "Corene", + "Coretta", + "Corette", + "Corey", + "Cori", + "Coridon", + "Corie", + "Corilla", + "Corin", + "Corina", + "Corine", + "Corinna", + "Corinne", + "Coriss", + "Corissa", + "Corkhill", + "Corley", + "Corliss", + "Corly", + "Cormac", + "Cormack", + "Cormick", + "Cormier", + "Cornall", + "Corneille", + "Cornel", + "Cornela", + "Cornelia", + "Cornelie", + "Cornelius", + "Cornell", + "Cornelle", + "Cornew", + "Corney", + "Cornia", + "Cornie", + "Cornish", + "Cornwall", + "Cornwell", + "Corny", + "Corotto", + "Correna", + "Correy", + "Corri", + "Corrianne", + "Corrie", + "Corrina", + "Corrine", + "Corrinne", + "Corron", + "Corry", + "Corsetti", + "Corsiglia", + "Corso", + "Corson", + "Cort", + "Cortie", + "Cortney", + "Corty", + "Corvese", + "Corvin", + "Corwin", + "Corwun", + "Cory", + "Coryden", + "Corydon", + "Cos", + "Cosenza", + "Cosetta", + "Cosette", + "Coshow", + "Cosimo", + "Cosma", + "Cosme", + "Cosmo", + "Cost", + "Costa", + "Costanza", + "Costanzia", + "Costello", + "Coster", + "Costin", + "Cote", + "Cotsen", + "Cott", + "Cotter", + "Cotterell", + "Cottle", + "Cottrell", + "Coucher", + "Couchman", + "Coughlin", + "Coulombe", + "Coulson", + "Coulter", + "Coumas", + "Countess", + "Courcy", + "Court", + "Courtenay", + "Courtland", + "Courtnay", + "Courtney", + "Courtund", + "Cousin", + "Cousins", + "Coussoule", + "Couture", + "Covell", + "Coveney", + "Cowan", + "Coward", + "Cowden", + "Cowen", + "Cower", + "Cowey", + "Cowie", + "Cowles", + "Cowley", + "Cown", + "Cox", + "Coy", + "Coyle", + "Cozmo", + "Cozza", + "Crabb", + "Craddock", + "Craggie", + "Craggy", + "Craig", + "Crain", + "Cralg", + "Cram", + "Cramer", + "Cran", + "Crandale", + "Crandall", + "Crandell", + "Crane", + "Craner", + "Cranford", + "Cranston", + "Crary", + "Craven", + "Craw", + "Crawford", + "Crawley", + "Creamer", + "Crean", + "Creath", + "Creedon", + "Creigh", + "Creight", + "Creighton", + "Crelin", + "Crellen", + "Crenshaw", + "Cresa", + "Crescantia", + "Crescen", + "Crescentia", + "Crescin", + "Crescint", + "Cresida", + "Crespi", + "Crespo", + "Cressi", + "Cressida", + "Cressler", + "Cressy", + "Crichton", + "Crifasi", + "Crim", + "Crin", + "Cris", + "Crisey", + "Crispa", + "Crispas", + "Crispen", + "Crispin", + "Crissie", + "Crissy", + "Crist", + "Crista", + "Cristabel", + "Cristal", + "Cristen", + "Cristi", + "Cristian", + "Cristiano", + "Cristie", + "Cristin", + "Cristina", + "Cristine", + "Cristiona", + "Cristionna", + "Cristobal", + "Cristoforo", + "Cristy", + "Criswell", + "Critchfield", + "Critta", + "Crocker", + "Crockett", + "Crofoot", + "Croft", + "Crofton", + "Croix", + "Crompton", + "Cromwell", + "Croner", + "Cronin", + "Crooks", + "Croom", + "Crosby", + "Crosley", + "Cross", + "Crosse", + "Croteau", + "Crotty", + "Crow", + "Crowe", + "Crowell", + "Crowley", + "Crowns", + "Croydon", + "Cruce", + "Crudden", + "Cruickshank", + "Crutcher", + "Cruz", + "Cryan", + "Crysta", + "Crystal", + "Crystie", + "Cthrine", + "Cuda", + "Cudlip", + "Culberson", + "Culbert", + "Culbertson", + "Culhert", + "Cull", + "Cullan", + "Cullen", + "Culley", + "Cullie", + "Cullin", + "Culliton", + "Cully", + "Culosio", + "Culver", + "Cumine", + "Cumings", + "Cummine", + "Cummings", + "Cummins", + "Cung", + "Cunningham", + "Cupo", + "Curcio", + "Curhan", + "Curkell", + "Curley", + "Curnin", + "Curr", + "Curran", + "Curren", + "Currey", + "Currie", + "Currier", + "Curry", + "Curson", + "Curt", + "Curtice", + "Curtis", + "Curzon", + "Cusack", + "Cusick", + "Custer", + "Cut", + "Cutcheon", + "Cutcliffe", + "Cuthbert", + "Cuthbertson", + "Cuthburt", + "Cutler", + "Cutlerr", + "Cutlip", + "Cutlor", + "Cutter", + "Cuttie", + "Cuttler", + "Cutty", + "Cuyler", + "Cy", + "Cyb", + "Cybil", + "Cybill", + "Cychosz", + "Cyd", + "Cykana", + "Cyler", + "Cyma", + "Cymbre", + "Cyn", + "Cyna", + "Cynar", + "Cynara", + "Cynarra", + "Cynde", + "Cyndi", + "Cyndia", + "Cyndie", + "Cyndy", + "Cynera", + "Cynth", + "Cynthea", + "Cynthia", + "Cynthie", + "Cynthla", + "Cynthy", + "Cyprian", + "Cyprio", + "Cypro", + "Cyprus", + "Cyrano", + "Cyrie", + "Cyril", + "Cyrill", + "Cyrilla", + "Cyrille", + "Cyrillus", + "Cyrus", + "Czarra", + "D'Arcy", + "Dabbs", + "Daberath", + "Dabney", + "Dace", + "Dacey", + "Dachi", + "Dachia", + "Dachy", + "Dacia", + "Dacie", + "Dacy", + "Daegal", + "Dael", + "Daffi", + "Daffie", + "Daffodil", + "Daffy", + "Dafna", + "Dafodil", + "Dag", + "Dagall", + "Daggett", + "Daggna", + "Dagley", + "Dagmar", + "Dagna", + "Dagnah", + "Dagney", + "Dagny", + "Dahl", + "Dahle", + "Dahlia", + "Dahlstrom", + "Daigle", + "Dail", + "Daile", + "Dailey", + "Daisey", + "Daisi", + "Daisie", + "Daisy", + "Daitzman", + "Dal", + "Dale", + "Dalenna", + "Daley", + "Dalia", + "Dalila", + "Dalis", + "Dall", + "Dallas", + "Dalli", + "Dallis", + "Dallman", + "Dallon", + "Daloris", + "Dalpe", + "Dalston", + "Dalt", + "Dalton", + "Dalury", + "Daly", + "Dam", + "Damal", + "Damalas", + "Damales", + "Damali", + "Damalis", + "Damalus", + "Damara", + "Damaris", + "Damarra", + "Dambro", + "Dame", + "Damek", + "Damian", + "Damiani", + "Damiano", + "Damick", + "Damicke", + "Damien", + "Damita", + "Damle", + "Damon", + "Damour", + "Dan", + "Dana", + "Danae", + "Danaher", + "Danais", + "Danas", + "Danby", + "Danczyk", + "Dane", + "Danell", + "Danella", + "Danelle", + "Danete", + "Danette", + "Daney", + "Danforth", + "Dang", + "Dani", + "Dania", + "Daniala", + "Danialah", + "Danica", + "Danice", + "Danie", + "Daniel", + "Daniela", + "Daniele", + "Daniell", + "Daniella", + "Danielle", + "Daniels", + "Danielson", + "Danieu", + "Danika", + "Danila", + "Danit", + "Danita", + "Daniyal", + "Dann", + "Danna", + "Dannel", + "Danni", + "Dannica", + "Dannie", + "Dannon", + "Danny", + "Dannye", + "Dante", + "Danuloff", + "Danya", + "Danyelle", + "Danyette", + "Danyluk", + "Danzig", + "Danziger", + "Dao", + "Daph", + "Daphene", + "Daphie", + "Daphna", + "Daphne", + "Dar", + "Dara", + "Darach", + "Darb", + "Darbee", + "Darbie", + "Darby", + "Darce", + "Darcee", + "Darcey", + "Darci", + "Darcia", + "Darcie", + "Darcy", + "Darda", + "Dardani", + "Dare", + "Dareece", + "Dareen", + "Darees", + "Darell", + "Darelle", + "Daren", + "Dari", + "Daria", + "Darian", + "Darice", + "Darill", + "Darin", + "Dario", + "Darius", + "Darken", + "Darla", + "Darleen", + "Darlene", + "Darline", + "Darlleen", + "Darmit", + "Darn", + "Darnall", + "Darnell", + "Daron", + "Darooge", + "Darra", + "Darrel", + "Darrell", + "Darrelle", + "Darren", + "Darrey", + "Darrick", + "Darrill", + "Darrin", + "Darrow", + "Darryl", + "Darryn", + "Darsey", + "Darsie", + "Dart", + "Darton", + "Darwen", + "Darwin", + "Darya", + "Daryl", + "Daryle", + "Daryn", + "Dash", + "Dasha", + "Dasi", + "Dasie", + "Dasteel", + "Dasya", + "Datha", + "Datnow", + "Daub", + "Daugherty", + "Daughtry", + "Daukas", + "Daune", + "Dav", + "Dave", + "Daveda", + "Daveen", + "Daven", + "Davena", + "Davenport", + "Daveta", + "Davey", + "David", + "Davida", + "Davidde", + "Davide", + "Davidoff", + "Davidson", + "Davie", + "Davies", + "Davilman", + "Davin", + "Davina", + "Davine", + "Davis", + "Davison", + "Davita", + "Davon", + "Davy", + "Dawes", + "Dawkins", + "Dawn", + "Dawna", + "Dawson", + "Day", + "Daye" +]
\ No newline at end of file diff --git a/data/world/locations.json b/data/world/locations.json new file mode 100644 index 0000000..90ed8a3 --- /dev/null +++ b/data/world/locations.json @@ -0,0 +1,31 @@ +[{
+ "latitude": 50.8577758,
+ "longitude": 5.6308645,
+ "name": "Maastricht",
+ "size": 2
+ },
+ {
+ "latitude": 48.8588377,
+ "longitude": 2.2770206,
+ "name": "Paris",
+ "size": 1
+ },
+ {
+ "latitude": 51.5285582,
+ "longitude": -0.2416796,
+ "name": "London",
+ "size": 1
+ },
+ {
+ "latitude": 55.8554403,
+ "longitude": -4.3024976,
+ "name": "Glasgow",
+ "size": 1
+ },
+ {
+ "latitude": 53.472225,
+ "longitude": -2.2935019,
+ "name": "Manchester",
+ "size": 1
+ }
+]
\ No newline at end of file diff --git a/docs/Screenshots/loading_screen.png b/docs/Screenshots/loading_screen.png Binary files differnew file mode 100644 index 0000000..74e9ea4 --- /dev/null +++ b/docs/Screenshots/loading_screen.png diff --git a/docs/Screenshots/menu_screen.png b/docs/Screenshots/menu_screen.png Binary files differnew file mode 100644 index 0000000..57cd21f --- /dev/null +++ b/docs/Screenshots/menu_screen.png diff --git a/docs/Screenshots/menu_screen_loading.png b/docs/Screenshots/menu_screen_loading.png Binary files differnew file mode 100644 index 0000000..9311d4f --- /dev/null +++ b/docs/Screenshots/menu_screen_loading.png diff --git a/docs/Screenshots/save_state_select.png b/docs/Screenshots/save_state_select.png Binary files differnew file mode 100644 index 0000000..8095e6c --- /dev/null +++ b/docs/Screenshots/save_state_select.png diff --git a/docs/Screenshots/world_map.png b/docs/Screenshots/world_map.png Binary files differnew file mode 100644 index 0000000..648c458 --- /dev/null +++ b/docs/Screenshots/world_map.png diff --git a/docs/Screenshots/world_map_purchase_location.png b/docs/Screenshots/world_map_purchase_location.png Binary files differnew file mode 100644 index 0000000..590137e --- /dev/null +++ b/docs/Screenshots/world_map_purchase_location.png diff --git a/docs/Specification.docx b/docs/Specification.docx Binary files differnew file mode 100644 index 0000000..d8fbe74 --- /dev/null +++ b/docs/Specification.docx diff --git a/docs/Use Cases/use case diagram.png b/docs/Use Cases/use case diagram.png Binary files differnew file mode 100644 index 0000000..0d33ee4 --- /dev/null +++ b/docs/Use Cases/use case diagram.png diff --git a/docs/Use Cases/use case diagram.uxf b/docs/Use Cases/use case diagram.uxf new file mode 100644 index 0000000..8f27dad --- /dev/null +++ b/docs/Use Cases/use case diagram.uxf @@ -0,0 +1,711 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<diagram program="umlet" version="14.3.0">
+ <zoom_level>6</zoom_level>
+ <element>
+ <id>UMLActor</id>
+ <coordinates>
+ <x>354</x>
+ <y>282</y>
+ <w>36</w>
+ <h>66</h>
+ </coordinates>
+ <panel_attributes>Player</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>576</x>
+ <y>276</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC2:
+Choose save state</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLGeneric</id>
+ <coordinates>
+ <x>432</x>
+ <y>120</y>
+ <w>996</w>
+ <h>648</h>
+ </coordinates>
+ <panel_attributes>TruckerX
+halign=left</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>498</x>
+ <y>432</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC4: exit game</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>570</x>
+ <y>354</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC3: manage
+game settings</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>714</x>
+ <y>276</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC5: select state to
+continue</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>552</x>
+ <y>198</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC1: start new game</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>984</x>
+ <y>276</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC10: select place
+to manage</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>906</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC8: view events</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>402</x>
+ <y>234</y>
+ <w>168</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes/>
+ <additional_attributes>10.0;100.0;260.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>402</x>
+ <y>294</y>
+ <w>186</w>
+ <h>24</h>
+ </coordinates>
+ <panel_attributes/>
+ <additional_attributes>10.0;20.0;290.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>396</x>
+ <y>312</y>
+ <w>192</w>
+ <h>66</h>
+ </coordinates>
+ <panel_attributes/>
+ <additional_attributes>10.0;10.0;300.0;90.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>390</x>
+ <y>324</y>
+ <w>150</w>
+ <h>120</h>
+ </coordinates>
+ <panel_attributes/>
+ <additional_attributes>10.0;10.0;230.0;180.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>648</x>
+ <y>294</y>
+ <w>78</w>
+ <h>24</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;20.0;110.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>924</x>
+ <y>294</y>
+ <w>72</w>
+ <h>24</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>624</x>
+ <y>222</y>
+ <w>252</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>lt=.>
+<<includes>></panel_attributes>
+ <additional_attributes>10.0;10.0;400.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>888</x>
+ <y>324</y>
+ <w>78</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;80.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>852</x>
+ <y>276</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC6: view world state</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>786</x>
+ <y>294</y>
+ <w>78</w>
+ <h>24</h>
+ </coordinates>
+ <panel_attributes>lt=.>
+<<includes>></panel_attributes>
+ <additional_attributes>10.0;20.0;110.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>798</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC7: select place to
+purchase</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>840</x>
+ <y>324</y>
+ <w>72</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>60.0;10.0;10.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>798</x>
+ <y>474</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC9: purchase place</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>834</x>
+ <y>432</y>
+ <w>54</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;70.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1122</x>
+ <y>276</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC11: view place
+state</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1056</x>
+ <y>294</y>
+ <w>78</w>
+ <h>24</h>
+ </coordinates>
+ <panel_attributes>lt=.>
+<<includes>></panel_attributes>
+ <additional_attributes>10.0;20.0;110.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1002</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC12:
+view employees</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1086</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC15:
+view schedule</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1170</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC18:
+view trucks</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1338</x>
+ <y>384</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC24:
+view job offers</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1044</x>
+ <y>318</y>
+ <w>102</w>
+ <h>78</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>150.0;10.0;10.0;110.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1182</x>
+ <y>318</y>
+ <w>192</w>
+ <h>78</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;300.0;110.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1170</x>
+ <y>324</y>
+ <w>72</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;60.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1128</x>
+ <y>324</y>
+ <w>60</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>30.0;10.0;10.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1002</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC13:
+select employee</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1038</x>
+ <y>432</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1002</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC14:
+change assigned
+truck</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1038</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1116</x>
+ <y>432</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1086</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC16:
+select job to
+reschedule</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1116</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1086</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC17:
+reschedule
+timeslots for job</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1200</x>
+ <y>432</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1170</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC19:
+select truck</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1200</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1170</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC20:
+upgrade truck
+parts</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1368</x>
+ <y>432</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1338</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC25:
+select job offer</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1368</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1338</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC26:
+schedule timeslots
+for new job</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1254</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC21:
+purchase
+new truck</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1284</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1254</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC22:
+select manufacturer</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1230</x>
+ <y>426</y>
+ <w>72</w>
+ <h>66</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;100.0;90.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>1254</x>
+ <y>672</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC23:
+select truck
+to purchase</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1284</x>
+ <y>624</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>954</x>
+ <y>426</y>
+ <w>72</w>
+ <h>66</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>100.0;10.0;10.0;90.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>918</x>
+ <y>480</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC27:
+hire new
+employee</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>954</x>
+ <y>528</y>
+ <w>54</w>
+ <h>60</h>
+ </coordinates>
+ <panel_attributes>lt=<.
+<<extends>></panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLUseCase</id>
+ <coordinates>
+ <x>918</x>
+ <y>576</y>
+ <w>78</w>
+ <h>54</h>
+ </coordinates>
+ <panel_attributes>UC28:
+select employee
+to hire</panel_attributes>
+ <additional_attributes/>
+ </element>
+</diagram>
diff --git a/docs/~$ecification.docx b/docs/~$ecification.docx Binary files differnew file mode 100644 index 0000000..34b5985 --- /dev/null +++ b/docs/~$ecification.docx diff --git a/libs/SDL2.lib b/libs/SDL2.lib Binary files differnew file mode 100644 index 0000000..ea6fa42 --- /dev/null +++ b/libs/SDL2.lib diff --git a/libs/SDL2_mixer.lib b/libs/SDL2_mixer.lib Binary files differnew file mode 100644 index 0000000..3b96d7d --- /dev/null +++ b/libs/SDL2_mixer.lib diff --git a/libs/libFLAC-8.dll b/libs/libFLAC-8.dll Binary files differnew file mode 100644 index 0000000..71f2e19 --- /dev/null +++ b/libs/libFLAC-8.dll diff --git a/libs/libmodplug-1.dll b/libs/libmodplug-1.dll Binary files differnew file mode 100644 index 0000000..7c05126 --- /dev/null +++ b/libs/libmodplug-1.dll diff --git a/libs/libmpg123-0.dll b/libs/libmpg123-0.dll Binary files differnew file mode 100644 index 0000000..c7809b1 --- /dev/null +++ b/libs/libmpg123-0.dll diff --git a/libs/libogg-0.dll b/libs/libogg-0.dll Binary files differnew file mode 100644 index 0000000..5133481 --- /dev/null +++ b/libs/libogg-0.dll diff --git a/libs/libopus-0.dll b/libs/libopus-0.dll Binary files differnew file mode 100644 index 0000000..9ba6c38 --- /dev/null +++ b/libs/libopus-0.dll diff --git a/libs/libopusfile-0.dll b/libs/libopusfile-0.dll Binary files differnew file mode 100644 index 0000000..97a88b6 --- /dev/null +++ b/libs/libopusfile-0.dll diff --git a/libs/libvorbis-0.dll b/libs/libvorbis-0.dll Binary files differnew file mode 100644 index 0000000..f5ae1bf --- /dev/null +++ b/libs/libvorbis-0.dll diff --git a/libs/libvorbisfile-3.dll b/libs/libvorbisfile-3.dll Binary files differnew file mode 100644 index 0000000..d078736 --- /dev/null +++ b/libs/libvorbisfile-3.dll diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..3698908 --- /dev/null +++ b/src/data.c @@ -0,0 +1,113 @@ +void data_load()
+{
+ // Loading screen
+ img_logo = assets_load_image_from_file("data/img/logo.png");
+
+ // Fonts
+ for (int i = 0; i < FONT_COUNT; i++) {
+ u16 size = FONT_START + (FONT_SIZE_SPACING * i);
+ font_regular[i] = assets_load_font_from_file("data/fonts/Exo-Regular.ttf", size);
+ }
+
+ // Images
+ img_logo_fruitosis = assets_load_image_from_file("data/img/logo_fruitosis.png");
+
+ img_truck_unknown = assets_load_image_from_file("data/img/truck-unknown.png");
+ img_iveco_stralis_hiway = assets_load_image_from_file("data/img/iveco-stralis-hiway.png");
+ img_iveco_stralis_activespace = assets_load_image_from_file("data/img/iveco-stralis-activespace.png");
+
+ img_logo_mercedes = assets_load_image_from_file("data/img/mercedes-logo.png");
+ img_logo_iveco = assets_load_image_from_file("data/img/iveco-logo.png");
+ img_logo_volvo = assets_load_image_from_file("data/img/volvo-logo.png");
+
+ img_white = assets_load_image_from_file("data/img/white.png");
+ img_location_pin = assets_load_image_from_file("data/img/location-pin.png");
+ img_city = assets_load_image_from_file("data/img/city.png");
+ img_boat = assets_load_image_from_file("data/img/boat.png");
+ img_star = assets_load_image_from_file("data/img/star.png");
+ img_road = assets_load_image_from_file("data/img/road.png");
+ img_timer = assets_load_image_from_file("data/img/timer.png");
+ img_coins = assets_load_image_from_file("data/img/coins.png");
+ img_arrow_left_rounded = assets_load_image_from_file("data/img/arrow-left-rounded.png");
+ img_globe = assets_load_image_from_file("data/img/globe.png");
+ img_questionmark = assets_load_image_from_file("data/img/question-mark.png");
+ img_checkmark = assets_load_image_from_file("data/img/checkmark.png");
+ img_grid = assets_load_image_from_file("data/img/grid.png");
+ img_lock = assets_load_image_from_file("data/img/lock.png");
+ img_arrow_left = assets_load_image_from_file("data/img/arrow-left.png");
+ img_arrow_right = assets_load_image_from_file("data/img/arrow-right.png");
+ img_pause = assets_load_image_from_file("data/img/pause.png");
+ img_close = assets_load_image_from_file("data/img/close.png");
+ img_back = assets_load_image_from_file("data/img/back.png");
+ img_locationdot = assets_load_image_from_file("data/img/location_dot.png");
+ img_dot = assets_load_image_from_file("data/img/dot.png");
+ img_carwheel = assets_load_image_from_file("data/img/car-wheel.png");
+ img_bank = assets_load_image_from_file("data/img/bank.png");
+ img_graph = assets_load_image_from_file("data/img/statistics.png");
+ img_list = assets_load_image_from_file("data/img/list.png");
+ img_tabitem = assets_load_image_from_file("data/img/tab-item.png");
+ img_portrait = assets_load_image_from_file("data/img/portrait.png");
+ img_resume = assets_load_image_from_file("data/img/resume.png");
+ img_signature = assets_load_image_from_file("data/img/signature.png");
+ img_hired = assets_load_image_from_file("data/img/hired.png");
+ img_denied = assets_load_image_from_file("data/img/denied.png");
+ img_world_map = assets_load_image_from_file("data/img/world_background.png");
+
+ img_panel_bottom = assets_load_image_from_file("data/img/panel_bottom.png");
+ img_panel_top = assets_load_image_from_file("data/img/panel_top.png");
+ img_panel_left = assets_load_image_from_file("data/img/panel_left.png");
+ img_panel_right = assets_load_image_from_file("data/img/panel_right.png");
+ img_panel_bottomleft = assets_load_image_from_file("data/img/panel_bottomleft.png");
+ img_panel_bottomright = assets_load_image_from_file("data/img/panel_bottomright.png");
+ img_panel_topleft = assets_load_image_from_file("data/img/panel_topleft.png");
+ img_panel_topright = assets_load_image_from_file("data/img/panel_topright.png");
+
+ img_button_bottom = assets_load_image_from_file("data/img/button_bottom.png");
+ img_button_top = assets_load_image_from_file("data/img/button_top.png");
+ img_button_left = assets_load_image_from_file("data/img/button_left.png");
+ img_button_right = assets_load_image_from_file("data/img/button_right.png");
+ img_button_bottomleft = assets_load_image_from_file("data/img/button_bottomleft.png");
+ img_button_bottomright = assets_load_image_from_file("data/img/button_bottomright.png");
+ img_button_topleft = assets_load_image_from_file("data/img/button_topleft.png");
+ img_button_topright = assets_load_image_from_file("data/img/button_topright.png");
+
+ img_portrait_body = assets_load_image_from_file("data/img/portrait/body.png");
+ img_portrait_head = assets_load_image_from_file("data/img/portrait/face.png");
+ for (s32 i = 0; i < PORTRAIT_MAX_HAIR_COUNT; i++)
+ {
+ char hair_path[50];
+ sprintf(hair_path, "data/img/portrait/hair/hair%d.png", i+1);
+ img_portrait_hair[i] = assets_load_image_from_file(hair_path);
+
+ }
+
+ // Sound effects
+ snd_click = assets_load_wav_from_file("data/sounds/click.wav");
+ snd_click2 = assets_load_wav_from_file("data/sounds/click2.wav");
+ snd_click3 = assets_load_wav_from_file("data/sounds/click3.wav");
+ snd_event = assets_load_wav_from_file("data/sounds/event.wav");
+ snd_accelerate = assets_load_wav_from_file("data/sounds/accelerate.wav");
+
+ // Songs
+ {
+ platform_set_active_directory(binary_path);
+
+ array files = array_create(sizeof(found_file));
+ array filters = string_split("*.mp3");
+ bool is_cancelled = false;
+ platform_list_files_block(&files, "data/music/", filters, true, 0, true, &is_cancelled, 0);
+ log_assert(files.length < SOUNGS_COUNT, "Not enough space for songs.");
+ for (s32 i = 0; i < files.length; i++)
+ {
+ found_file *file = array_at(&files, i);
+
+ if (platform_file_exists(file->path))
+ {
+ snd_songs[i] = assets_load_music_from_file(file->path);
+ }
+ }
+
+ array_destroy(&files);
+ array_destroy(&filters);
+ }
+}
\ No newline at end of file diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..de41182 --- /dev/null +++ b/src/game.c @@ -0,0 +1,134 @@ +
+static game _game_instance;
+
+static void game_init_current_scene()
+{
+ switch (_game_instance.current_state)
+ {
+ case GAME_STATE_LOADING:
+ loading_scene_init();
+ break;
+ case GAME_STATE_MENU:
+ menu_scene_init();
+ break;
+ case GAME_STATE_SELECT_SAVE:
+ save_state_select_scene_init();
+ break;
+ case GAME_STATE_WORLD_MAP:
+ world_map_scene_init();
+ break;
+ case GAME_STATE_LOADING_WORLD:
+ loading_world_scene_init();
+ break;
+ case GAME_STATE_ERROR:
+ error_scene_init();
+ break;
+ case GAME_STATE_PLACE_DETAIL:
+ place_detail_scene_init();
+ break;
+ case GAME_STATE_SETTINGS:
+ settings_scene_init();
+ break;
+ }
+}
+
+static void game_destroy_current_scene()
+{
+ switch (_game_instance.current_state)
+ {
+ case GAME_STATE_LOADING:
+ loading_scene_destroy();
+ break;
+ case GAME_STATE_MENU:
+ menu_scene_destroy();
+ break;
+ case GAME_STATE_SELECT_SAVE:
+ save_state_select_scene_destroy();
+ break;
+ case GAME_STATE_WORLD_MAP:
+ world_map_scene_destroy();
+ break;
+ case GAME_STATE_LOADING_WORLD:
+ loading_world_scene_destroy();
+ break;
+ case GAME_STATE_ERROR:
+ error_scene_destroy();
+ break;
+ case GAME_STATE_PLACE_DETAIL:
+ place_detail_scene_destroy();
+ break;
+ case GAME_STATE_SETTINGS:
+ settings_scene_destroy();
+ break;
+ }
+}
+
+void game_set_active_scene(game_state state)
+{
+ game_destroy_current_scene();
+ _game_instance.current_state = state;
+ game_init_current_scene();
+}
+
+void game_update(platform_window* window)
+{
+ switch (_game_instance.current_state)
+ {
+ case GAME_STATE_LOADING:
+ loading_scene_update(window);
+ break;
+ case GAME_STATE_MENU:
+ menu_scene_update(window);
+ break;
+ case GAME_STATE_SELECT_SAVE:
+ save_state_select_scene_update(window);
+ break;
+ case GAME_STATE_WORLD_MAP:
+ world_map_scene_update(window);
+ break;
+ case GAME_STATE_LOADING_WORLD:
+ loading_world_scene_update(window);
+ break;
+ case GAME_STATE_ERROR:
+ error_scene_update(window);
+ break;
+ case GAME_STATE_PLACE_DETAIL:
+ place_detail_scene_update(window);
+ break;
+ case GAME_STATE_SETTINGS:
+ settings_scene_update(window);
+ break;
+ }
+}
+
+void game_render(platform_window* window)
+{
+ switch (_game_instance.current_state)
+ {
+ case GAME_STATE_LOADING:
+ loading_scene_render(window);
+ break;
+ case GAME_STATE_MENU:
+ menu_scene_render(window);
+ break;
+ case GAME_STATE_SELECT_SAVE:
+ save_state_select_scene_render(window);
+ break;
+ case GAME_STATE_WORLD_MAP:
+ world_map_scene_render(window);
+ break;
+ case GAME_STATE_LOADING_WORLD:
+ loading_world_scene_render(window);
+ break;
+ case GAME_STATE_ERROR:
+ error_scene_render(window);
+ break;
+ case GAME_STATE_PLACE_DETAIL:
+ place_detail_scene_render(window);
+ break;
+ case GAME_STATE_SETTINGS:
+ settings_scene_render(window);
+ break;
+ }
+ update_render_tooltip();
+}
\ No newline at end of file diff --git a/src/include/data.h b/src/include/data.h new file mode 100644 index 0000000..1f13791 --- /dev/null +++ b/src/include/data.h @@ -0,0 +1,100 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_DATA
+#define INCLUDE_DATA
+
+#define FONT_SIZE_SPACING 4
+#define FONT_COUNT 20
+#define FONT_START 8
+
+image* img_logo_fruitosis;
+
+image* img_truck_unknown;
+image* img_iveco_stralis_activespace;
+image* img_iveco_stralis_hiway;
+
+image* img_logo_mercedes;
+image* img_logo_iveco;
+image* img_logo_volvo;
+
+image* img_white;
+image* img_location_pin;
+image* img_city;
+image* img_boat;
+image* img_star;
+image* img_road;
+image* img_timer;
+image* img_coins;
+image* img_arrow_left_rounded;
+image* img_globe;
+image* img_questionmark;
+image* img_checkmark;
+image* img_grid;
+image* img_lock;
+image* img_arrow_left;
+image* img_arrow_right;
+image* img_logo;
+image* img_pause;
+image* img_close;
+image* img_back;
+image* img_locationdot;
+image* img_dot;
+image* img_carwheel;
+image* img_graph;
+image* img_list;
+image* img_bank;
+image* img_tabitem;
+image* img_portrait;
+image* img_resume;
+image* img_signature;
+image* img_hired;
+image* img_denied;
+image* img_world_map;
+
+image* img_button_bottom;
+image* img_button_top;
+image* img_button_left;
+image* img_button_right;
+image* img_button_bottomleft;
+image* img_button_bottomright;
+image* img_button_topleft;
+image* img_button_topright;
+
+image* img_panel_bottom;
+image* img_panel_top;
+image* img_panel_left;
+image* img_panel_right;
+image* img_panel_bottomleft;
+image* img_panel_bottomright;
+image* img_panel_topleft;
+image* img_panel_topright;
+
+#define PORTRAIT_MAX_HAIR_COUNT 5
+image* img_portrait_body;
+image* img_portrait_head;
+image* img_portrait_hair[PORTRAIT_MAX_HAIR_COUNT];
+
+font* font_regular[FONT_COUNT];
+
+sound* snd_click;
+sound* snd_click2;
+sound* snd_click3;
+sound* snd_event;
+sound* snd_accelerate;
+
+#define SOUNGS_COUNT 30
+sound* snd_songs[SOUNGS_COUNT];
+
+void data_load();
+
+font empty_font_d = {0};
+
+#define SIZE_RDF(_w, _size) ((s32)(_size * (_w) + 3) & ~0x03)
+#define SIZE_RD(_w, _size) ((s32)((_size * (_w/1280.0f)) + 3) & ~0x03)
+#define FONT_REGULAR(_size) (_size < FONT_START || _size > (FONT_START+(FONT_SIZE_SPACING*FONT_COUNT))) ? (&empty_font_d) : font_regular[(_size-FONT_START)/FONT_SIZE_SPACING];
+
+#endif
\ No newline at end of file diff --git a/src/include/game.h b/src/include/game.h new file mode 100644 index 0000000..2c09ada --- /dev/null +++ b/src/include/game.h @@ -0,0 +1,31 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_GAME
+#define INCLUDE_GAME
+
+typedef enum t_game_state
+{
+ GAME_STATE_LOADING = 1,
+ GAME_STATE_MENU = 2,
+ GAME_STATE_SELECT_SAVE = 3,
+ GAME_STATE_WORLD_MAP = 4,
+ GAME_STATE_LOADING_WORLD = 5,
+ GAME_STATE_ERROR = 6,
+ GAME_STATE_PLACE_DETAIL = 7,
+ GAME_STATE_SETTINGS = 8,
+} game_state;
+
+typedef struct t_game
+{
+ game_state current_state;
+} game;
+
+void game_set_active_scene(game_state state);
+void game_update(platform_window* window);
+void game_render(platform_window* window);
+
+#endif
\ No newline at end of file diff --git a/src/include/scenery.h b/src/include/scenery.h new file mode 100644 index 0000000..08afec0 --- /dev/null +++ b/src/include/scenery.h @@ -0,0 +1,29 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_SCENERY
+#define INCLUDE_SCENERY
+
+#define BOAT_ROUTE_MAX_POINTS 300
+
+typedef struct t_boat_route_point
+{
+ float x;
+ float y;
+} boat_route_point;
+
+typedef struct t_boat_route
+{
+ boat_route_point points[BOAT_ROUTE_MAX_POINTS];
+ u8 count;
+ u8 current_point;
+ float current_point_duration;
+ bool reversed;
+} boat_route;
+
+void update_render_scenery(world* world);
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/error_scene.h b/src/include/scenes/error_scene.h new file mode 100644 index 0000000..b2b9a0d --- /dev/null +++ b/src/include/scenes/error_scene.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_ERROR_SCENE
+#define INCLUDE_ERROR_SCENE
+
+void error_scene_init();
+void error_scene_render(platform_window* window);
+void error_scene_update(platform_window* window);
+void error_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/loading_scene.h b/src/include/scenes/loading_scene.h new file mode 100644 index 0000000..3e49a9a --- /dev/null +++ b/src/include/scenes/loading_scene.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_LOADING_SCENE
+#define INCLUDE_LOADING_SCENE
+
+void loading_scene_init();
+void loading_scene_render(platform_window* window);
+void loading_scene_update(platform_window* window);
+void loading_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/loading_world_scene.h b/src/include/scenes/loading_world_scene.h new file mode 100644 index 0000000..864fe8d --- /dev/null +++ b/src/include/scenes/loading_world_scene.h @@ -0,0 +1,16 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_LOADING_WORLD_SCENE
+#define INCLUDE_LOADING_WORLD_SCENE
+
+void loading_world_scene_init();
+void start_loading_world(char* saved_file_path);
+void loading_world_scene_render(platform_window* window);
+void loading_world_scene_update(platform_window* window);
+void loading_world_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/menu_scene.h b/src/include/scenes/menu_scene.h new file mode 100644 index 0000000..e68b778 --- /dev/null +++ b/src/include/scenes/menu_scene.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_MENU_SCENE
+#define INCLUDE_MENU_SCENE
+
+void menu_scene_init();
+void menu_scene_render(platform_window* window);
+void menu_scene_update(platform_window* window);
+void menu_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/place_detail.h b/src/include/scenes/place_detail.h new file mode 100644 index 0000000..91c34ab --- /dev/null +++ b/src/include/scenes/place_detail.h @@ -0,0 +1,16 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_PLACE_DETAIL_SCENE
+#define INCLUDE_PLACE_DETAIL_SCENE
+
+void place_detail_scene_init();
+void place_detail_set_active_location(world_location* location);
+void place_detail_scene_render(platform_window* window);
+void place_detail_scene_update(platform_window* window);
+void place_detail_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/save_state_select.h b/src/include/scenes/save_state_select.h new file mode 100644 index 0000000..260bec2 --- /dev/null +++ b/src/include/scenes/save_state_select.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_SELECT_SAVE_SCENE
+#define INCLUDE_SELECT_SAVE_SCENE
+
+void save_state_select_scene_init();
+void save_state_select_scene_render(platform_window* window);
+void save_state_select_scene_update(platform_window* window);
+void save_state_select_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/settings_scene.h b/src/include/scenes/settings_scene.h new file mode 100644 index 0000000..701e6a9 --- /dev/null +++ b/src/include/scenes/settings_scene.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_SETTINGS_SCENE
+#define INCLUDE_SETTINGS_SCENE
+
+void settings_scene_init();
+void settings_scene_render(platform_window* window);
+void settings_scene_update(platform_window* window);
+void settings_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/scenes/world_map.h b/src/include/scenes/world_map.h new file mode 100644 index 0000000..d678868 --- /dev/null +++ b/src/include/scenes/world_map.h @@ -0,0 +1,16 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_WORLD_MAP_SCENE
+#define INCLUDE_WORLD_MAP_SCENE
+
+void world_map_set_active_world(world* world);
+void world_map_scene_init();
+void world_map_scene_render(platform_window* window);
+void world_map_scene_update(platform_window* window);
+void world_map_scene_destroy();
+
+#endif
\ No newline at end of file diff --git a/src/include/settings.h b/src/include/settings.h new file mode 100644 index 0000000..cba99ad --- /dev/null +++ b/src/include/settings.h @@ -0,0 +1,28 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_SETTINGS
+#define INCLUDE_SETTINGS
+
+#define AUDIO_CHANNEL_SFX_1 1
+#define AUDIO_CHANNEL_SFX_2 2
+#define AUDIO_CHANNEL_SFX_3 3
+
+u16 key_back = KEY_ESCAPE;
+u16 key_accept = KEY_ENTER;
+u16 key_insights_graph = KEY_F1;
+u16 key_insights_chart = KEY_F2;
+u16 key_events = KEY_F3;
+u16 key_bank = KEY_F4;
+
+float volume_global = 0.2f;
+float volume_music = 0.2f;
+float volume_sfx = 0.2f;
+
+bool option_vsync = true;
+bool option_fullscreen = false;
+
+#endif
\ No newline at end of file diff --git a/src/include/tooltip.h b/src/include/tooltip.h new file mode 100644 index 0000000..8748c81 --- /dev/null +++ b/src/include/tooltip.h @@ -0,0 +1,18 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_TOOPTIP
+#define INCLUDE_TOOPTIP
+
+char tooltip_buffer[100];
+s32 tooltip_x = 0;
+s32 tooltip_y = 0;
+bool tooltop_visible = false;
+
+void show_tooltip(s32 x, s32 y, char* buf);
+void update_render_tooltip();
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/animation.h b/src/include/ui/animation.h new file mode 100644 index 0000000..1a10c0f --- /dev/null +++ b/src/include/ui/animation.h @@ -0,0 +1,24 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_ANIMATION
+#define INCLUDE_ANIMATION
+
+typedef struct t_animation
+{
+ float time;
+ bool started;
+ float duration;
+ float percentage;
+} animation;
+
+#define AN_LI(_cx,_dx,_an) (_cx + (_dx-_cx)*_an.percentage)
+#define AN_LI_TINT(_color, _an) rgba((_color).r,(_color).g,(_color).b,255*_an.percentage)
+
+animation animation_create(s32 duration);
+float animation_update(animation* an);
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/button.h b/src/include/ui/button.h new file mode 100644 index 0000000..e381631 --- /dev/null +++ b/src/include/ui/button.h @@ -0,0 +1,20 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_BUTTON
+#define INCLUDE_BUTTON
+
+typedef enum t_button_type
+{
+ BUTTON_STATIC = 0,
+ BUTTON_ENABLED = 1,
+ BUTTON_DISABLED = 2,
+ BUTTON_HIGHLIGHTED = 3,
+} button_type;
+
+bool button_render(float scale, button_type enabled, char* text, s32 x, s32 y, s32 w, s32 h);
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/colors.h b/src/include/ui/colors.h new file mode 100644 index 0000000..f8a7f91 --- /dev/null +++ b/src/include/ui/colors.h @@ -0,0 +1,62 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_COLORS
+#define INCLUDE_COLORS
+
+#define COLOR_WORLD_MAP_BACKGROUND rgb(32,52,63)
+#define COLOR_WHITE rgb(255,255,255)
+#define COLOR_BLACK rgb(0,0,0)
+#define COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION rgb(40,40,40)
+#define COLOR_DOT_HOVERED rgb(100,220,100)
+
+#define COLOR_TEXT_NEGATIVE rgb(226,86,86)
+#define COLOR_TITLE rgb(8, 10, 12)
+#define COLOR_TEXT_SHADOW rgb(24,24,24)
+#define COLOR_TEXT rgb(207,207,207)
+
+#define COLOR_BUTTON_DISABLED_TINT rgb(70,70,70)
+
+#define COLOR_BUTTON_HIGHLIGHTED_TINT rgb(240,160,160)
+#define COLOR_BUTTON_ACTIVE_TINT rgb(210,210,210)
+#define COLOR_PANEL_BACKGROUND rgb(66,63,58)
+
+#define COLOR_BUTTON rgb(98, 95, 90)
+#define COLOR_BUTTON_ACTIVE rgb(81, 78, 74)
+#define COLOR_BUTTON_HIGHLIGHTED_ACTIVE rgb(92, 60, 56)
+#define COLOR_BUTTON_DISABLED rgb(27, 26, 25)
+
+#define COLOR_LOCATION_DOT_UNOWNED rgb(220,220,220)
+#define COLOR_LOCATION_DOT_OWNED rgb(220,100,100)
+
+#define COLOR_LIST_ENTRY_BACKGROUND rgb(46,43,40)
+#define COLOR_LIST_ENTRY_BACKGROUND_ACTIVE rgb(63,59,56)
+
+#define COLOR_SCHEDULE_ROW_ACTIVE rgb(118,115,100)
+#define COLOR_SCHEDULE_TILE_FIXED rgb(178,239,155)
+#define COLOR_SCHEDULE_TILE_HOVERED rgb(26,200,237)
+#define COLOR_SCHEDULE_TILE_INVALID rgb(244,70,73)
+#define COLOR_SCHEDULE_TILE_INVALID_SELECTED rgb(252,159,160)
+#define COLOR_SCHEDULE_TILE_SELECTED rgb(174,212,230)
+#define COLOR_SCHEDULE_TILE_HIGHLIGHTED rgb(237,177,26)
+
+#define COLOR_SELECTOR_UNDERLINE rgb(180,180,180)
+
+#define LEGENDA_HOVER_BACKGROUND_COLOR rgba(255,0,0,50)
+#define LEGENDA_COLOR_DISABLED rgb(120,120,120)
+#define LEGENDA_SUB_COLOR_DISABLED rgba(120,120,120,100)
+
+#define COLOR_SCHEDULE_BG rgb(142,138,132)
+#define COLOR_SCHEDULE_BORDER rgb(75,73,69)
+#define COLOR_SCHEDULE_BORDER_THIN rgb(88,85,80)
+
+#define COLOR_TEXTBOX_TINT rgb(100,100,100)
+#define COLOR_TEXTBOX_FILL rgb(38, 37, 35)
+
+#define COLOR_WRONG rgb(168,45,45)
+#define COLOR_CORRECT rgb(47,168,45)
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/panel.h b/src/include/ui/panel.h new file mode 100644 index 0000000..83103d2 --- /dev/null +++ b/src/include/ui/panel.h @@ -0,0 +1,15 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_PANEL
+#define INCLUDE_PANEL
+
+// 1280 is our reference width.
+#define UI_SCALE(_w) (_w/1280.0f)
+
+void panel_render(float scale, s32 x, s32 y, s32 w, s32 h);
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/portrait.h b/src/include/ui/portrait.h new file mode 100644 index 0000000..8bff8e1 --- /dev/null +++ b/src/include/ui/portrait.h @@ -0,0 +1,28 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_PORTRAIT
+#define INCLUDE_PORTRAIT
+
+color hair_palette[] = {
+ rgb(199, 186, 168), rgb(188, 181, 160), rgb(191, 173, 148), rgb(203, 181, 138), rgb(187, 162, 120),
+ rgb(174, 153, 122), rgb(172, 134, 109), rgb(205, 169, 129), rgb(168, 115, 88), rgb(137, 82, 71),
+ rgb(158, 131, 99), rgb(150, 116, 93), rgb(128, 93, 73), rgb(202, 162, 136), rgb(197, 146, 137),
+ rgb(194, 136, 129), rgb(165, 127, 117), rgb(152, 111, 113), rgb(123, 103, 93), rgb(98, 79, 73)
+};
+
+color skin_palette[] = {
+ rgb(233, 203, 167), rgb(238, 208, 183), rgb(247, 221, 196), rgb(247, 226, 171), rgb(239, 199, 148), rgb(239, 192, 136),
+ rgb(231, 188, 145), rgb(236, 192, 131), rgb(208, 158, 125), rgb(203, 150, 98), rgb(171, 139, 100), rgb(148, 98, 61),
+};
+
+color body_palette[] = {
+ rgb(33, 28, 32), rgb(76, 74, 77), rgb(109, 103, 107), rgb(171, 133, 86), rgb(213, 175, 126), rgb(240, 229, 225),
+};
+
+void draw_employee_portrait(employee* emp, float x, float y, float w, float h);
+
+#endif
\ No newline at end of file diff --git a/src/include/ui/selectors.h b/src/include/ui/selectors.h new file mode 100644 index 0000000..6832ff7 --- /dev/null +++ b/src/include/ui/selectors.h @@ -0,0 +1,13 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_EMPLOYEE_SELECTOR
+#define INCLUDE_EMPLOYEE_SELECTOR
+
+employee* employee_selector_render(platform_window* window, float scale, bool enabled, employee* current_val, s32 x, s32 y, s32 w, s32 h, animation an, scheduled_job* offer);
+world_location* location_selector_render(platform_window* window, float scale, bool enabled, world_location* current_val, s32 x, s32 y, s32 w, s32 h);
+
+#endif
\ No newline at end of file diff --git a/src/include/world.h b/src/include/world.h new file mode 100644 index 0000000..4f8af10 --- /dev/null +++ b/src/include/world.h @@ -0,0 +1,383 @@ +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_WORLD
+#define INCLUDE_WORLD
+
+#define MAX_WORLD_LOCATION_NAME_LENGTH 20
+#define MAX_ENPOLYEE_FIRSTNAME_LENGTH 14
+#define MAX_ENPOLYEE_LASTNAME_LENGTH 14
+#define MAX_EMPLOYEE_NAME_LENGTH 30
+#define MAX_COMPANY_NAME_LENGTH 50
+#define MAX_DEALER_NAME_LENGTH 20
+#define MAX_TRUCK_NAME_LENGTH 30
+#define MAX_PRODUCT_NAME_LENGTH 50
+#define MAX_EMPLOYEE_NR_LENGTH 12
+#define MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR 10
+
+// Static = loaded from file
+// Save State = loaded from save state
+// Dynamic = set at runtime
+
+#define MINUTES(_n) (_n*60)
+#define HOURS(_n) (_n*MINUTES(60))
+#define DAYS(_n) (_n*HOURS(24))
+
+typedef struct t_world_location world_location;
+typedef struct t_employee employee;
+
+#define WORK_HOUR_START 8
+#define WORK_HOUR_END 20
+#define TIME_SLOTS_PER_HOUR 4
+#define TIME_SLOTS_PER_DAY ((WORK_HOUR_END-WORK_HOUR_START)*TIME_SLOTS_PER_HOUR)
+#define TIME_SLOTS_PER_WEEK (TIME_SLOTS_PER_DAY*7)
+
+#define MAX_JOBOFFER_COUNT 25
+#define MAX_EMPLOYEE_COUNT (TIME_SLOTS_PER_WEEK)
+#define MAX_TRUCK_COUNT (TIME_SLOTS_PER_WEEK)
+
+#define MISSED_DELIVERY_TRUST_PENALTY (0.5f)
+#define MAX_EFFECTIVE_EXPERIENCE 25.0f // anything past 25 years of experience has no extra positives.
+#define SHIPTIME_DURATION_MULTIPLIER_MAX 1.0f
+#define SHIPTIME_DURATION_MULTIPLIER_MIN 1.15f
+#define DIESEL_PRICE_PER_LITER 1.4f
+
+#define INVALID_ID 0
+#define MAX_WORKED_HOURS_WEEKLY (45.0f)
+#define MINIMUM_EMPLOYEE_HAPPINESS (0.4f)
+#define EMPLOYEE_MAX_UNHAPPY_DAYS_BEFORE_QUITTING (60.0f)
+
+#define CDAYTORDAY(_day) (_day == 0 ? 7 : _day) // m = 1, s = 7
+#define RDAYTOCDAY(_day) (_day == 7 ? 0 : _day) // m = 1, s = 0
+
+#define BASE_PAY 1800
+#define RAISE_PER_YEAR 55
+#define MAX_PAY 3250
+
+typedef enum t_minor_event
+{
+ EXTERNAL_INSPECTION, // Check overworking, safety
+} minor_event;
+
+typedef enum t_weekday
+{
+ MONDAY = 1,
+ TUESDAY = 2,
+ WEDNESDAY = 3,
+ THURSDAY = 4,
+ FRIDAY = 5,
+ SATURDAY = 6,
+ SUNDAY = 0,
+
+ DAY_INVALID = 99
+} weekday;
+
+typedef struct t_product
+{
+ char name[MAX_PRODUCT_NAME_LENGTH];
+} product;
+
+typedef struct t_company
+{
+ // Static
+ char name[MAX_COMPANY_NAME_LENGTH];
+ array products;
+
+ // Dynamic
+ image* logo;
+} company;
+
+typedef struct t_truck
+{
+ // Static
+ char name[MAX_TRUCK_NAME_LENGTH];
+ u16 hp;
+ u32 price;
+ u16 fuelcapacity;
+ u16 torque;
+ float fuelusage;
+
+ // Dynamic
+ image* logo;
+
+ // Save State
+ s32 type;
+ s32 id;
+ employee* assigned_employee;
+} truck;
+
+typedef struct t_truck_dealer
+{
+ // Static
+ char name[MAX_DEALER_NAME_LENGTH];
+ array trucks;
+
+ // Dynamic
+ image* logo;
+} truck_dealer;
+
+#define JOB_OFFER_REWARD_PER_CONNECTION 160
+#define MAX_SHIPDAYS 4
+
+typedef struct t_job_offer
+{
+ u32 id;
+ s64 expire_date;
+ company* company;
+ product* product;
+ s32 shipday_count;
+ weekday shipdays[MAX_SHIPDAYS];
+ u32 reward;
+ array connections; // Should not be freed if offer has been accepted.
+ double total_distance; // in KM
+ time_t duration_sec_min; // experienced drivers
+ time_t duration_sec_max; // inexperienced drivers
+} job_offer;
+
+typedef struct t_employee
+{
+ u32 id;
+ char name[MAX_EMPLOYEE_NAME_LENGTH];
+ u8 age;
+ struct tm hire_date;
+ u8 experience;
+ float salary;
+ float happiness;
+ s16 days_below_happiness_treshold;
+ u32 current_location_id;
+ u32 original_location_id;
+ truck* assigned_truck;
+ u32 active_job_id;
+
+ // Portrait
+ u8 portrait_hair_type;
+ color hair_color;
+ color face_color;
+ color body_color;
+} employee;
+
+#define RESUME_FADEOUT_MS 300
+typedef struct t_resume
+{
+ employee* employee;
+ s64 expire_date;
+ bool hired;
+ animation animation;
+} resume;
+
+typedef struct t_scheduled_job_time
+{
+ s16 day; // sunday = 0
+ s16 timeslot;
+ bool stay_at_destination;
+ employee* assignee;
+} scheduled_job_time;
+
+typedef struct t_scheduled_job
+{
+ float trust;
+ job_offer offer;
+ world_location* location;
+ scheduled_job_time timeslots[MAX_SHIPDAYS];
+} scheduled_job;
+
+typedef struct t_active_job
+{
+ // save state
+ s16 day;
+ s16 timeslot;
+ bool stay_at_destination;
+ job_offer offer;
+ employee assignee;
+ truck assigned_truck;
+ time_t duration_sec;
+ time_t left_at;
+ time_t done_at;
+ bool reversed;
+
+ // dynamic
+ vec2f px_pos;
+ bool is_hovered;
+} active_job;
+
+typedef struct t_active_job_ref
+{
+ s16 day;
+ s16 timeslot;
+ u32 offerid;
+} active_job_ref;
+
+typedef struct t_world_update_result
+{
+ active_job* clicked_job;
+ world_location* clicked_location;
+} world_update_result;
+
+#define NUM_DAYS 7
+typedef struct t_schedule
+{
+ array jobs;
+} schedule;
+
+typedef struct t_world_location
+{
+ // Static
+ u8 size;
+ double latitude;
+ double longitude;
+ char name[MAX_WORLD_LOCATION_NAME_LENGTH];
+ s32 map_position_x;
+ s32 map_position_y;
+
+ // Save State
+ bool is_owned;
+ array employees; // Contains internal and external employees. Employee can be at 2 locations at any given time.
+ array job_offers;
+ array resumes;
+ array trucks;
+ float reliability;
+ schedule schedule;
+ u16 purchase_year;
+ array insights;
+
+ // Dynamic
+ array connections;
+ bool is_hovered;
+ u32 id;
+} world_location;
+
+typedef struct t_job_endpoints
+{
+ world_location* source;
+ world_location* dest;
+} job_endpoints;
+
+typedef enum t_event_type
+{
+ EVENT_TYPE_MISSED_SHIPMENT_NO_TRUCK, // go to employee detail
+ EVENT_TYPE_MISSED_SHIPMENT_NOT_AT_LOCATION, // go to schedule
+ EVENT_TYPE_MISSED_SHIPMENT_NO_ASSIGNEE, // go to schedule
+ EVENT_TYPE_EMPLOYEE_QUIT, // go to schedule
+} event_type;
+
+#define MAX_EVENT_MESSAGE_LENGTH 150
+
+typedef struct t_event
+{
+ void* data;
+ event_type type;
+ scheduled_job_time job_time;
+ char message[MAX_EVENT_MESSAGE_LENGTH];
+} event;
+
+#define MIN_SIMULATION_SPEED 0
+#define MAX_SIMULATION_SPEED 8
+
+#define LOG_HISTORY_LENGTH 25
+
+typedef struct t_event_log
+{
+ array events;
+ u16 write_cursor;
+ bool has_unread_messages;
+} event_log;
+
+#define ADD_EXPENSE(_world,_loc,_var,_amount)\
+ {\
+ _world->money -= _amount;\
+ money_data_collection* collection = get_current_insights_data(_world);\
+ collection->months[_world->current_time.tm_mon].total_expenses -= _amount;\
+ collection->months[_world->current_time.tm_mon].total_profit -= _amount;\
+ collection->months[_world->current_time.tm_mon]._var -= _amount;\
+ if (_loc) {\
+ collection = get_current_insights_data_for_location(_world,_loc);\
+ collection->months[_world->current_time.tm_mon].total_expenses -= _amount;\
+ collection->months[_world->current_time.tm_mon].total_profit -= _amount;\
+ collection->months[_world->current_time.tm_mon]._var -= _amount;}\
+ }
+
+#define ADD_INCOME(_world,_loc,_var,_amount)\
+ {\
+ _world->money += _amount;\
+ money_data_collection* collection = get_current_insights_data(_world);\
+ collection->months[_world->current_time.tm_mon].total_income += _amount;\
+ collection->months[_world->current_time.tm_mon].total_profit += _amount;\
+ collection->months[_world->current_time.tm_mon]._var += _amount;\
+ if (_loc) {\
+ collection = get_current_insights_data_for_location(_world,_loc);\
+ collection->months[_world->current_time.tm_mon].total_income += _amount;\
+ collection->months[_world->current_time.tm_mon].total_profit += _amount;\
+ collection->months[_world->current_time.tm_mon]._var += _amount;}\
+ }
+
+#define EXPENSES get_current_insights_data(world)->months[world->current_time.tm_mon]
+
+typedef struct t_money_data
+{
+ float total_income;
+ float total_expenses;
+ float total_profit;
+
+ float income_from_trips;
+
+ float expenses_from_trucks;
+ float expenses_from_utility;
+ float expenses_from_healthcare;
+ float expenses_from_repairs;
+ float expenses_from_fuel;
+ float expenses_from_employees;
+} money_data;
+
+#define MONTHS_IN_YEAR 12
+
+typedef struct t_money_data_collection
+{
+ money_data months[MONTHS_IN_YEAR];
+} money_data_collection;
+
+typedef struct t_company_investments
+{
+ u32 safety;
+ u32 marketing;
+ u32 human_resources;
+ u32 training;
+ u32 legal;
+} company_investments;
+
+typedef struct t_world
+{
+ // Save State
+ s64 simulation_time;
+ u16 start_year;
+ float money;
+ u32 next_id;
+ u8 simulation_speed;
+ array active_jobs;
+ event_log log;
+ array insights;
+ company_investments investments;
+ u16 days_since_last_random_event;
+
+ // Dynamic
+ array locations;
+ array companies;
+ array firstnames;
+ array lastnames;
+ array truck_dealers;
+ array boat_routes;
+ struct tm current_time;
+} world;
+
+world* world_create_new();
+void world_report_event(world* world, char* msg, event_type type, void* data);
+world_location* get_world_location_by_id(world* world, s32 id);
+world_location* get_world_location_by_name(world* world, char* str);
+float world_location_get_price(world_location* location);
+void add_truck_to_world_location(world* world, world_location* location, truck* tr);
+void world_update(platform_window* window, world* world);
+world_update_result world_render(platform_window* window, world* world);
+
+#endif
\ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ce94b9c --- /dev/null +++ b/src/main.c @@ -0,0 +1,182 @@ +#define ASSET_FONT_COUNT 25
+#define ASSET_WORKER_COUNT 4
+#define ASSET_QUEUE_COUNT 100
+#define ASSET_IMAGE_COUNT 70
+#define ASSET_SOUND_COUNT 30
+#define NUM_AUDIO_CHANNELS 8
+#define GAME_VERSION "0.1"
+
+#include "../project-base/src/project_base.h"
+
+platform_window* main_window;
+
+vec4 area;
+float scale = 1.0f;
+float zoom = 1.0f;
+float camera_x = 0.0f;
+float camera_y = 0.0f;
+font* fnt_rd8;
+font* fnt_rd12;
+font* fnt_rd16;
+font* fnt_rd20;
+font* fnt_rd24;
+font* fnt_rd28;
+font* fnt_rd32;
+font* fnt_rd36;
+font* fnt_rd40;
+font* fnt_rd44;
+font* fnt_rd48;
+
+#include "include/settings.h"
+#include "include/ui/colors.h"
+#include "include/ui/animation.h"
+#include "include/world.h"
+#include "include/ui/portrait.h"
+#include "include/scenery.h"
+#include "include/data.h"
+#include "include/game.h"
+#include "include/tooltip.h"
+#include "include/ui/panel.h"
+#include "include/ui/button.h"
+#include "include/ui/selectors.h"
+#include "include/scenes/menu_scene.h"
+#include "include/scenes/loading_scene.h"
+#include "include/scenes/save_state_select.h"
+#include "include/scenes/world_map.h"
+#include "include/scenes/loading_world_scene.h"
+#include "include/scenes/error_scene.h"
+#include "include/scenes/place_detail.h"
+#include "include/scenes/settings_scene.h"
+
+#include "music.c"
+#include "world.c"
+#include "data.c"
+#include "game.c"
+#include "scenery.c"
+#include "ui/panel.c"
+#include "ui/button.c"
+#include "ui/animation.c"
+#include "ui/portrait.c"
+#include "tooltip.c"
+#include "scenes/menu_scene.c"
+#include "scenes/loading_scene.c"
+#include "scenes/save_state_select.c"
+#include "scenes/world_map.c"
+#include "scenes/loading_world_scene.c"
+#include "scenes/error_scene.c"
+#include "scenes/place_detail.c"
+#include "scenes/settings_scene.c"
+#include "ui/selectors.c"
+
+#define CONFIG_DIRECTORY "trucker_x"
+
+static void draw_debug_overlay(platform_window* window)
+{
+ static bool enabled = false;
+ if (keyboard_is_key_pressed(KEY_F1)) enabled = !enabled;
+ if (!enabled) return;
+
+ renderer->set_render_depth(20);
+
+ renderer->render_rectangle(0,0,200*scale,200*scale,rgb(70,70,70));
+
+ font* fnt = FONT_REGULAR(SIZE_RD(area.w, 24));
+
+ {
+ char deltabuf[20];
+ sprintf(deltabuf, "Frame: %.5f", frame_delta);
+ renderer->render_text(fnt, 10, 10, deltabuf, rgb(255,0,0));
+ }
+
+ {
+ char deltabuf[20];
+ sprintf(deltabuf, "Game: %.5f", update_delta);
+ renderer->render_text(fnt, 10, 10+(fnt->px_h+2)*1, deltabuf, rgb(255,0,0));
+ }
+
+ {
+ char deltabuf[20];
+ sprintf(deltabuf, "FPS: %.0f", 1.0f/frame_delta);
+ renderer->render_text(fnt, 10, 10+(fnt->px_h+2)*2, deltabuf, rgb(255,0,0));
+ }
+
+ renderer->set_render_depth(19);
+}
+
+void update_render_game(platform_window* window)
+{
+ area = camera_get_target_rectangle(window);
+ scale = UI_SCALE(area.w);
+
+ fnt_rd8 = FONT_REGULAR(SIZE_RDF(scale, 8));
+ fnt_rd12 = FONT_REGULAR(SIZE_RDF(scale, 12));
+ fnt_rd16 = FONT_REGULAR(SIZE_RDF(scale, 16));
+ fnt_rd20 = FONT_REGULAR(SIZE_RDF(scale, 20));
+ fnt_rd24 = FONT_REGULAR(SIZE_RDF(scale, 24));
+ fnt_rd28 = FONT_REGULAR(SIZE_RDF(scale, 28));
+ fnt_rd32 = FONT_REGULAR(SIZE_RDF(scale, 32));
+ fnt_rd36 = FONT_REGULAR(SIZE_RDF(scale, 36));
+ fnt_rd40 = FONT_REGULAR(SIZE_RDF(scale, 40));
+ fnt_rd44 = FONT_REGULAR(SIZE_RDF(scale, 44));
+ fnt_rd48 = FONT_REGULAR(SIZE_RDF(scale, 48));
+
+ #ifdef MODE_DEBUG
+ draw_debug_overlay(window);
+ #endif
+
+ game_update(window);
+ game_render(window);
+
+ update_music();
+}
+
+int main(int argc, char** argv)
+{
+ platform_init(argc, argv, CONFIG_DIRECTORY);
+
+ #define VALIDATE_VOLUME(_vol) if (_vol < 0.0f) _vol = 0.0f; else if (_vol > 1.0f) _vol = 1.0f;
+ volume_global = settings_get_number_or_default("v_global", 100) / 100.0f;
+ volume_music = settings_get_number_or_default("v_music", 100) / 100.0f;
+ volume_sfx = settings_get_number_or_default("v_sfx", 100) / 100.0f;
+ option_vsync = settings_get_number_or_default("vsync", 1);
+ option_fullscreen = settings_get_number_or_default("fullscreen", 1);
+ VALIDATE_VOLUME(volume_global);
+ VALIDATE_VOLUME(volume_music);
+ VALIDATE_VOLUME(volume_sfx);
+
+ s32 window_w = settings_get_number_or_default("window_w", 1280);
+ s32 window_h = settings_get_number_or_default("window_h", 720);
+
+ main_window = platform_open_window("TruckerX",
+ window_w, window_h,
+ 9999, 9999,
+ 960, 540 + platform_get_titlebar_height(),
+ update_render_game, 0);
+
+ platform_toggle_vsync(main_window, option_vsync);
+ if (option_fullscreen) platform_toggle_fullscreen(main_window, option_fullscreen);
+
+ data_load();
+ game_set_active_scene(GAME_STATE_LOADING);
+
+ audio_set_mixer_volume(AUDIO_CHANNEL_SFX_1, volume_sfx*volume_global);
+ audio_set_mixer_volume(AUDIO_CHANNEL_SFX_2, volume_sfx*volume_global);
+
+ while(platform_keep_running(main_window)) {
+ main_window->do_draw = true;
+ platform_handle_events();
+ }
+
+ settings_set_number("window_w", main_window->width);
+ settings_set_number("window_h", main_window->height + platform_get_titlebar_height());
+ settings_set_number("v_global", volume_global*100);
+ settings_set_number("v_music", volume_music*100);
+ settings_set_number("v_sfx", volume_sfx*100);
+ settings_set_number("vsync", option_vsync);
+ settings_set_number("fullscreen", option_fullscreen);
+
+ settings_write_to_file();
+ platform_destroy();
+
+ return 0;
+}
\ No newline at end of file diff --git a/src/music.c b/src/music.c new file mode 100644 index 0000000..c85b63c --- /dev/null +++ b/src/music.c @@ -0,0 +1,22 @@ +
+void update_music()
+{
+ static s32 current_song_index = 0;
+ if (!audio_music_is_playing()) {
+ sound* snd = snd_songs[current_song_index];
+ if (!snd) {
+ current_song_index = 0;
+ }
+ else {
+ if (!snd->loaded) return;
+
+ char buf[MAX_INPUT_LENGTH];
+ sprintf(buf, "Now playing: \"%s\".", (char*)snd->start_addr);
+ log_info(buf);
+
+ audio_set_music_volume(volume_music*volume_global);
+ audio_play_sound(snd, -1);
+ current_song_index++;
+ }
+ }
+}
\ No newline at end of file diff --git a/src/scenery.c b/src/scenery.c new file mode 100644 index 0000000..9e647d6 --- /dev/null +++ b/src/scenery.c @@ -0,0 +1,53 @@ +
+
+static void update_render_path(world* world, boat_route *route)
+{
+ boat_route_point prev_point = route->points[route->current_point];
+ boat_route_point next_point = route->points[route->current_point + (route->reversed ? -1 : 1)];
+
+ float dist = sqrt(pow(prev_point.x - next_point.x, 2) + pow(prev_point.y - next_point.y, 2));
+ float time_between_points = (dist*1000000.0f);
+
+ float percentage = route->current_point_duration/time_between_points;
+
+ vec2f start_pos = {area.x + (prev_point.x*area.w), area.y + (prev_point.y*area.h)};
+ vec2f end_pos = {area.x + (next_point.x*area.w), area.y + (next_point.y*area.h)};
+
+ float currx = start_pos.x - (start_pos.x - end_pos.x)*percentage;
+ float curry = start_pos.y - (start_pos.y - end_pos.y)*percentage;
+
+ vec2f map_pos = {currx*zoom+camera_x, curry*zoom+camera_y};
+
+ float rad = atan2(end_pos.y-start_pos.y, end_pos.x-start_pos.x);
+
+ gl_render_set_rotation(-rad);
+ renderer->render_image(img_boat, map_pos.x-3, map_pos.y-3, 6, 6);
+ gl_render_set_rotation(0.0f);
+
+ route->current_point_duration += (frame_delta*1000.0f)*world->simulation_speed;
+ if (route->current_point_duration > time_between_points) {
+ if (!route->reversed) route->current_point++;
+ else route->current_point--;
+ route->current_point_duration = 0;
+ }
+ if (!route->reversed && route->current_point >= route->count-1) route->reversed = true;
+ if (route->reversed && route->current_point <= 0) route->reversed = false;
+}
+
+void update_render_scenery(world* world) {
+
+ renderer->render_set_scissor(main_window, area.x,area.y,area.w,area.h);
+ for (s32 i = 0; i < world->boat_routes.length; i++) {
+ boat_route* route = array_at(&world->boat_routes, i);
+ update_render_path(world, route);
+ }
+ renderer->render_reset_scissor();
+
+
+#if 0
+ static s32 count = 0;
+ if (is_left_down() && count++ % 10 == 0) {
+ printf("%f, %f,\n", (_global_mouse.x-area.x)/(float)area.w, (_global_mouse.y-area.y)/(float)area.h);
+ }
+#endif
+}
\ No newline at end of file diff --git a/src/scenes/error_scene.c b/src/scenes/error_scene.c new file mode 100644 index 0000000..8d4446a --- /dev/null +++ b/src/scenes/error_scene.c @@ -0,0 +1,74 @@ +
+void error_scene_init()
+{
+
+}
+
+static void error_scene_draw_info(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ float vertical_pad = 20 * scale;
+ float horizontal_pad = vertical_pad;
+ float spacing = 5 * scale;
+
+ s32 panel_h = 280 * scale;
+ s32 panel_item_size = (panel_h - (vertical_pad*2) - (spacing*1)) / 2;
+ s32 panel_w = (panel_item_size * 3) + (horizontal_pad*2) + (spacing*2);
+
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // info text
+ {
+ {
+ char* title = "ERROR";
+ font* font_title = FONT_REGULAR(SIZE_RD(area.w, 32));
+ s32 text_w = renderer->calculate_text_width(font_title, title);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = panel_y + (vertical_pad*2);
+ renderer->render_text(font_title, text_x+2, text_y+2, title, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_title, text_x, text_y, title, COLOR_TEXT);
+ }
+ {
+ char* text = "An error occured, please verify\nyour game files.";
+ font* font_info = FONT_REGULAR(SIZE_RD(area.w, 28));
+ s32 text_w = panel_w - (horizontal_pad*4);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = screen_center_y - (font_info->px_h/2);
+ renderer->render_text_cutoff(font_info, text_x+2, text_y+2, text, COLOR_TEXT_SHADOW, 9999);
+ renderer->render_text_cutoff(font_info, text_x, text_y, text, COLOR_TEXT, 9999);
+ }
+
+ }
+
+ // back button
+ {
+ s32 back_h = img_back->height * scale/2;
+ s32 back_w = img_back->width * scale/2;
+ s32 back_x = panel_x + (panel_item_size/3);
+ s32 back_y = panel_y + panel_h - (back_h/2) - 1;
+
+ if (push_back_button(scale, back_x, back_y, back_w, back_h)) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+ }
+}
+
+void error_scene_render(platform_window* window)
+{
+ menu_draw_background(window);
+ error_scene_draw_info(window);
+}
+
+void error_scene_update(platform_window* window)
+{
+
+}
+
+void error_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/loading_scene.c b/src/scenes/loading_scene.c new file mode 100644 index 0000000..2240aa8 --- /dev/null +++ b/src/scenes/loading_scene.c @@ -0,0 +1,85 @@ +
+#define MAX_CREDITED_NAMES 5
+#define MAX_CREDIT_NAME_LENGTH 30
+#define COMPLETE_CREDIT_LENGTH (MAX_CREDIT_NAME_LENGTH*MAX_CREDITED_NAMES)+20
+char complete_credit_text[COMPLETE_CREDIT_LENGTH];
+
+void loading_scene_init()
+{
+ strcpy(complete_credit_text, "Music by ");
+
+ // Load names to credit.
+ {
+ platform_set_active_directory(binary_path);
+
+ array files = array_create(sizeof(found_file));
+ array filters = string_split("AUTHOR.txt");
+ bool is_cancelled = false;
+ platform_list_files_block(&files, "data/music/", filters, true, 0, true, &is_cancelled, 0);
+ log_assert(files.length <= MAX_CREDITED_NAMES, "Not enough space for credited names.");
+ for (s32 i = 0; i < files.length; i++)
+ {
+ found_file *file = array_at(&files, i);
+
+ if (platform_file_exists(file->path))
+ {
+ file_content name = platform_read_file_content(file->path, "rb");
+ if (name.file_error) continue;
+
+ string_appendn(complete_credit_text, name.content, COMPLETE_CREDIT_LENGTH);
+ if (i != files.length-1) {
+ string_appendn(complete_credit_text, ", ", COMPLETE_CREDIT_LENGTH);
+ }
+ platform_destroy_file_content(&name);
+ }
+
+ mem_free(file->matched_filter);
+ mem_free(file->path);
+ }
+
+ array_destroy(&files);
+ array_destroy(&filters);
+ }
+}
+
+void loading_scene_render(platform_window* window)
+{
+ renderer->render_rectangle(area.x, area.y, area.w, area.h, COLOR_WHITE);
+
+ font* font_reg = FONT_REGULAR(SIZE_RD(area.w, 36));
+ s32 target_size = area.h/5;
+ s32 logo_text_pad = 20;
+ s32 total_height = target_size + logo_text_pad + font_reg->px_h;
+
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+ s32 logo_x = screen_center_x - (target_size/2);
+ s32 logo_y = screen_center_y - (total_height/2);
+ renderer->render_image(img_logo, logo_x, logo_y, target_size, target_size);
+
+ s32 text_y = logo_y + target_size + logo_text_pad;
+ char* company_name = "Tar Software";
+ s32 company_name_width = renderer->calculate_text_width(font_reg, company_name);
+ s32 text_x = screen_center_x - (company_name_width/2);
+
+ renderer->render_text(font_reg, text_x, text_y, company_name, COLOR_TITLE);
+
+ // Credits
+ font* font_s = FONT_REGULAR(SIZE_RD(area.w, 20));
+ s32 credit_pad = 30*scale;
+ renderer->render_text(font_s, area.x + credit_pad, area.y+area.h-credit_pad-font_s->px_h, complete_credit_text, COLOR_TITLE);
+}
+
+void loading_scene_update(platform_window* window)
+{
+ platform_set_cursor(window, CURSOR_LOADING);
+
+ if (global_asset_collection.done_loading_assets) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+}
+
+void loading_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/loading_world_scene.c b/src/scenes/loading_world_scene.c new file mode 100644 index 0000000..3d15909 --- /dev/null +++ b/src/scenes/loading_world_scene.c @@ -0,0 +1,116 @@ +
+void loading_world_scene_init()
+{
+
+}
+
+u64 load_start_stamp = 0;
+
+static void* start_loading_world_t(void* arg)
+{
+ load_start_stamp = platform_get_time(TIME_FULL, TIME_US); // Used for displaying info texts.
+ #ifdef MODE_DEBUG
+ // thread_sleep(1000*200);
+ #endif
+
+ char* path = (char*)arg;
+ world* world_to_load = 0;
+
+ if (path) {
+ // Load from file here
+ }
+ else {
+ world_to_load = world_create_new();
+ }
+
+ #ifdef MODE_DEBUG
+ u64 load_end_stamp = platform_get_time(TIME_FULL, TIME_US);
+ u64 elapsed_ns = load_end_stamp - load_start_stamp;
+ char info_msg[50];
+ sprintf(info_msg, "Loaded world in %.2fms", elapsed_ns/1000.0f);
+ log_info(info_msg);
+ #endif
+
+ if (!world_to_load) {
+ log_info("Failed to load world");
+ game_set_active_scene(GAME_STATE_ERROR);
+ }
+ else {
+ world_map_set_active_world(world_to_load);
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+
+ return 0;
+}
+
+void start_loading_world(char* saved_file_path)
+{
+ game_set_active_scene(GAME_STATE_LOADING_WORLD);
+ thread_start(start_loading_world_t, saved_file_path);
+}
+
+static void loading_world_draw_info_texts(font* font, s32 center_x, s32 y)
+{
+ char* texts[5] = {
+ "(Building cities)",
+ "(Connecting roads)",
+ "(Manufacturing trucks)",
+ "(Finding truck drivers)",
+ "(This is taking very long..)",
+ };
+
+ u64 load_end_stamp = platform_get_time(TIME_FULL, TIME_US);
+ u64 elapsed_ns = load_end_stamp - load_start_stamp;
+ float elapsed_sec = elapsed_ns / 1000.0f;
+ int text_index = elapsed_sec / 2000.0f; // 2 sec per text.
+ if (text_index >= 5) text_index = 4;
+
+ s32 text_len = renderer->calculate_text_width(font, texts[text_index]);
+ renderer->render_text(font, center_x - (text_len/2), y, texts[text_index], COLOR_TEXT);
+}
+
+static void loading_world_draw_animation(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ float vertical_pad = 20 * scale;
+ float horizontal_pad = vertical_pad;
+ float spacing = 5 * scale;
+
+ s32 panel_h = 280 * scale;
+ s32 panel_item_size = (panel_h - (vertical_pad*2) - (spacing*1)) / 2;
+ s32 panel_w = (panel_item_size * 3) + (horizontal_pad*2) + (spacing*2);
+
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ s32 carwheel_size = panel_h/4;
+
+ static float rotation = 0.0f;
+ rotation -= 0.05f;
+ gl_render_set_rotation(rotation);
+ renderer->render_image(img_carwheel, screen_center_x - (carwheel_size/2), screen_center_y - (carwheel_size/2), carwheel_size, carwheel_size);
+ gl_render_set_rotation(0.0f);
+
+
+ font* font_info = FONT_REGULAR(SIZE_RD(area.w, 28));
+ loading_world_draw_info_texts(font_info, screen_center_x, panel_y + panel_h - font_info->px_h - vertical_pad*2);
+}
+
+void loading_world_scene_render(platform_window* window)
+{
+ menu_draw_background(window);
+ loading_world_draw_animation(window);
+}
+
+void loading_world_scene_update(platform_window* window)
+{
+
+}
+
+void loading_world_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/menu_scene.c b/src/scenes/menu_scene.c new file mode 100644 index 0000000..73ec22d --- /dev/null +++ b/src/scenes/menu_scene.c @@ -0,0 +1,93 @@ +
+void menu_scene_init()
+{
+
+}
+
+static void menu_draw_background(platform_window* window)
+{
+ vec4 area = camera_get_target_rectangle(window);
+ renderer->render_rectangle(area.x, area.y, area.w, area.h, COLOR_WORLD_MAP_BACKGROUND);
+ renderer->render_image(img_world_map, area.x, area.y, area.w, area.h);
+}
+
+static void menu_draw_options(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ s32 panel_w = 198 * scale;
+ s32 panel_h = 193 * scale;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ s32 button_w = 178 * scale;
+ s32 button_h = 37 * scale;
+ s32 vertical_pad = 10 * scale;
+ s32 pad_x = (panel_w - button_w)/2;
+ float pad_y = (panel_h - (vertical_pad*2) - button_h*4)/5.0f;
+
+ if (button_render(scale, BUTTON_ENABLED, "New Game", panel_x + pad_x, vertical_pad + panel_y + pad_y*1, button_w, button_h))
+ {
+ start_loading_world(0); // Start new world
+ }
+
+ if (button_render(scale, BUTTON_ENABLED, "Continue", panel_x + pad_x, vertical_pad + panel_y + pad_y*2 + button_h*1, button_w, button_h))
+ {
+ game_set_active_scene(GAME_STATE_SELECT_SAVE);
+ }
+
+ if (button_render(scale, BUTTON_ENABLED, "Settings", panel_x + pad_x, vertical_pad + panel_y + pad_y*3 + button_h*2, button_w, button_h))
+ {
+ game_set_active_scene(GAME_STATE_SETTINGS);
+ }
+
+ if (button_render(scale, BUTTON_ENABLED, "Quit", panel_x + pad_x, vertical_pad + panel_y + pad_y*4 + button_h*3, button_w, button_h))
+ {
+ window->is_open = false;
+ }
+}
+
+static void menu_draw_title(platform_window* window)
+{
+ s32 panel_w = 198 * scale;
+ s32 panel_h = 70 * scale;
+ s32 panel_pad = 50 * scale;
+ s32 panel_x = area.x + panel_pad;
+ s32 panel_y = area.y + area.h - panel_h - panel_pad;
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ font* font_reg = FONT_REGULAR(SIZE_RD(area.w, 44));
+ font* font_sml = FONT_REGULAR(SIZE_RD(area.w, 20));
+ s32 text_pad = 5*scale;
+ s32 total_text_h = font_reg->px_h + text_pad + font_sml->px_h;
+ s32 text_y = panel_y + (panel_h/2) - (total_text_h/2);
+ char* game_title = "TruckerX";
+ char* game_version = "rev "GAME_VERSION;
+ s32 game_title_width = renderer->calculate_text_width(font_reg, game_title);
+ s32 text_x = panel_x + (panel_w/2) - (game_title_width/2);
+
+ renderer->render_text(font_reg, text_x+2, text_y+2, game_title, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_reg, text_x, text_y, game_title, COLOR_TEXT);
+
+ renderer->render_text(font_sml, 10*scale + text_x+2,font_reg->px_h + text_pad + text_y+2, game_version, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_sml, 10*scale + text_x, font_reg->px_h + text_pad + text_y, game_version, COLOR_TEXT);
+}
+
+void menu_scene_render(platform_window* window)
+{
+ menu_draw_background(window);
+ menu_draw_options(window);
+ menu_draw_title(window);
+}
+
+void menu_scene_update(platform_window* window)
+{
+
+}
+
+void menu_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/place_detail.c b/src/scenes/place_detail.c new file mode 100644 index 0000000..699fe0e --- /dev/null +++ b/src/scenes/place_detail.c @@ -0,0 +1,1771 @@ +typedef enum t_place_detail_state
+{
+ PLACE_DETAIL_SHOW_MAIN,
+ PLACE_DETAIL_SHOW_RESUMES,
+ PLACE_DETAIL_SHOW_DEALERS,
+ PLACE_DETAIL_SHOW_EMPLOYEE,
+ PLACE_DETAIL_SHOW_SCHEDULE,
+} place_detail_state;
+
+typedef enum t_place_detail_info_state
+{
+ PLACE_DETAIL_EMPLOYEES = 0,
+ PLACE_DETAIL_JOBOFFERS = 1,
+ PLACE_DETAIL_SCHEDULE = 2,
+ PLACE_DETAIL_GARAGE = 3,
+} place_detail_info_state;
+
+typedef enum t_schedule_state
+{
+ SCHEDULING_JOB,
+ RESCHEDULING_JOB,
+ VIEWING,
+} schedule_state;
+
+// Animations
+#define TAG_ANIMATION_DURATION 100
+#define EMPLOYEE_SELECTOR_ANIMATION_DURATION 100
+#define TRUCK_SWAP_ANIMATION_DURATION 200
+animation tag_animation = {0,0,0,1};
+animation employee_selector_animation = {0,0,0,1};
+animation truck_swap_animation = {0,0,0,1};
+
+// States
+world_location* _active_location;
+employee* _active_employee;
+scheduled_job _active_scheduling_job;
+scheduled_job* _active_selected_scheduled_job;
+schedule_state _active_schedule_state = VIEWING;
+s32 _active_schedule_selected_job_index = 0;
+place_detail_info_state selected_tab_index = PLACE_DETAIL_EMPLOYEES;
+place_detail_state current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+static s16 selected_truck_index = 0;
+static u8 active_dealer_index = 0;
+#define INVALID_VAL -999
+static s32 index_of_truck = INVALID_VAL;
+
+typedef struct t_tab
+{
+ s32 x;
+ s32 y;
+ s32 w;
+ s32 h;
+ float scale;
+} tab;
+
+void _goto_default_detail_state()
+{
+ index_of_truck = INVALID_VAL;
+ selected_truck_index = 0;
+ active_dealer_index = 0;
+ _active_employee = 0;
+ _active_schedule_state = VIEWING;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ _active_schedule_selected_job_index = 0;
+ _active_selected_scheduled_job = 0;
+ keyboard_set_input_text("");
+ _global_keyboard.take_input = false;
+}
+
+void place_detail_set_active_location(world_location* location)
+{
+ _active_location = location;
+ selected_tab_index = PLACE_DETAIL_EMPLOYEES;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+}
+
+void place_detail_scene_init()
+{
+
+}
+
+static char* get_shipday_list_string(job_offer* offer, char* buf, s32 len)
+{
+ memset(buf, 0, len);
+ bool first = true;
+ if (job_offer_has_ship_day(offer, MONDAY)) { string_appendn(buf, "Mon", len); first = false; }
+ if (job_offer_has_ship_day(offer, TUESDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Tue", len); first = false; }
+ if (job_offer_has_ship_day(offer, WEDNESDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Wed", len); first = false; }
+ if (job_offer_has_ship_day(offer, THURSDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Thu", len); first = false; }
+ if (job_offer_has_ship_day(offer, FRIDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Fri", len); first = false; }
+ if (job_offer_has_ship_day(offer, SATURDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Sat", len); first = false; }
+ if (job_offer_has_ship_day(offer, SUNDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Sun", len); first = false; }
+
+ return buf;
+}
+
+static scheduled_job* get_scheduled_job_at_time(s32 day, s32 timeslot)
+{
+ for (s32 i = 0; i < _active_location->schedule.jobs.length; i++) {
+ scheduled_job* slot = array_at(&_active_location->schedule.jobs, i);
+ for (s32 x = 0; x < slot->offer.shipday_count; x++) {
+ if (slot->timeslots[x].day == day && slot->timeslots[x].timeslot == timeslot) return slot;
+ }
+ }
+ return 0;
+}
+
+static s32 find_empty_timeslot_for_day(s32 day)
+{
+ log_assert(day >= 0 && day < NUM_DAYS, "Invalid day");
+ for (s32 i = 0; i < TIME_SLOTS_PER_DAY; i++) {
+ scheduled_job* job = get_scheduled_job_at_time(day, i);
+ if (!job || (_active_schedule_state == RESCHEDULING_JOB && job == _active_selected_scheduled_job)) return i;
+ }
+ return -1;
+}
+
+static s32 find_empty_timeslot_for_day_right_to_left(s32 day)
+{
+ log_assert(day >= 0 && day < NUM_DAYS, "Invalid day");
+ for (s32 i = TIME_SLOTS_PER_DAY-1; i >= 0; i--) {
+ scheduled_job* job = get_scheduled_job_at_time(day, i);
+ if (!job || (_active_schedule_state == RESCHEDULING_JOB && job == _active_selected_scheduled_job)) return i;
+ }
+ return -1;
+}
+
+
+static scheduled_job create_empty_job_schedule(job_offer* job)
+{
+ scheduled_job new_job;
+ new_job.location = _active_location;
+ new_job.offer = *job;
+ new_job.trust = 1.0f;
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ new_job.timeslots[i] = (scheduled_job_time){-1, -1, 0, 0};
+ }
+ for (s32 i = 0; i < job->shipday_count; i++) {
+ new_job.timeslots[i] = (scheduled_job_time){job->shipdays[i], find_empty_timeslot_for_day(job->shipdays[i]), 0, 0};
+ }
+ return new_job;
+}
+
+#define scroll_speed 15
+#define HANDLE_TAB_SCROLL\
+ bool hovering_tab = (_global_mouse.y >= orig_y && _global_mouse.y <= orig_y + h \
+ && _global_mouse.x >= x && _global_mouse.x <= x + w);\
+ if (scroll_h > 0) {\
+ if (hovering_tab) {\
+ if (_global_mouse.scroll_state < 0) current_scroll += scroll_speed;\
+ if (_global_mouse.scroll_state > 0) current_scroll -= scroll_speed;\
+ }\
+ if (current_scroll > scroll_h) current_scroll = scroll_h;\
+ if (current_scroll < 0) current_scroll = 0;\
+ y -= current_scroll;\
+ }
+
+#define HANDLE_TAB_START(_count, _parts)\
+ s32 item_h = 34 * tab.scale;\
+ s32 total_h = (item_h+1) * (_count) + (10 * tab.scale);\
+ s32 scroll_h = total_h - h;\
+ s32 orig_y = y;\
+ static s32 current_scroll = 0;\
+ font* fnt = fnt_rd16;\
+ s32 info_text_h = fnt->px_h*4;\
+ scroll_h += info_text_h;\
+ s32 item_part_w = (w-item_h) / _parts;\
+ (void)item_part_w;
+
+#define HANDLE_TAB_INFO(_info, _btn_name, _next_state)\
+ s32 btn_h = info_text_h/1.3;\
+ s32 btn_w = btn_h*4;\
+ total_h += info_text_h;\
+ s32 info_text_y = y + (btn_h/2)-(fnt->px_h/2);\
+ renderer->render_text(fnt, x+1, info_text_y+1, _info, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, x, info_text_y, _info, COLOR_TEXT);\
+ if (_btn_name && button_render(tab.scale, true, _btn_name, x+w-btn_w-1, y, btn_w, btn_h)) {\
+ current_detail_state = _next_state;\
+ }\
+ y += info_text_h;
+
+#define HANDLE_TAB_ITEM_INTERACTION(_take) HANDLE_TAB_ITEM_INTERACTIONX(_take, i);
+#define HANDLE_TAB_ITEM_INTERACTIONX(_take, _count)\
+ s32 item_y = y + ((item_h+1) * _count);\
+ bool hovered = (_global_mouse.x >= x && _global_mouse.x <= x + w\
+ && _global_mouse.y >= item_y && _global_mouse.y <= item_y + item_h\
+ && hovering_tab);\
+ color tint = COLOR_LIST_ENTRY_BACKGROUND;\
+ if (_take && hovered) {\
+ tint = COLOR_LIST_ENTRY_BACKGROUND_ACTIVE;\
+ platform_set_cursor(window, CURSOR_POINTER);\
+ }\
+ renderer->render_rectangle(x, item_y, w, item_h, tint);
+
+#define TAB_ITEM_PUSH_TEXT(_buf,_width,_total)\
+ s32 text_w = renderer->calculate_text_width(fnt, _buf);\
+ s32 x_start = (x + item_h*2 - text_pad) + _total;\
+ s32 text_x = x_start + (_width/2)-(text_w/2);\
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);\
+ renderer->render_text(fnt, text_x+1, text_y+1, _buf, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, text_x, text_y,_buf, COLOR_TEXT);\
+ renderer->render_rectangle(x_start + _width, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);\
+ _total += _width;
+
+#define PUSH_NOT_AVAILABLE_TEXT(_cond, _text)\
+ if (_cond) {\
+ font* fnt = fnt_rd20;\
+ char* txt = _text;\
+ s32 textw = renderer->calculate_text_width(fnt, txt);\
+ renderer->render_text(fnt, x+(w/2)-(textw/2), y+(tab.h/2)-(fnt->px_h/2)-(30*scale), txt, COLOR_TEXT);\
+ }
+
+static void place_detail_draw_job_offers(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->job_offers.length, 2);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Job offers open.", _active_location->job_offers.length);
+ HANDLE_TAB_INFO(info_buf, 0, 0);
+
+ PUSH_NOT_AVAILABLE_TEXT(!_active_location->job_offers.length, "No job offers available.");
+
+ for (s32 i = 0; i < _active_location->job_offers.length; i++) {
+ job_offer* offer = array_at(&_active_location->job_offers, i);
+ HANDLE_TAB_ITEM_INTERACTION(true);
+
+ if (hovered && is_left_clicked()) {
+ current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
+ _active_schedule_state = SCHEDULING_JOB;
+ _active_schedule_selected_job_index = 0;
+ _active_selected_scheduled_job = 0;
+ _active_scheduling_job = create_empty_job_schedule(offer);
+
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ renderer->render_image(offer->company->logo, x + icon_pad, item_y + icon_pad, icon_s*2, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s*2 + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ float width_of_piece = 80 * tab.scale;
+ float price_text_w = 0;
+
+ // price
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "$%d/trip", offer->reward);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // distance
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fkm", offer->total_distance);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // dur
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fh-%.0fh", offer->duration_sec_min/3600.0f, offer->duration_sec_max/3600.0f);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // Name
+ {
+ char daybuf[50];
+ char buf[200];
+ sprintf(buf, "%s wants you to ship %s to %s every %s", offer->company->name, offer->product->name,
+ (*(world_location**)array_at(&offer->connections, offer->connections.length-1))->name, get_shipday_list_string(offer, daybuf, 50));
+ s32 text_x = x + item_h*2 + price_text_w + icon_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);
+ }
+ }
+}
+
+
+static void place_detail_draw_trucks(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->trucks.length, 5);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Trucks in garage.", _active_location->trucks.length);
+ HANDLE_TAB_INFO(info_buf, "Purchase", PLACE_DETAIL_SHOW_DEALERS);
+
+ PUSH_NOT_AVAILABLE_TEXT(!_active_location->trucks.length, "No trucks in garage.");
+
+ for (s32 i = 0; i < _active_location->trucks.length; i++) {
+ truck* emp = array_at(&_active_location->trucks, i);
+ HANDLE_TAB_ITEM_INTERACTION(false);
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ renderer->render_image(emp->logo, x + icon_pad, item_y + icon_pad, icon_s, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_WORLD_LOCATION_NAME_LENGTH + 20];
+ sprintf(buffer, "%s, ID: #%d", emp->name, emp->id);
+
+ s32 text_x = x + item_h + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // current location
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ if (emp->assigned_employee) sprintf(buffer, "Assigned to %s", emp->assigned_employee->name);
+ else strcpy(buffer, "No assignee");
+ s32 text_x = x + item_h + item_part_w*1 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ }
+ }
+}
+
+static void place_detail_draw_employees(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->employees.length+2, 4);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Employees currently on site.", _active_location->employees.length);
+ HANDLE_TAB_INFO(info_buf, "Hire", PLACE_DETAIL_SHOW_RESUMES);
+
+ s32 current_index = 0;
+ bool show_internal = true;
+ do_again:;
+
+ for (s32 i = 0; i <= _active_location->employees.length; i++) {
+ employee* emp = 0;
+ if (i > 0) {
+ emp = *(employee**)array_at(&_active_location->employees, i-1);
+ bool is_internal = (emp->original_location_id == _active_location->id);
+ if (show_internal != is_internal) continue;
+ }
+
+ HANDLE_TAB_ITEM_INTERACTIONX(i != 0, current_index);
+ if (i != 0 && hovered && is_left_clicked()) {
+ place_detail_show_employee_detail(emp);
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ current_index++;
+
+ if (i == 0) {
+ char* buffer = show_internal ? "Internal" : "External";
+ s32 text_x = x + item_h;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ continue;
+ }
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ draw_employee_portrait(emp, x + icon_pad, item_y + icon_pad, icon_s, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ sprintf(buffer, "%s, ID: #%d", emp->name, emp->id);
+ s32 text_x = x + item_h + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w, item_y+(5*tab.scale), 1, item_h-(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ if (emp->assigned_truck) sprintf(buffer, "Truck: %s, #%d", emp->assigned_truck->name, emp->assigned_truck->id);
+ else strcpy(buffer, "No assigned truck");
+ s32 text_x = x + item_h + item_part_w*1 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w*2, item_y+(5*tab.scale), 1, item_h-(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // current location
+ {
+ char buffer[MAX_WORLD_LOCATION_NAME_LENGTH + 20];
+ if (emp->active_job_id != INVALID_ID) {
+ active_job* j = get_active_job_by_id(_active_world, emp->active_job_id);
+ job_endpoints endpoints = job_offer_get_endpoints(&j->offer);
+ sprintf(buffer, "Driving to %s", endpoints.dest->name);
+ }
+ else if (emp->current_location_id != _active_location->id) { // employee located at other location
+ sprintf(buffer, "Located at %s", get_world_location_by_id(_active_world, emp->current_location_id)->name);
+ }
+ else { // At original location
+ sprintf(buffer, "%s", "Idling");
+ }
+
+ s32 text_x = x + item_h + item_part_w*2 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w*3, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Happiness
+ {
+ s32 text_x = x + item_h + item_part_w*3 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+
+ s32 stars = employee_calculate_happiness_stars(emp);
+ s32 textw = renderer->render_text(fnt, text_x, text_y, "Happiness: ", COLOR_TEXT);
+ text_x += (scale*5);
+ for (s32 i = 0; i < 5; i++)
+ {
+ if (i < stars) renderer->render_image(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h);
+ else renderer->render_image_tint(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));
+ }
+
+ //renderer->render_rectangle(x + item_h + item_part_w*4, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+ }
+
+ if (show_internal) {
+ show_internal = false;
+ goto do_again;
+ }
+}
+
+static void render_logo_at(image* img, s32 pad, s32 x, s32 y, s32 w, s32 h)
+{
+ if (img->width >= img->height)
+ {
+ float s_scale = w/(float)img->width;
+ float new_w = w - (pad*2);
+ float new_h = (img->height * s_scale) - (pad*2);
+ float new_x = x + w/2 - new_w/2;
+ float new_y = y + h/2 - new_h/2;
+ renderer->render_image(img,new_x,new_y,new_w,new_h);
+ }
+}
+
+static void place_detail_draw_active_dealer(platform_window* window, truck_dealer* dealer, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ button_render(scale, false, 0, x, y, w, h);
+ static truck_dealer* prev_dealer = 0;
+ if (prev_dealer != dealer) {
+ prev_dealer = dealer;
+ selected_truck_index = 0;
+ }
+
+ if (selected_truck_index < 0) selected_truck_index = 0;
+ if (selected_truck_index >= dealer->trucks.length) selected_truck_index = dealer->trucks.length-1;
+ truck* tr_curr = (selected_truck_index >= 0 && selected_truck_index <= dealer->trucks.length-1) ? array_at(&dealer->trucks, selected_truck_index) : 0;
+ truck* tr_prev = (selected_truck_index-1 >= 0) ? array_at(&dealer->trucks, selected_truck_index-1) : 0;
+ truck* tr_next = (selected_truck_index+1 <= dealer->trucks.length-1) ? array_at(&dealer->trucks, selected_truck_index+1) : 0;
+ if (!tr_curr) return;
+ s32 total_img_space = (w)/3 * 2;
+ s32 img_w_center = total_img_space/10*5;
+ s32 img_w_side = total_img_space/10*2.5;
+ s32 pad = 40 * scale;
+ s32 img_x = x;
+ s32 img_y = y;
+
+ static animation swap_animation = {0,0,0,0};
+ static animation purchase_animation = {0,0,0,0};
+ if (swap_animation.started) animation_update(&swap_animation);
+ if (purchase_animation.started) animation_update(&purchase_animation);
+ static s32 target_truck_index = 0;
+
+ truck* tn_prev = (target_truck_index-1 >= 0) ? array_at(&dealer->trucks, target_truck_index-1) : 0;
+ truck* tn_next = (target_truck_index+1 <= dealer->trucks.length-1) ? array_at(&dealer->trucks, target_truck_index+1) : 0;
+
+ // Truck images
+ {
+ s32 overlap = 50 * scale;
+
+ s32 y_side = img_y + (h / 2) - (img_w_side/2);
+ s32 x_left = img_x + overlap;
+ s32 y_left = y_side;
+ s32 w_left = img_w_side;
+ s32 h_left = img_w_side;
+
+ s32 x_right = img_x+img_w_side+img_w_center - overlap;
+ s32 y_right = y_side;
+ s32 w_right = img_w_side;
+ s32 h_right = img_w_side;
+
+ s32 x_center = img_x+img_w_side;
+ s32 y_center = img_y + (h / 2) - (img_w_center/2);
+ s32 w_center = img_w_center;
+ s32 h_center = img_w_center;
+
+ #define LI(_cx,_dx) (_cx + (_dx-_cx)*swap_animation.percentage)
+ #define LIP(_cx,_dx) (_cx + (_dx-_cx)*purchase_animation.percentage)
+ #define LI_TINT(_c,_d) rgba(255,255,255,_c + (_d-_c)*swap_animation.percentage)
+ #define LI_TINTP(_c,_d) rgba(255,255,255,_c + (_d-_c)*purchase_animation.percentage)
+
+ if (tr_prev) {
+ if (target_truck_index < selected_truck_index) {
+ color tint = LI_TINT(50, 255);
+ renderer->render_image_tint(tr_prev->logo,LI(x_left,x_center),LI(y_left,y_center),LI(w_left,w_center),LI(h_left,h_center), tint);
+
+ if (swap_animation.started && tn_prev) {
+ color tint = LI_TINT(0, 50);
+ renderer->render_image_tint(tn_prev->logo,x_left,y_left,w_left,h_left, tint);
+ }
+ }
+ else {
+ color tint = LI_TINT(50, 0);
+ renderer->render_image_tint(tr_prev->logo,x_left,y_left,w_left,h_left, tint);
+ }
+ }
+ if (tr_next) {
+ if (target_truck_index < selected_truck_index) {
+ color tint = LI_TINT(50, 0);
+ renderer->render_image_tint(tr_next->logo,x_right,y_right,w_right,h_right, tint);
+ }
+ else {
+ color tint = LI_TINT(50, 255);
+ renderer->render_image_tint(tr_next->logo,LI(x_right,x_center),LI(y_right,y_center),LI(w_right,w_center),LI(h_right,h_center), tint);
+
+ if (swap_animation.started && tn_next) {
+ color tint = LI_TINT(0, 50);
+ renderer->render_image_tint(tn_next->logo,x_right,y_right,w_right,h_right, tint);
+ }
+ }
+ }
+ if (!purchase_animation.started)
+ {
+ color tint = LI_TINT(255, 50);
+ if (target_truck_index < selected_truck_index)
+ renderer->render_image_tint(tr_curr->logo,LI(x_center,x_right),LI(y_center,y_right),LI(w_center,w_right),LI(h_center,h_right), tint);
+ else
+ renderer->render_image_tint(tr_curr->logo,LI(x_center,x_left),LI(y_center,y_left),LI(w_center,w_left),LI(h_center,h_left), tint);
+ }
+ else {
+ vec4 area = camera_get_target_rectangle(window);
+ s32 x_off = area.x;
+ s32 h_off = area.h/2;
+ s32 y_off = area.y+(area.h/2)-(h_off/2);
+ s32 w_off = h_off;
+
+ color tint = LI_TINTP(255, 0);
+ renderer->render_image_tint(tr_curr->logo,LIP(x_center,x_off),LIP(y_center,y_off),LIP(w_center,w_off),LIP(h_center,h_off), tint);
+ }
+ }
+
+ font* fnt = fnt_rd24;
+ s32 text_y = img_y + pad;
+ s32 text_x = x + total_img_space;
+
+ #define PUSH_TEXT(_str, _data)\
+ {char buf[50]; snprintf(buf,50,_str,_data);\
+ renderer->render_text(fnt, text_x+1, text_y+1, buf, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);}\
+ text_y+=fnt->px_h+(10*scale);
+
+ PUSH_TEXT("Name: %s", tr_curr->name);
+ PUSH_TEXT("Power: %dhp", tr_curr->hp);
+ PUSH_TEXT("Price: $%d", tr_curr->price);
+ PUSH_TEXT("Fuel Capacity: %dL", tr_curr->fuelcapacity);
+ PUSH_TEXT("Torque %drpm", tr_curr->torque);
+ PUSH_TEXT("Fuel Usage %.1fL per 100Km", tr_curr->fuelusage);
+
+ #define TRUCK_SWAP_DELAY 200
+ #define TRUCK_PURCHASE_DELAY 800
+ s32 btn_size = 30*scale;
+ s32 btn_x = text_x;
+
+ button_type type1 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : (selected_truck_index > 0) ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type1, "<", btn_x, text_y, btn_size, btn_size)) {
+ if (!swap_animation.started) {
+ swap_animation = animation_create(TRUCK_SWAP_DELAY);
+ swap_animation.started = true;
+ target_truck_index = selected_truck_index-1;
+ }
+ }
+ btn_x += btn_size;
+ s32 center_btn_w = 100*scale;
+ button_type type2 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : BUTTON_ENABLED;
+ if (button_render(scale, type2, "purchase", btn_x, text_y, center_btn_w, btn_size)) {
+ ADD_EXPENSE(_active_world, _active_location, expenses_from_trucks, tr_curr->price)
+ add_truck_to_world_location(_active_world, _active_location, tr_curr);
+ purchase_animation = animation_create(TRUCK_PURCHASE_DELAY);
+ purchase_animation.started = true;
+ }
+ btn_x += center_btn_w;
+ button_type type3 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : (selected_truck_index < dealer->trucks.length-1) ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type3, ">", btn_x, text_y, btn_size, btn_size)) {
+ if (!swap_animation.started) {
+ swap_animation = animation_create(TRUCK_SWAP_DELAY);
+ swap_animation.started = true;
+ target_truck_index = selected_truck_index+1;
+ }
+ }
+ if (swap_animation.percentage == 1.0f) {
+ swap_animation = (animation){0,0,0,0};
+ selected_truck_index = target_truck_index;
+ }
+ if (purchase_animation.percentage == 1.0f) {
+ purchase_animation = (animation){0,0,0,0};
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ selected_truck_index = 0;
+ active_dealer_index = 0;
+ }
+}
+
+void place_detail_show_schedule_with_highlighted_job(world_location* loc, scheduled_job* job, scheduled_job_time job_time) {
+ _goto_default_detail_state();
+ place_detail_set_active_location(loc);
+ game_set_active_scene(GAME_STATE_PLACE_DETAIL);
+
+ if (job) {
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ if (job_time.day == job->timeslots[i].day) {
+ _active_schedule_selected_job_index = i;
+ break;
+ }
+ }
+ }
+
+ _active_schedule_state = VIEWING;
+ _active_selected_scheduled_job = job;
+ selected_tab_index = PLACE_DETAIL_SHOW_MAIN;
+ current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+}
+
+void place_detail_show_employee_detail(employee* emp) {
+ _goto_default_detail_state();
+ world_location* original_loc = get_world_location_by_id(_active_world, emp->original_location_id);
+ place_detail_set_active_location(original_loc);
+ game_set_active_scene(GAME_STATE_PLACE_DETAIL);
+ current_detail_state = PLACE_DETAIL_SHOW_EMPLOYEE;
+ _active_employee = emp;
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+}
+
+static s32 place_detail_draw_selected_employee_truck_selector(platform_window* window, s32 x, s32 y, s32 w, s32 h)
+{
+ s32 btn_w = 40*scale;
+ s32 pad = 30*scale;
+ s32 truck_h = h / 2;
+ s32 truck_w = truck_h;
+ s32 truck_x = x + (pad*2) + btn_w;
+ s32 truck_y = y + pad;
+
+ world_location* original_location = get_world_location_by_id(_active_world, _active_employee->original_location_id);
+
+ if (index_of_truck == INVALID_VAL) {
+ index_of_truck = _active_employee->assigned_truck ? ((void*)_active_employee->assigned_truck - (void*)original_location->trucks.data) / sizeof(truck) : -1;
+ }
+
+ s32 bg_h = h;
+ s32 bg_w = truck_w + (btn_w*2) + (pad*4);
+ button_draw_background(scale, x,y,bg_w,bg_h, COLOR_WHITE, COLOR_BUTTON);
+
+ static bool animation_going_left = false;
+
+ // Draw truck info
+ {
+ #define TRUCK_ANIMATION_OFFSET (animation_going_left ? -60*scale : 60*scale)
+ s32 truck_offset_x = TRUCK_ANIMATION_OFFSET - (TRUCK_ANIMATION_OFFSET*truck_swap_animation.percentage);
+ color truck_tint = AN_LI_TINT(COLOR_WHITE, truck_swap_animation);
+
+ truck* selected_truck = 0;
+ if (index_of_truck != -1) selected_truck = array_at(&original_location->trucks, index_of_truck);
+ renderer->render_image_tint(selected_truck ? selected_truck->logo : img_truck_unknown, truck_x+truck_offset_x, truck_y, truck_w, truck_h, truck_tint);
+ if (selected_truck) {
+ font* fnt = fnt_rd24;
+ char buf[40];
+ sprintf(buf, "%s, ID: #%d", selected_truck->name, selected_truck->id);
+ s32 text_w = renderer->calculate_text_width(fnt, buf);
+ s32 text_x = truck_x + (truck_w/2)-(text_w/2);
+ renderer->render_text(fnt, text_x+1+truck_offset_x, truck_y+truck_h+1, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x+truck_offset_x,truck_y+truck_h, buf, COLOR_TEXT);
+ }
+ }
+
+ // Change truck
+ {
+ if (button_render(scale, BUTTON_ENABLED, "<", truck_x-btn_w-pad,truck_y, btn_w, truck_h)) {
+ s32 prev_index = index_of_truck;
+ index_of_truck = -1;
+
+ try_again:
+ for (s32 i = prev_index-1; i >= 0; i--) {
+ truck* emp = array_at(&original_location->trucks, i);
+ if (emp->assigned_employee == 0 || emp->assigned_employee == _active_employee) {
+ index_of_truck = i;
+ break;
+ }
+ }
+
+ if (prev_index == -1) {
+ prev_index = original_location->trucks.length;
+ goto try_again;
+ }
+
+ truck_swap_animation = animation_create(TRUCK_SWAP_ANIMATION_DURATION);
+ truck_swap_animation.started = true;
+ animation_going_left = true;
+ }
+ if (button_render(scale, BUTTON_ENABLED, ">", truck_x+truck_w+pad,truck_y, btn_w, truck_h)) {
+ s32 prev_index = index_of_truck;
+ index_of_truck = -1;
+ for (s32 i = prev_index+1; i < original_location->trucks.length; i++) {
+ truck* emp = array_at(&original_location->trucks, i);
+ if (emp->assigned_employee == 0 || emp->assigned_employee == _active_employee) {
+ index_of_truck = i;
+ break;
+ }
+ }
+
+ truck_swap_animation = animation_create(TRUCK_SWAP_ANIMATION_DURATION);
+ truck_swap_animation.started = true;
+ animation_going_left = false;
+ }
+ }
+
+
+ // Save changes button
+ {
+ s32 btn_h = 30*scale;
+ btn_w = 160*scale;
+ s32 btn_y = y + h - pad - btn_h;
+ s32 btn_x = x + (bg_w/2) - (btn_w/2);
+ if (button_render(scale, BUTTON_ENABLED, "Save Changes", btn_x, btn_y, btn_w, btn_h)) {
+ if (index_of_truck != -1) {
+ if (_active_employee->assigned_truck) _active_employee->assigned_truck->assigned_employee = 0;
+ _active_employee->assigned_truck = array_at(&_active_location->trucks, index_of_truck);
+ log_assert(_active_employee->assigned_truck->assigned_employee == 0 &&
+ _active_employee->assigned_truck->assigned_employee != _active_employee, "Truck already has assignee");
+
+ _active_employee->assigned_truck->assigned_employee = _active_employee;
+ }
+ else {
+ if (_active_employee->assigned_truck) _active_employee->assigned_truck->assigned_employee = 0;
+ _active_employee->assigned_truck = 0;
+ }
+
+ index_of_truck = INVALID_VAL;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ }
+
+ animation_update(&truck_swap_animation);
+ return bg_w;
+}
+
+static void place_detail_draw_selected_employee(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+
+ s32 truck_selector_w = place_detail_draw_selected_employee_truck_selector(window, x, y, w, h);
+
+ {
+ font* fnt = fnt_rd24;
+
+ s32 info_panel_x = x + truck_selector_w+offset;
+ s32 info_panel_w = w - offset - truck_selector_w;
+ s32 pad = 30*scale;
+
+ s32 text_y = y + pad;
+ s32 text_x = info_panel_x + pad;
+ s32 text_offset = fnt->px_h + (10*scale);
+ s32 info_h = (h/2)-(pad/2);
+ button_draw_background(scale, info_panel_x, y, info_panel_w, info_h, COLOR_WHITE, COLOR_BUTTON);
+
+ s32 portrait_h = (info_h)-(pad*2);
+ draw_employee_portrait(_active_employee, text_x, text_y, portrait_h, portrait_h);
+
+ text_x += portrait_h + pad;
+
+ #define PUSH_INFO_TEXT(_fmt, _data)\
+ {\
+ char buf[100];\
+ sprintf(buf, _fmt, _data);\
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);\
+ text_y += text_offset;\
+ }
+
+ PUSH_INFO_TEXT("Name: %s", _active_employee->name);
+ PUSH_INFO_TEXT("Age: %d", _active_employee->age);
+ PUSH_INFO_TEXT("Experience: %d years", _active_employee->experience);
+ PUSH_INFO_TEXT("Salary: $%.2f/month", _active_employee->salary);
+
+ // Happiness
+ {
+ s32 stars = employee_calculate_happiness_stars(_active_employee);
+ s32 textw = renderer->render_text(fnt, text_x, text_y, "Happiness: ", COLOR_TEXT);
+ for (s32 i = 0; i < 5; i++)
+ {
+ if (i < stars) renderer->render_image(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h);
+ else renderer->render_image_tint(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));
+ }
+ text_y += text_offset;
+ }
+
+ #define SALARY_RAISE_INCREASE 70
+ // Buttons
+ {
+ s32 pad_between_items = 10 * scale;
+ s32 button_w = 164 * scale;
+ s32 button_h = 37 * scale;
+ s32 btn_y = y+info_h+pad+info_h-button_h;
+ s32 btn_x = x + w - button_w;
+ if (button_render(scale, BUTTON_ENABLED, "End Contract", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click3, AUDIO_CHANNEL_SFX_1);
+ end_contract_with_employee(_active_world, _active_employee);
+ _active_employee = 0;
+ _goto_default_detail_state();
+ }
+ btn_y -= (button_h+pad_between_items);
+
+ if (button_render(scale, BUTTON_ENABLED, "Give Raise", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ _active_employee->salary += SALARY_RAISE_INCREASE;
+ }
+ btn_y -= (button_h+pad_between_items);
+ }
+ }
+}
+
+static void place_detail_draw_schedule_employee_options(platform_window* window, s32 pad, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ bool viewing = (_active_schedule_state == VIEWING && !_active_selected_scheduled_job);
+ if (viewing) return;
+
+ job_endpoints endpoints = job_offer_get_endpoints(&_active_scheduling_job.offer);
+ bool enabled = endpoints.dest->is_owned;
+
+ if (enabled) button_draw_background(scale, x,y,w,h, COLOR_WHITE, COLOR_BUTTON);
+ else button_draw_background(scale, x,y,w,h, COLOR_BUTTON_DISABLED_TINT, COLOR_BUTTON_DISABLED);
+
+ s32 checkbox_s = h/3;
+ scheduled_job_time selected_timeslot = _active_scheduling_job.timeslots[_active_schedule_selected_job_index];
+ if (_active_schedule_state == VIEWING) selected_timeslot = _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index];
+
+ char* check_txt = selected_timeslot.stay_at_destination ? "X" : "";
+ if (button_render(scale, enabled && _active_schedule_state != VIEWING ? BUTTON_ENABLED : BUTTON_DISABLED, check_txt, x+pad,y+(h/2)-(checkbox_s/2),checkbox_s,checkbox_s)) {
+ _active_scheduling_job.timeslots[_active_schedule_selected_job_index].stay_at_destination = !selected_timeslot.stay_at_destination;
+ }
+
+ font* fnt = fnt_rd20;
+ s32 textx = x + pad + checkbox_s + pad/2;
+ s32 texty = y+(h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, "Stay at destination", COLOR_TEXT);
+
+ if (!enabled) {
+ s32 icon_s = h/2;
+ renderer->render_image(img_lock, x + (w/2)-(icon_s/2), y + (h/2)-(icon_s/2), icon_s, icon_s);
+ }
+}
+
+static void place_detail_draw_schedule_employee_selector(platform_window* window, s32 pad, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ if (_active_schedule_state == VIEWING && !_active_selected_scheduled_job) {
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+ font* fnt = fnt_rd20;
+ s32 texty = y + (h/2)-(fnt->px_h/2);
+ s32 textx = x + pad;
+ renderer->render_text(fnt, textx, texty, "Select a timeslot for details.", COLOR_TEXT);
+ }
+ else {
+ scheduled_job_time selected_timeslot = _active_scheduling_job.timeslots[_active_schedule_selected_job_index];
+
+ employee* selected_employee = selected_timeslot.assignee;
+ bool is_viewing_existing_timeslot = _active_selected_scheduled_job && _active_schedule_state == VIEWING;
+ if (is_viewing_existing_timeslot) {
+ selected_employee = _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index].assignee;
+ }
+
+ // When timeslot changes, set selected employee id as keyboard input text.
+ static s32 prev_selected_job_index = 0;
+ if (is_viewing_existing_timeslot) prev_selected_job_index = -1;
+ if (prev_selected_job_index != _active_schedule_selected_job_index) {
+ prev_selected_job_index = _active_schedule_selected_job_index;
+ if (selected_employee) {
+ char idbuf[20];
+ sprintf(idbuf, "%d", selected_employee->id);
+ keyboard_set_input_text(idbuf);
+ }
+ else {
+ keyboard_set_input_text("");
+ }
+ }
+
+ _active_scheduling_job.timeslots[_active_schedule_selected_job_index].assignee =
+ employee_selector_render(window, scale, !is_viewing_existing_timeslot, selected_employee,x,y,w,h, employee_selector_animation, &_active_scheduling_job);
+ animation_update(&employee_selector_animation);
+ }
+}
+
+static bool scheduling_job_is_correct()
+{
+ for (s32 i = 0; i < _active_scheduling_job.offer.shipday_count; i++) {
+ scheduled_job_time scheduled_time = _active_scheduling_job.timeslots[i];
+ if (!scheduled_time.assignee) { return false; }
+ if (scheduled_time.timeslot == -1) { return false; }
+ }
+ return true;
+}
+
+static void draw_duration_of_scheduled_job_entry(scheduled_job_time scheduled_time, s32 hour_w, s32 tx, s32 ty, s32 timeslot_w, s32 x, s32 y, s32 timeslot_h, color tile_color)
+{
+ #define TILE_X(_x) (x+hour_w+(timeslot_w*_x)+1)
+ #define TILE_Y(_y) (y+(timeslot_h*(CDAYTORDAY(_y)))+1)
+
+ s32 duration_of_job_measured_in_timeslots_max = ceil((_active_scheduling_job.offer.duration_sec_max/60.0f) / (60.0f/TIME_SLOTS_PER_HOUR));
+ if (!scheduled_time.stay_at_destination) duration_of_job_measured_in_timeslots_max*=2;
+ log_assert(duration_of_job_measured_in_timeslots_max < 36*TIME_SLOTS_PER_HOUR, "Multi-day trip not supported yet in schedule preview.");
+
+ s32 slots_outside_of_schedule = (24-(WORK_HOUR_END-WORK_HOUR_START))*TIME_SLOTS_PER_HOUR;
+ s32 overflow_to_next_day = -(((TIME_SLOTS_PER_DAY-scheduled_time.timeslot) -
+ (duration_of_job_measured_in_timeslots_max)) +
+ slots_outside_of_schedule);
+ color tile_color_bg = tile_color;
+ tile_color_bg.a = 50;
+
+ s32 highlight_w = timeslot_w*duration_of_job_measured_in_timeslots_max;
+ if (tx+highlight_w > x+(timeslot_w*(TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)))
+ highlight_w -= (tx+highlight_w) - (x+(timeslot_w*(TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)));
+ renderer->render_rectangle(tx, ty, highlight_w, timeslot_h, tile_color_bg);
+ s32 highlight_y = ty+timeslot_h;
+ if (scheduled_time.day == SUNDAY) highlight_y = TILE_Y(MONDAY);
+ if (overflow_to_next_day > 0) renderer->render_rectangle(TILE_X(0), highlight_y, timeslot_w*overflow_to_next_day, timeslot_h, tile_color_bg);
+}
+
+static void place_detail_draw_schedule(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 pad_between_items = 10 * scale;
+ s32 employee_select_h = (h/4);
+ h -= employee_select_h + pad_between_items;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+ s32 btn_pad = pad_between_items/2;
+
+ s32 button_w = 124 * scale;
+ s32 button_h = (employee_select_h-btn_pad)/2;
+ s32 schedule_pad = 20*scale;
+
+ #define COLS (TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)
+ #define ROWS 8
+ s32 timeslot_w = (w-schedule_pad*2)/COLS;
+ s32 timeslot_h = (h-schedule_pad*2)/ROWS;
+ s32 hour_w = timeslot_w*4;
+ s32 new_w = (timeslot_w)*COLS+schedule_pad*2;
+ s32 new_h = (timeslot_h)*ROWS+schedule_pad*2;
+ s32 off_x = w - new_w;
+ s32 off_y = h - new_h;
+ w = new_w;
+ h = new_h;
+ x += off_x/2;
+ y += off_y/2;
+
+ s32 employee_select_y = y + h + pad_between_items;
+ s32 btn_y = y+h+pad_between_items;
+ if (_active_schedule_state == SCHEDULING_JOB || _active_schedule_state == RESCHEDULING_JOB)
+ {
+ button_type type = scheduling_job_is_correct() ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type, "Accept", x-button_w+w, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ if (_active_schedule_state == SCHEDULING_JOB)
+ array_push(&_active_location->schedule.jobs, &_active_scheduling_job);
+ else if (_active_schedule_state == RESCHEDULING_JOB)
+ *_active_selected_scheduled_job = _active_scheduling_job;
+
+ job_offer* offer = get_job_offer_by_id(_active_location, _active_scheduling_job.offer.id);
+ if (offer) array_remove_by(&_active_location->job_offers, offer);
+
+ _goto_default_detail_state();
+ }
+ btn_y += btn_pad + button_h;
+ if (button_render(scale, BUTTON_ENABLED, "Cancel", x-button_w+w, btn_y, button_w, button_h)) {
+ _goto_default_detail_state();
+ }
+ }
+ else if (_active_schedule_state == VIEWING && _active_selected_scheduled_job) {
+ if (button_render(scale, BUTTON_ENABLED, "Reschedule", x-button_w+w, btn_y, button_w, button_h)) {
+ _active_schedule_state = RESCHEDULING_JOB;
+ _active_scheduling_job = *_active_selected_scheduled_job;
+ }
+ }
+
+ s32 options_w = 230*scale;
+ s32 selector_w = w-options_w-(pad_between_items*2)-button_w;
+
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ x+=schedule_pad;
+ y+=schedule_pad;
+ w-=schedule_pad*2;
+ h-=schedule_pad*2;
+
+ #define TILE_X(_x) (x+hour_w+(timeslot_w*_x)+1)
+ #define TILE_Y(_y) (y+(timeslot_h*(CDAYTORDAY(_y)))+1)
+
+
+ vec2f hovered_tile = (vec2f){(s32)((_global_mouse.x-x)/timeslot_w)-TIME_SLOTS_PER_HOUR, (s32)((_global_mouse.y-y)/timeslot_h)};
+ s32 hovered_day = RDAYTOCDAY((s32)hovered_tile.y);
+ scheduled_job* existing_job_at_hovered_tile = get_scheduled_job_at_time(hovered_day, (s32)hovered_tile.x);
+ font* fnt = fnt_rd24;
+
+ static bool dragging_tile = false;
+
+ // newly scheduling job
+ if (_active_schedule_state == SCHEDULING_JOB || _active_schedule_state == RESCHEDULING_JOB)
+ {
+ for (s32 i = 0; i < _active_scheduling_job.offer.shipday_count; i++) {
+ scheduled_job_time scheduled_time = _active_scheduling_job.timeslots[i];
+ s32 dday = CDAYTORDAY(scheduled_time.day);
+ renderer->render_rectangle(x+hour_w, y+(dday*timeslot_h), w-hour_w, timeslot_h, COLOR_SCHEDULE_ROW_ACTIVE);
+
+ bool being_hovered = false;
+ bool valid_tile = (!existing_job_at_hovered_tile || (_active_schedule_state == RESCHEDULING_JOB && existing_job_at_hovered_tile == _active_selected_scheduled_job));
+ if (valid_tile && hovered_tile.x >= 0 && hovered_tile.x < TIME_SLOTS_PER_DAY && hovered_tile.y == dday) { // If in current row.
+
+ // Interaction.
+ if (_active_scheduling_job.timeslots[i].timeslot == hovered_tile.x) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ being_hovered = true;
+
+ // Check if player started to drag.
+ if (is_left_clicked_peak()) { // is_left_clicked_peak instead of is_left_clicked so employee selector can reset input.
+ dragging_tile = true;
+ _active_schedule_selected_job_index = i;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ }
+ }
+
+ s32 tx = TILE_X(scheduled_time.timeslot);
+ s32 ty = TILE_Y(scheduled_time.day);
+
+ bool is_dragging_current_tile = (dragging_tile && _active_schedule_selected_job_index == i);
+ color tile_color = (_active_schedule_selected_job_index == i) ? COLOR_SCHEDULE_TILE_HOVERED : COLOR_SCHEDULE_TILE_SELECTED;
+
+ // Handle dragging.
+ if (being_hovered || is_dragging_current_tile) {
+
+ // Get index of new timeslot.
+ s32 index_to_set = hovered_tile.x;
+ s32 possible_tile_left = find_empty_timeslot_for_day(scheduled_time.day);
+ s32 possible_tile_right = find_empty_timeslot_for_day_right_to_left(scheduled_time.day);
+ if (index_to_set < 0) index_to_set = possible_tile_left;
+ if (index_to_set >= TIME_SLOTS_PER_DAY) index_to_set = possible_tile_right;
+
+ // Set new timeslot.
+ if (is_dragging_current_tile) {
+ platform_set_cursor(window, CURSOR_DRAG);
+
+ scheduled_job* existing_job_at_tile = get_scheduled_job_at_time(scheduled_time.day, index_to_set);
+ if (existing_job_at_tile == _active_selected_scheduled_job) existing_job_at_tile = 0; // Make sure reschedule can be set at current location.
+ if (index_to_set != -1 && !existing_job_at_tile) _active_scheduling_job.timeslots[i].timeslot = index_to_set;
+
+ if (!is_left_down()) {
+ dragging_tile = false;
+ }
+
+ tx = TILE_X(_active_scheduling_job.timeslots[i].timeslot);
+ ty = TILE_Y(scheduled_time.day);
+ }
+
+ // Draw duration of job.
+ draw_duration_of_scheduled_job_entry(scheduled_time, hour_w, tx, ty, timeslot_w, x, y, timeslot_h, tile_color);
+
+ // Draw left and right arrow.
+ s32 icon_s = timeslot_w*0.7f;
+ s32 icon_y = ty + (timeslot_h-icon_s)/2;
+ s32 icon_pad = (3*scale);
+ if (possible_tile_left != -1 && possible_tile_left != index_to_set) {
+ renderer->render_image_tint(img_arrow_left_rounded, tx - icon_s - icon_pad-1, icon_y, icon_s+2, icon_s,COLOR_SCHEDULE_BORDER_THIN);
+ renderer->render_image_tint(img_arrow_left_rounded, tx - icon_s - icon_pad, icon_y, icon_s, icon_s,tile_color);
+ }
+ if (possible_tile_right != -1 && possible_tile_right != index_to_set) {
+ gl_render_set_rotation(M_PI);
+ renderer->render_image_tint(img_arrow_left_rounded, tx + timeslot_w + icon_pad-1, icon_y, icon_s+2, icon_s,COLOR_SCHEDULE_BORDER_THIN);
+ renderer->render_image_tint(img_arrow_left_rounded, tx + timeslot_w + icon_pad, icon_y, icon_s, icon_s,tile_color);
+ gl_render_set_rotation(0.0f);
+ }
+ }
+
+ // Draw tile.
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, tile_color);
+
+ // Status icon if tile being scheduled.
+ s32 icon_size = timeslot_w*0.6f;
+ if (scheduled_time.assignee == 0) {
+ renderer->render_image(img_questionmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+ else {
+ renderer->render_image(img_checkmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+ }
+ }
+
+ // existing jobs
+ {
+ for (s32 i = 0; i < _active_location->schedule.jobs.length; i++) {
+ scheduled_job* job = array_at(&_active_location->schedule.jobs, i);
+
+ // if rescheduling, dont show the timeslots for the job being rescheduled.
+ if (_active_schedule_state == RESCHEDULING_JOB && _active_selected_scheduled_job == job) {
+ continue;
+ }
+
+ for (s32 t = 0; t < job->offer.shipday_count; t++) {
+ scheduled_job_time scheduled_time = job->timeslots[t];
+ s32 tx = TILE_X(scheduled_time.timeslot);
+ s32 ty = TILE_Y(scheduled_time.day);
+ bool is_selected_job = (_active_selected_scheduled_job == job);
+ bool is_selected = (is_selected_job && _active_schedule_selected_job_index == t);
+ bool is_inspecting_employee = false;
+
+ if (_active_selected_scheduled_job != 0 && scheduled_time.assignee == _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index].assignee && !is_selected) {
+ is_inspecting_employee = true;
+ }
+
+ color tc = COLOR_SCHEDULE_TILE_FIXED;
+ if (is_inspecting_employee) {
+ tc = COLOR_SCHEDULE_TILE_HIGHLIGHTED;
+ }
+ else if (is_selected) {
+ tc = COLOR_SCHEDULE_TILE_HOVERED;
+ }
+ if (scheduled_time.assignee == 0) tc = is_selected ? COLOR_SCHEDULE_TILE_HOVERED : COLOR_SCHEDULE_TILE_INVALID;
+ if (is_inspecting_employee || is_selected) {
+ // Draw duration of job.
+ draw_duration_of_scheduled_job_entry(scheduled_time, hour_w, tx, ty, timeslot_w, x, y, timeslot_h, tc);
+ }
+
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, tc);
+ if (is_selected_job && !is_selected) {
+ s32 dotsize = timeslot_w/3;
+ s32 dotoffsetx = (timeslot_w/2)-(dotsize/2);
+ s32 dotoffsety = timeslot_h-(timeslot_h/4)-(dotsize/2);
+ renderer->render_image_tint(img_dot, tx+dotoffsetx,ty+dotoffsety,dotsize,dotsize,COLOR_SCHEDULE_TILE_HOVERED);
+ }
+
+ // Status icon
+ s32 icon_size = timeslot_w*0.6f;
+ if (scheduled_time.assignee == 0) {
+ renderer->render_image(img_questionmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+
+ #if 0
+ color col = COLOR_SCHEDULE_TILE_FIXED;
+ if (is_selected_job) col = COLOR_SCHEDULE_TILE_HIGHLIGHTED;
+ if (is_selected) col = COLOR_SCHEDULE_TILE_HOVERED;
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, col);
+ #endif
+
+ #if 0
+ // Viewing job info box.
+ if (is_selected) {
+ s32 tooltip_offset_from_tile = 15*scale;
+ s32 tooltip_pad = 15*scale;
+ s32 tooltip_h = fnt_s->px_h + (tooltip_pad*2);
+ s32 tooltip_x = tx + timeslot_w + tooltip_offset_from_tile;
+ s32 tooltip_y = ty + (timeslot_h/2)-(tooltip_h/2);
+ // if (tx > area.x + (area.w/2))
+
+ char* tooltip_text = "Maastricht -> Machester";
+ s32 tooltip_text_w = renderer->calculate_text_width(fnt_s, tooltip_text);
+ s32 tooltip_w = tooltip_text_w + (tooltip_pad*2);
+
+ renderer->set_render_depth(5);
+ button_draw_background(scale, tooltip_x,tooltip_y,tooltip_w,tooltip_h, COLOR_WHITE, COLOR_BUTTON);
+ renderer->render_text(fnt_s, tooltip_x+tooltip_pad, tooltip_y+tooltip_pad, tooltip_text, COLOR_TEXT);
+ renderer->set_render_depth(4);
+ }
+ #endif
+
+ if (_active_schedule_state == VIEWING && mouse_interacts(tx,ty,timeslot_w,timeslot_h)) {
+ platform_set_cursor(window, CURSOR_POINTER);
+
+ if (is_left_clicked()) {
+ scheduled_job* prev_selected_scheduled_job = _active_selected_scheduled_job;
+ _active_schedule_state = VIEWING;
+ _active_selected_scheduled_job = job;
+ _active_schedule_selected_job_index = t;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+
+ if (_active_selected_scheduled_job != prev_selected_scheduled_job) {
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+ }
+
+ employee_selector_animation = animation_create(EMPLOYEE_SELECTOR_ANIMATION_DURATION);
+ employee_selector_animation.started = true;
+ }
+ }
+ }
+ }
+ }
+
+ // rows
+ for (s32 ty = 0; ty < ROWS; ty++)
+ {
+ s32 row_y = y + (ty*timeslot_h);
+
+ if (ty==0) {
+ // COLOR_SCHEDULE_ROW_ACTIVE
+ renderer->render_rectangle(x, y, timeslot_w*4, h, COLOR_SCHEDULE_BG);
+ renderer->render_rectangle(x, y, w, timeslot_h, COLOR_SCHEDULE_BG);
+ }
+ else {
+ // Days
+ {
+ char buf[20];
+ switch(ty) {
+ case 1: strcpy(buf, "Mon"); break;
+ case 2: strcpy(buf, "Tue"); break;
+ case 3: strcpy(buf, "Wed"); break;
+ case 4: strcpy(buf, "Thu"); break;
+ case 5: strcpy(buf, "Fri"); break;
+ case 6: strcpy(buf, "Sat"); break;
+ case 7: strcpy(buf, "Sun"); break;
+ }
+
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ s32 textx = x + (hour_w/2)-(tw/2);
+ s32 texty = row_y + (timeslot_h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, buf, COLOR_TEXT);
+ }
+ }
+ renderer->render_rectangle(x, row_y, w, 1, COLOR_SCHEDULE_BORDER);
+ }
+
+ // cols
+ for (s32 tx = 0; tx < COLS; tx++)
+ {
+ s32 row_x = x + (tx*timeslot_w);
+ bool is_big_line = tx % 4 == 0;
+ if (tx>=4 || is_big_line) {
+ s32 liney = y;
+ s32 lineh = h;
+ if (!is_big_line) {
+ liney = y+timeslot_h;
+ lineh = h-timeslot_h;
+ }
+ renderer->render_rectangle(row_x, liney, 1, lineh, (is_big_line) ? COLOR_SCHEDULE_BORDER : COLOR_SCHEDULE_BORDER_THIN);
+ }
+ if (tx!=0 && is_big_line) {
+
+ char buf[20];
+ sprintf(buf, "%d:00", WORK_HOUR_START+((tx-1)/TIME_SLOTS_PER_HOUR));
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ s32 textx = row_x + (hour_w/2)-(tw/2);
+ s32 texty = y + (timeslot_h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, buf, COLOR_TEXT);
+ }
+ }
+
+ // outline
+ renderer->render_rectangle_outline(x,y,w+1,h+1,1,COLOR_SCHEDULE_BORDER);
+
+ x -= schedule_pad;
+ place_detail_draw_schedule_employee_options(window, schedule_pad, scale, x + selector_w + pad_between_items, employee_select_y, options_w, employee_select_h);
+ place_detail_draw_schedule_employee_selector(window, schedule_pad, scale, x, employee_select_y, selector_w, employee_select_h);
+
+ // Deselect selected job.
+ if (mouse_interacts(x+schedule_pad,y,w+1,h+1) && is_left_clicked()) {
+ if (_active_schedule_state == VIEWING) {
+ _active_selected_scheduled_job = 0;
+ }
+ }
+}
+
+static void place_detail_draw_dealers(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+
+ s32 item_count = _active_world->truck_dealers.length;
+
+ s32 spacing = 6;
+ s32 logo_space_w = w / 7.0f;
+ s32 logo_space_h = (h-(spacing*(item_count-1))) / 3.0f;
+
+ for (s32 i = 0; i < item_count; i++)
+ {
+ truck_dealer* d = array_at(&_active_world->truck_dealers, i);
+ if(button_render(scale, true, 0, x, y + (logo_space_h*i)+spacing*i, logo_space_w, logo_space_h)) active_dealer_index = i;
+ render_logo_at(d->logo, 40 * scale, x, y + (logo_space_h*i)+spacing*i, logo_space_w, logo_space_h);
+ }
+
+ if (active_dealer_index < _active_world->truck_dealers.length) {
+ truck_dealer* d = array_at(&_active_world->truck_dealers, active_dealer_index);
+
+ s32 panel_x = x + spacing + logo_space_w;
+ s32 panel_w = (x + w) - panel_x;
+ place_detail_draw_active_dealer(window, d, scale, panel_x, y, panel_w, h);
+ }
+}
+
+static void place_detail_draw_resumes(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+ s32 panel_w = area.w*0.75;
+ s32 panel_h = area.h*0.75;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+
+ bool resume_available = _active_location->resumes.length;
+
+ font* fntb = fnt_rd32;
+ font* fnt = fnt_rd16;
+
+ if (!resume_available) {
+ char* message = "No resumes available.";
+ s32 text_w = renderer->calculate_text_width(fnt, message);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = screen_center_y - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, message, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, message, COLOR_TEXT);
+ }
+ else {
+ s32 panel_w = area.w*0.2;
+ s32 panel_h = area.h*0.3;
+ panel_x = screen_center_x - (panel_w/2);
+ panel_y = screen_center_y - (panel_h/2);
+ resume* resume = array_at(&_active_location->resumes, 0);
+
+ float opacity = 1.0f - resume->animation.percentage;
+ if (opacity < 0.0f) opacity = 0.0f;
+
+ color color_bg = COLOR_WHITE;
+ color_bg.a = opacity*255;
+
+ renderer->render_image_tint(img_resume, panel_x, panel_y, panel_w, panel_h, color_bg);
+
+ char buffer[100];
+ sprintf(buffer, "Resume");
+ s32 text_x = panel_x + (panel_w/2) - (renderer->calculate_text_width(fntb, buffer)/2);
+ s32 text_y = panel_y + (20*scale);
+
+ color t_shadow = COLOR_TEXT_SHADOW;
+ t_shadow.a = opacity*255;
+
+ renderer->render_text(fntb, text_x, text_y, buffer, t_shadow);
+
+ text_x = panel_x + (20*scale);
+ text_y += fntb->px_h+(15*scale);
+
+ sprintf(buffer, "Name: %s", resume->employee->name);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Age: %d", resume->employee->age);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Experience: %d years", resume->employee->experience);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Salary: $%.2f/month", resume->employee->salary);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ struct tm* curr_time = gmtime(&resume->expire_date);
+ text_y += fnt->px_h + 8*scale;
+ strftime(buffer, 50, "Offer open untill %d/%m/%Y", curr_time);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+ text_y += fnt->px_h + 8*scale;
+
+ s32 signature_h = ((panel_y+panel_h)-text_y)*0.6;
+ text_y += (10 * scale);
+ renderer->render_image(img_signature, text_x, text_y, signature_h*2, signature_h);
+
+ if (!resume->animation.started) {
+ s32 button_w = 124 * scale;
+ s32 button_h = 37 * scale;
+ s32 pad = 20 * scale;
+ s32 btn_y = panel_y + panel_h + pad;
+ s32 btn_x = panel_x;
+ if (button_render(scale, true, "Hire", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ resume->animation.started = true;
+ resume->hired = true;
+ resume->employee->id = _active_world->next_id++;
+ resume->employee->hire_date = _active_world->current_time;
+ add_employee_to_world_location(_active_location, resume->employee);
+ }
+ btn_x = panel_x + panel_w - button_w;
+ if (button_render(scale, true, "Decline", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click3, AUDIO_CHANNEL_SFX_1);
+ resume->animation.started = true;
+ resume->hired = false;
+ }
+ }
+ else {
+ s32 pad = scale * 50;
+ s32 stamp_x = panel_x + pad;
+ s32 stamp_y = panel_y + pad;
+ s32 stamp_w = panel_w - (pad*2);
+ s32 stamp_h = panel_h - (pad*2);
+ if (resume->hired) {
+ renderer->render_image_tint(img_hired, stamp_x, stamp_y, stamp_w, stamp_h, color_bg);
+ }
+ else {
+ renderer->render_image_tint(img_denied, stamp_x, stamp_y, stamp_w, stamp_h, color_bg);
+ }
+
+ animation_update(&resume->animation);
+ if (resume->animation.percentage == 1.0f) {
+ array_remove_at(&_active_location->resumes, 0);
+ }
+ }
+ }
+}
+
+static void place_detail_draw_info(platform_window* window, tab tab)
+{
+ float pad = tab.scale * 10;
+ float x = tab.x+pad;
+ float y = tab.y+pad;
+ float w = tab.w-(pad*2);
+ float h = tab.h-(pad*2);
+
+ renderer->render_set_scissor(window, x, y, w, h);
+ if (selected_tab_index == PLACE_DETAIL_EMPLOYEES) {
+ place_detail_draw_employees(window, tab, x, y, w, h);
+ }
+ else if (selected_tab_index == PLACE_DETAIL_JOBOFFERS) {
+ place_detail_draw_job_offers(window, tab, x, y, w, h);
+ }
+ else if (selected_tab_index == PLACE_DETAIL_GARAGE) {
+ place_detail_draw_trucks(window, tab, x, y, w, h);
+ }
+
+ renderer->render_reset_scissor(window);
+}
+
+static tab place_detail_draw_tab_bg(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2));
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y + item_h;
+
+ color fill = COLOR_BUTTON_ACTIVE_TINT;
+
+ // button_render(scale, BUTTON_STATIC, 0, panel_x + pad_x, vertical_pad + panel_y + pad_y*2 + button_h*1, button_w, button_h);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y-1, cornor_size, size_height+2, fill);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y-1, cornor_size, size_height+2, fill);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + size_height, cornor_size, cornor_size, fill);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + size_height, top_width, cornor_size, fill);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + size_height, cornor_size, cornor_size, fill);
+
+ // fill
+ s32 pad = cornor_size-1;
+ fill = COLOR_BUTTON_ACTIVE;
+ renderer->render_rectangle(x+pad, y-1, w-(pad*2), h-(pad*2), fill);
+
+ return (tab){x,y,w,h, scale};
+}
+
+static void place_detail_push_tab(place_detail_info_state index, platform_window* window, char* text)
+{
+ float offset = scale * 40.0;
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 item_w = 426 * 0.4 * scale;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 pos_x = offset + area.x + (area.w*0.05) + (item_w*index);
+ bool hovered = mouse_interacts(pos_x,pos_y,item_w,item_h);
+
+ color tint = COLOR_WHITE;
+ if (selected_tab_index == index) {
+ tint = COLOR_BUTTON_ACTIVE_TINT;
+ }
+ if (hovered) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ if (selected_tab_index != index) audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ selected_tab_index = index;
+ }
+ }
+
+ renderer->render_image_tint(img_tabitem, pos_x, pos_y, item_w, item_h, tint);
+
+ {
+ font* fnt = fnt_rd24;
+ s32 text_x = pos_x + (item_w/2) - (renderer->calculate_text_width(fnt, text)/2);
+ s32 text_y = pos_y + (item_h/2) - (fnt->px_h/2);
+
+ renderer->render_text(fnt, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, text, COLOR_TEXT);
+ }
+}
+
+static tab place_detail_draw_tabs(platform_window* window)
+{
+ place_detail_push_tab(PLACE_DETAIL_EMPLOYEES, window, "Employees");
+ place_detail_push_tab(PLACE_DETAIL_JOBOFFERS, window, "Job Offers");
+ place_detail_push_tab(PLACE_DETAIL_SCHEDULE, window, "Schedule");
+ place_detail_push_tab(PLACE_DETAIL_GARAGE, window, "Garage");
+ return place_detail_draw_tab_bg(window);
+}
+
+static void place_detail_draw_title(platform_window* window)
+{
+ char buf[200];
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ strcpy(buf, _active_location->name);
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) {
+ strcpy(buf, "Hire new employees");
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_DEALERS) {
+ strcpy(buf, "Dealers");
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ sprintf(buf, "%s, #%d", _active_employee->name, _active_employee->id);
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE) {
+ if (_active_schedule_state == VIEWING)
+ sprintf(buf, "Schedule for %s", _active_location->name);
+ else {
+ sprintf(buf, "%s wants you to ship %s to %s",
+ _active_scheduling_job.offer.company->name,
+ _active_scheduling_job.offer.product->name,
+ (*(world_location**)array_at(&_active_scheduling_job.offer.connections,
+ _active_scheduling_job.offer.connections.length-1))->name);
+ }
+ }
+
+ font* fnt = fnt_rd36;
+ float text_pad = scale * 40.0;
+ s32 text_x = text_pad + area.x + (area.w*0.05);
+ s32 text_y = text_pad + area.y + (area.w*0.05);
+
+ // Title
+ {
+ renderer->render_text(fnt, text_x+2, text_y+2, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);
+ }
+
+ color tags_text_color = AN_LI_TINT(COLOR_TEXT, tag_animation);
+ color tag_icon_color = AN_LI_TINT(COLOR_WHITE, tag_animation);
+
+ // Tags
+ #define PUSH_TAG(_text, _icon){\
+ char* text = _text;\
+ s32 textw = renderer->calculate_text_width(fnt, text);\
+ text_x -= textw;\
+ renderer->render_text(fnt, text_x, text_y, text, tags_text_color);\
+ text_x -= icon_s + pad_between_icon_and_text;\
+ renderer->render_image_tint(_icon, text_x, text_y,icon_s,icon_s, tag_icon_color);\
+ text_x -= pad_between_tags;}
+
+ text_y += (fnt->px_h/2);
+ fnt = fnt_rd20;
+ text_y -= (fnt->px_h/2);
+ s32 icon_s = fnt->px_h;
+ s32 pad_between_icon_and_text = 5*scale;
+ s32 pad_between_tags = 20*scale;
+
+ #define ANIMATION_OFFSET (30*scale)
+ text_x = area.x + (area.w*0.05) + (area.w*0.9) - text_pad + (ANIMATION_OFFSET-(ANIMATION_OFFSET*tag_animation.percentage));
+ #undef ANIMATION_OFFSET
+
+ job_offer* job_to_inspect = 0;
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && _active_schedule_state != VIEWING)
+ job_to_inspect = &_active_scheduling_job.offer;
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && _active_schedule_state == VIEWING && _active_selected_scheduled_job != 0)
+ job_to_inspect = &_active_selected_scheduled_job->offer;
+
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && job_to_inspect) {
+ // price
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "$%d/trip", job_to_inspect->reward);
+ PUSH_TAG(pricebuf, img_coins);
+ }
+
+ // distance
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fkm", job_to_inspect->total_distance);
+ PUSH_TAG(pricebuf, img_road);
+ }
+
+ // duration
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fh-%.0fh", job_to_inspect->duration_sec_min/3600.0f, job_to_inspect->duration_sec_max/3600.0f);
+ PUSH_TAG(pricebuf, img_timer);
+ }
+
+ if (_active_schedule_state == VIEWING) {
+ char namebuf[MAX_WORLD_LOCATION_NAME_LENGTH*3];
+ job_endpoints endpoints = job_offer_get_endpoints(job_to_inspect);
+ sprintf(namebuf, "%s to %s", endpoints.source->name, endpoints.dest->name);
+ PUSH_TAG(namebuf, img_globe);
+ }
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ // Original location
+ {
+ char pricebuf[100];
+ sprintf(pricebuf, "From: %s", get_world_location_by_id(_active_world, _active_employee->original_location_id)->name);
+ PUSH_TAG(pricebuf, img_city);
+ }
+
+ // Current location or active trip destination
+ {
+ char pricebuf[100];
+ if (_active_employee->current_location_id != INVALID_ID) {
+ sprintf(pricebuf, "Currently at: %s", get_world_location_by_id(_active_world, _active_employee->current_location_id)->name);
+ }
+ else if (_active_employee->active_job_id != INVALID_ID) {
+ active_job* j = get_active_job_by_id(_active_world, _active_employee->active_job_id);
+ job_endpoints endpoints = job_offer_get_endpoints(&j->offer);
+ sprintf(pricebuf, "Driving to: %s", endpoints.dest->name);
+ }
+ PUSH_TAG(pricebuf, img_location_pin);
+ }
+ }
+
+ animation_update(&tag_animation);
+}
+
+static void place_detail_draw_panel(platform_window* window)
+{
+ s32 panel_w = area.w*0.9;
+ s32 panel_h = area.h*0.7;
+ s32 panel_x = area.x + area.w*0.05;
+ s32 panel_y = area.y + area.w*0.05;
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // back button
+ {
+ s32 back_h = img_back->height * scale/2;
+ s32 back_w = img_back->width * scale/2;
+ s32 back_x = panel_x + (panel_w/10.0f);
+ s32 back_y = panel_y + panel_h - (back_h/2) - 1;
+
+ if (push_back_button(scale, back_x, back_y, back_w, back_h)) {
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+ else {
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ _goto_default_detail_state();
+ }
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ }
+ else if (is_left_clicked()) {
+ _goto_default_detail_state();
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+}
+
+void place_detail_scene_render(platform_window* window)
+{
+ renderer->set_render_depth(5);
+ world_map_draw_info_panel(window, false);
+
+ renderer->set_render_depth(4);
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ tab t = place_detail_draw_tabs(window);
+ place_detail_draw_info(window, t);
+
+ if (selected_tab_index == PLACE_DETAIL_SCHEDULE) {
+ selected_tab_index = PLACE_DETAIL_SHOW_MAIN;
+ current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
+ }
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) {
+ place_detail_draw_resumes(window);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_DEALERS) {
+ place_detail_draw_dealers(window);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ place_detail_draw_selected_employee(window);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE) {
+ place_detail_draw_schedule(window);
+ }
+
+ renderer->set_render_depth(3);
+ place_detail_draw_title(window);
+
+ renderer->set_render_depth(2);
+ place_detail_draw_panel(window);
+
+ renderer->set_render_depth(1);
+ menu_draw_background(window);
+}
+
+void place_detail_scene_update(platform_window* window)
+{
+ // world_update(window, _active_world, false);
+
+ if (keyboard_is_key_pressed(KEY_ESCAPE)) {
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+ else {
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ _goto_default_detail_state();
+ }
+}
+
+void place_detail_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/save_state_select.c b/src/scenes/save_state_select.c new file mode 100644 index 0000000..1db5d11 --- /dev/null +++ b/src/scenes/save_state_select.c @@ -0,0 +1,105 @@ +
+void save_state_select_scene_init()
+{
+
+}
+
+static bool push_save_state_button(float scale, bool enabled, s32 x, s32 y, s32 size)
+{
+ if (enabled) {
+ button_render(scale, true, 0, x, y, size, size);
+ }
+ else {
+ button_render(scale, true, 0, x, y, size, size);
+ float close_size = size/3;
+ float close_x = x + (size/2)-(close_size/2);
+ float close_y = y + (size/2)-(close_size/2);
+ renderer->render_image(img_close, close_x, close_y, close_size, close_size);
+ }
+
+ return false;
+}
+
+static bool push_back_button(float scale, s32 back_x, s32 back_y, s32 back_w, s32 back_h)
+{
+ bool result = false;
+ color tint = COLOR_WHITE;
+ if (mouse_interacts(back_x,back_y,back_w,back_h)) {
+ tint = COLOR_BUTTON_ACTIVE_TINT;
+ platform_set_cursor(main_window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ result = true;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ }
+
+ renderer->render_image_tint(img_back, back_x, back_y, back_w, back_h, tint);
+
+ font* font_sml = fnt_rd20;
+ char* back_text = "Back";
+ s32 back_text_width = renderer->calculate_text_width(font_sml, back_text);
+ s32 text_x = back_x + (back_w/2) - (back_text_width/2) + (back_w/12);
+ s32 text_y = back_y + (back_h/2) - (font_sml->px_h/2);
+
+ renderer->render_text(font_sml, text_x+2, text_y+2, back_text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_sml, text_x, text_y, back_text, COLOR_TEXT);
+ return result;
+}
+
+static void save_state_draw_options(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ float vertical_pad = 20 * scale;
+ float horizontal_pad = vertical_pad;
+ float spacing = 5 * scale;
+
+ s32 panel_h = 280 * scale;
+ s32 panel_item_size = (panel_h - (vertical_pad*2) - (spacing*1)) / 2;
+ s32 panel_w = (panel_item_size * 3) + (horizontal_pad*2) + (spacing*2);
+
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // top row
+ for (s32 i = 0; i < 3; i++)
+ push_save_state_button(scale, 0, panel_x + horizontal_pad + (panel_item_size*i) +
+ (spacing*i), panel_y + horizontal_pad, panel_item_size);
+
+ // bottom row
+ for (s32 i = 0; i < 3; i++)
+ push_save_state_button(scale, 0, panel_x + horizontal_pad + (panel_item_size*i) + (spacing*i),
+ panel_y + horizontal_pad + panel_item_size+spacing, panel_item_size);
+
+ // back button
+ {
+ s32 back_h = img_back->height * scale/2;
+ s32 back_w = img_back->width * scale/2;
+ s32 back_x = panel_x + (panel_item_size/3);
+ s32 back_y = panel_y + panel_h - (back_h/2) - 1;
+
+ if (push_back_button(scale, back_x, back_y, back_w, back_h)) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+ }
+}
+
+void save_state_select_scene_render(platform_window* window)
+{
+ menu_draw_background(window);
+ save_state_draw_options(window);
+}
+
+void save_state_select_scene_update(platform_window* window)
+{
+ if (keyboard_is_key_pressed(KEY_ESCAPE)) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+}
+
+void save_state_select_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/scenes/settings_scene.c b/src/scenes/settings_scene.c new file mode 100644 index 0000000..23655d3 --- /dev/null +++ b/src/scenes/settings_scene.c @@ -0,0 +1,152 @@ +enum settings_state
+{
+ SETTINGS_AUDIO,
+ SETTINGS_DISPLAY,
+ SETTINGS_KEYBINDINGS,
+};
+
+enum settings_state settings_state = SETTINGS_AUDIO;
+
+void settings_scene_init() {
+
+}
+
+static void draw_display_settings(s32 x, s32 y, s32 w, s32 h)
+{
+ s32 option_spacing = 20*scale;
+ s32 checkbox_s = 30*scale;
+ s32 checkbox_offset = ((checkbox_s-fnt_rd24->px_h)/2);
+ s32 text_y = y + option_spacing;
+ s32 text_x = x + checkbox_s + option_spacing;
+
+ #define PUSH_DISPLAY_OPTION(_str, _opt)\
+ renderer->render_text(fnt_rd24, text_x, text_y, _str, COLOR_TEXT);\
+ if (button_draw_background(scale, x,text_y-checkbox_offset, checkbox_s, checkbox_s, COLOR_WHITE, COLOR_BUTTON)) {\
+ if (is_left_clicked()) { \
+ _opt = !_opt;\
+ if (&_opt == &option_vsync) platform_toggle_vsync(main_window, option_vsync);\
+ if (&_opt == &option_fullscreen) platform_toggle_fullscreen(main_window, option_fullscreen);\
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);\
+ }\
+ }\
+ if (_opt) {\
+ s32 tw = renderer->calculate_text_width(fnt_rd24, "X");\
+ renderer->render_text(fnt_rd24, x + checkbox_s/2 - tw/2,text_y-checkbox_offset + checkbox_s/2 - fnt_rd24->px_h/2, "X", COLOR_TEXT);\
+ }\
+ text_y += (checkbox_s + option_spacing);
+
+ PUSH_DISPLAY_OPTION("Vsync", option_vsync);
+ PUSH_DISPLAY_OPTION("Fullscreen", option_fullscreen);
+}
+
+static void draw_audio_settings(s32 x, s32 y, s32 w, s32 h)
+{
+ s32 option_spacing = 20*scale;
+ s32 slider_h = 30*scale;
+ s32 slider_offset = ((slider_h-fnt_rd24->px_h)/2);
+ s32 slider_w = w/2;
+ s32 slider_x = x + slider_w;
+ s32 text_y = y + option_spacing;
+
+ // Music
+ #define PUSH_VOLUME_OPTION(_text, _opt)\
+ {\
+ static bool is_editing = false;\
+ renderer->render_text(fnt_rd24, x, text_y, _text, COLOR_TEXT);\
+ s32 slider_y = text_y - slider_offset;\
+ float percentage = is_editing ? ((_global_mouse.x - (slider_x+10*scale)) / (float)(slider_w-20*scale)) : _opt;\
+ if (percentage < 0.0f) percentage = 0.0f;\
+ if (percentage > 1.0f) percentage = 1.0f;\
+ button_draw_background_percentage(scale, slider_x,slider_y,slider_w,slider_h, COLOR_WHITE, COLOR_BUTTON, percentage, COLOR_WHITE);\
+ bool hovered = mouse_interacts(slider_x,slider_y,slider_w,slider_h);\
+ if (hovered && is_left_clicked()) is_editing = true;\
+ if (is_editing) {\
+ audio_set_mixer_volume(AUDIO_CHANNEL_SFX_1, volume_sfx*volume_global);\
+ audio_set_mixer_volume(AUDIO_CHANNEL_SFX_2, volume_sfx*volume_global);\
+ audio_set_music_volume(volume_music*volume_global);\
+ }\
+ if (is_editing) {\
+ if (!is_left_down()) { is_editing = false; audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1); }\
+ _opt = percentage;\
+ }\
+ text_y += (slider_h + option_spacing);\
+ }
+
+ PUSH_VOLUME_OPTION("Global", volume_global);
+ PUSH_VOLUME_OPTION("Music", volume_music);
+ PUSH_VOLUME_OPTION("Interface", volume_sfx);
+}
+
+static void settings_draw_options(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ s32 panel_w = 400 * scale;
+ s32 panel_h = 500 * scale;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // Buttons
+ s32 button_pad = 10*scale;
+ s32 button_w = (panel_w-(button_pad*4))/3;
+ s32 button_h = 37*scale;
+ s32 button_y = panel_y + button_pad*1.3f;
+ s32 button_x = panel_x + button_pad;
+
+ if (button_render(scale, BUTTON_ENABLED, "Audio", button_x, button_y, button_w, button_h))
+ {
+ settings_state = SETTINGS_AUDIO;
+ }
+
+ if (button_render(scale, BUTTON_ENABLED, "Display", button_x + (button_w + button_pad), button_y, button_w, button_h))
+ {
+ settings_state = SETTINGS_DISPLAY;
+ }
+
+ if (button_render(scale, BUTTON_ENABLED, "Keybindings", button_x + (button_w + button_pad)*2, button_y, button_w, button_h))
+ {
+ settings_state = SETTINGS_KEYBINDINGS;
+ }
+
+ s32 detail_pad = 25*scale;
+ s32 detail_w = panel_w - (detail_pad*2)-(button_pad*2);
+ s32 detail_h = panel_h - (detail_pad*2)-(button_pad*3)-button_h;
+ s32 detail_x = panel_x+detail_pad+button_pad;
+ s32 detail_y = button_y + button_h + detail_pad+button_pad;
+
+ if (settings_state == SETTINGS_AUDIO) {
+ draw_audio_settings(detail_x, detail_y, detail_w, detail_h);
+ }
+ else if (settings_state == SETTINGS_DISPLAY) {
+ draw_display_settings(detail_x, detail_y, detail_w, detail_h);
+ }
+
+ // back button
+ {
+ s32 back_h = img_back->height * scale/2;
+ s32 back_w = img_back->width * scale/2;
+ s32 back_x = panel_x + (panel_w/10);
+ s32 back_y = panel_y + panel_h - (back_h/2) - 1;
+
+ if (push_back_button(scale, back_x, back_y, back_w, back_h)) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+ }
+}
+
+void settings_scene_render(platform_window* window) {
+ menu_draw_background(window);
+ settings_draw_options(window);
+}
+
+void settings_scene_update(platform_window* window) {
+ if (keyboard_is_key_pressed(KEY_ESCAPE)) {
+ game_set_active_scene(GAME_STATE_MENU);
+ }
+}
+
+void settings_scene_destroy() {
+
+}
\ No newline at end of file diff --git a/src/scenes/world_map.c b/src/scenes/world_map.c new file mode 100644 index 0000000..eb106cb --- /dev/null +++ b/src/scenes/world_map.c @@ -0,0 +1,1094 @@ +typedef enum t_world_map_scene_state
+{
+ WORLD_SCENE_STATE_IDLE,
+ WORLD_SCENE_STATE_PURCHASE_LOCATION,
+ WORLD_SCENE_STATE_LOG,
+ WORLD_SCENE_STATE_INSIGHTS,
+ WORLD_SCENE_STATE_INVEST,
+} world_map_scene_state;
+
+typedef union t_world_map_scene_data
+{
+ world_location* location_to_purchase;
+} world_map_scene_data;
+
+s32 insights_selected_year_index = 0; // years since first year.
+world* _active_world = 0;
+world_map_scene_state scene_state = WORLD_SCENE_STATE_IDLE;
+world_map_scene_data scene_data = {0};
+active_job_ref currently_viewing_active_job = {0,0,0};
+
+animation log_button_flash_animation = {0,0,0,1};
+
+void place_detail_show_employee_detail(employee* emp);
+void place_detail_show_schedule_with_highlighted_job(world_location* loc, scheduled_job* job, scheduled_job_time job_time);
+
+void world_map_set_active_world(world* world)
+{
+ _active_world = world;
+}
+
+void world_map_scene_init()
+{
+
+}
+
+static bool push_info_panel_button(float scale, image* img, s32 x, s32 y, s32 size, bool enabled, bool flashing)
+{
+ button_type type = (enabled ? ((flashing && log_button_flash_animation.percentage >= 0.5f) ? BUTTON_HIGHLIGHTED : BUTTON_ENABLED) : BUTTON_DISABLED);
+ bool result = button_render(scale, type, 0, x, y, size, size);
+
+ float img_size = size / 2;
+ renderer->render_image(img, x+(img_size/2), y + (img_size/2), img_size, img_size);
+ return result;
+}
+
+static void world_map_draw_speed_panel(platform_window* window, bool enabled)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+
+ s32 panel_h = 60 * scale;
+ s32 panel_w = 180 * scale;
+
+ float btn_size = 23 * scale;
+ float pad_top = 6 * scale;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = area.y + area.h - panel_h - (100 * scale);
+ s32 text_y = panel_y + pad_top;
+ float side_btn_offset = pad_top;
+
+ // Background panel
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // Button decrease simulation speed
+ if (push_info_panel_button(scale, img_arrow_left, screen_center_x - (panel_w/2) + side_btn_offset, text_y, btn_size, enabled, false)) {
+ _active_world->simulation_speed/=2;
+ }
+ // Button increase simulation speed
+ if (push_info_panel_button(scale, img_arrow_right, screen_center_x + (panel_w/2) - btn_size - side_btn_offset, text_y, btn_size, enabled, false)) {
+ _active_world->simulation_speed*=2;
+ if (_active_world->simulation_speed == 0) _active_world->simulation_speed = 1;
+ }
+
+ // Validate new simulation speed
+ if (_active_world->simulation_speed < MIN_SIMULATION_SPEED) _active_world->simulation_speed = MIN_SIMULATION_SPEED;
+ if (_active_world->simulation_speed > MAX_SIMULATION_SPEED) _active_world->simulation_speed = MAX_SIMULATION_SPEED;
+
+ // Draw the current speed, or pause icon when paused
+ if (_active_world->simulation_speed != 0) {
+ font* fnt = fnt_rd20;
+
+ char buf[10];
+ sprintf(buf, "%dx", _active_world->simulation_speed);
+
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ s32 textx = panel_x + (panel_w/2)-(tw/2);
+ renderer->render_text(fnt, textx, text_y+(5*scale), buf, COLOR_TEXT);
+ }
+ else {
+ s32 icon_pad = 4*scale;
+ s32 icon_s = btn_size-(icon_pad*2);
+ renderer->render_image(img_pause, panel_x+(panel_w/2)-(icon_s/2), text_y+icon_pad, icon_s, icon_s);
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ }
+}
+
+static void world_map_draw_info_panel(platform_window* window, bool enabled)
+{
+ world_map_draw_speed_panel(window, enabled);
+
+ s32 screen_center_x = area.x + (area.w/2);
+
+ float vertical_pad = 20 * scale;
+
+ s32 panel_h = 120 * scale;
+ s32 panel_w = 280 * scale;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = area.y + area.h - panel_h - (10 * scale);
+
+ // Draw background panel
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ if (enabled) {
+ char txt_buf[50];
+ char* text = txt_buf;
+ s32 text_y;
+ s32 text_x;
+ font* font_big = fnt_rd32;
+ s32 game_title_width;
+
+ // Draw current date and time
+ {
+ strftime(txt_buf, 50, "%H:%M %d/%m/%Y", &_active_world->current_time);
+ game_title_width = renderer->calculate_text_width(font_big, text);
+ text_y = panel_y + vertical_pad;
+ text_x = screen_center_x - (game_title_width/2);
+
+ renderer->render_text(font_big, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_big, text_x, text_y, text, COLOR_TEXT);
+ }
+
+ // Draw money
+ {
+ sprintf(txt_buf, "$%.0f", _active_world->money);
+ text = txt_buf;
+ font* font_medium = fnt_rd24;
+ game_title_width = renderer->calculate_text_width(font_medium, text);
+ text_y = text_y + font_big->px_h + (10 * scale);
+ text_x = screen_center_x - (game_title_width/2);
+
+ renderer->render_text(font_medium, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_medium, text_x, text_y, text, COLOR_TEXT);
+ }
+
+ float btn_size = 35 * scale;
+ float btn_spacing = 2 * scale;
+ float btn_y = panel_y + panel_h - btn_size - vertical_pad/2;
+ float total_btn_w = (btn_size+btn_spacing)*4-btn_spacing;
+
+ if (log_button_flash_animation.percentage == 1.0f) log_button_flash_animation = animation_create(1000);
+ log_button_flash_animation.started = true;
+ animation_update(&log_button_flash_animation);
+
+ // Graph button
+ if (push_info_panel_button(scale, img_graph, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*0, btn_y, btn_size, enabled, false)) {
+ scene_state = (scene_state == WORLD_SCENE_STATE_INSIGHTS) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_INSIGHTS;
+ }
+
+ // Event log button
+ if (push_info_panel_button(scale, img_list, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*1, btn_y, btn_size, enabled, _active_world->log.has_unread_messages)) {
+ scene_state = (scene_state == WORLD_SCENE_STATE_LOG) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_LOG;
+ }
+
+ // Bank button
+ push_info_panel_button(scale, img_bank, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*2, btn_y, btn_size, enabled, false);
+
+ // Event log button
+ if (push_info_panel_button(scale, img_list, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*3, btn_y, btn_size, enabled, _active_world->log.has_unread_messages)) {
+ scene_state = (scene_state == WORLD_SCENE_STATE_INVEST) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_INVEST;
+ }
+ }
+ else {
+ s32 icon_s = panel_h/2;
+ renderer->render_image(img_pause, panel_x+(panel_w/2)-(icon_s/2), panel_y+(panel_h/2)-(icon_s/2), icon_s, icon_s);
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ }
+}
+
+static void _insights_draw_grid(float scale, bool invalid_location, money_data_collection* collection, s32 grid_rows, s32 grid_cols, s32 textpad, s32 x, s32 y, s32 w, s32 h, s32 width_per_item, s32 height_per_item)
+{
+ font* fnt = fnt_rd16;
+ font* fnt_title = fnt_rd24;
+
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {
+ if (!collection) break;
+ money_data data = collection->months[i];
+ if (isnan(data.total_income)) continue;
+
+ char textbuf[50];
+ #define PUSH_VAL(_index, _val, _neg)\
+ sprintf(textbuf, "$%.0f", fabs(_val));\
+ renderer->render_text(fnt, x + ((i+3)*width_per_item) + (textpad/2), y + (_index*height_per_item)+(height_per_item/2)-(fnt->px_h/2), textbuf, (_neg) ? COLOR_TEXT_NEGATIVE : COLOR_TEXT);
+
+ PUSH_VAL(1, data.income_from_trips, false);
+ PUSH_VAL(2, data.expenses_from_utility, true);
+ PUSH_VAL(3, data.expenses_from_healthcare, true);
+ PUSH_VAL(4, data.expenses_from_repairs, true);
+ PUSH_VAL(5, data.expenses_from_fuel, true);
+ PUSH_VAL(6, data.expenses_from_employees, true);
+ PUSH_VAL(7, data.expenses_from_trucks, true);
+ // ADD NEW ENTRY HERE
+ PUSH_VAL(9, data.total_income, false);
+ PUSH_VAL(10, data.total_expenses, true);
+ PUSH_VAL(11, data.total_profit, data.total_profit < 0.0f);
+ }
+
+ renderer->render_rectangle(x, y, width_per_item*3, h, COLOR_SCHEDULE_BG);
+ renderer->render_rectangle(x, y, w, height_per_item, COLOR_SCHEDULE_BG);
+
+ for (s32 tx = 3; tx < grid_cols; tx++) {
+ s32 posx = x + tx * width_per_item;
+ renderer->render_rectangle(posx,y,1,h, COLOR_SCHEDULE_BORDER_THIN);
+
+ char buf[50];
+ buf[0] = 0;
+
+ switch(tx-2) {
+ case 1: strcpy(buf, "Jan"); break;
+ case 2: strcpy(buf, "Feb"); break;
+ case 3: strcpy(buf, "Mar"); break;
+ case 4: strcpy(buf, "Apr"); break;
+ case 5: strcpy(buf, "May"); break;
+ case 6: strcpy(buf, "Jun"); break;
+ case 7: strcpy(buf, "Jul"); break;
+ case 8: strcpy(buf, "Aug"); break;
+ case 9: strcpy(buf, "Sep"); break;
+ case 10: strcpy(buf, "Oct"); break;
+ case 11: strcpy(buf, "Nov"); break;
+ case 12: strcpy(buf, "Dec"); break;
+ default: break;
+ }
+
+ s32 textw = renderer->calculate_text_width(fnt_title, buf);
+ renderer->render_text(fnt_title, posx + (width_per_item/2)-(textw/2), y+(height_per_item/2)-(fnt_title->px_h/2), buf, COLOR_TEXT);
+ }
+
+ for (s32 ty = 0; ty < grid_rows; ty++) {
+ s32 posy = y + ty * height_per_item;
+ renderer->render_rectangle(x,posy,w,1, COLOR_SCHEDULE_BORDER_THIN);
+
+ char buf[50];
+ buf[0] = 0;
+
+ switch(ty) {
+ case 1: strcpy(buf, "Income"); break;
+ case 2: strcpy(buf, "Utility"); break;
+ case 3: strcpy(buf, "Employee Benefits"); break;
+ case 4: strcpy(buf, "Repairs"); break;
+ case 5: strcpy(buf, "Fuel"); break;
+ case 6: strcpy(buf, "Salaries"); break;
+ case 7: strcpy(buf, "Trucks"); break;
+ // ADD NEW ENTRY HERE
+ case 9: strcpy(buf, "Total Income"); break;
+ case 10: strcpy(buf, "Total Expenses"); break;
+ case 11: strcpy(buf, "Total Profit"); break;
+ default: break;
+ }
+
+ renderer->render_text(fnt_title, x + textpad, posy+(height_per_item/2)-(fnt_title->px_h/2), buf, COLOR_TEXT);
+ }
+
+ if (!collection) {
+ char* txtbuf = invalid_location ? "Invalid location" : "No data for time period";
+ s32 textw = renderer->calculate_text_width(fnt_title, txtbuf);
+ s32 textx = x + (width_per_item*9) - (textw/2);
+ s32 texty = y + (h/2)-(fnt_title->px_h/2);
+ renderer->render_text(fnt_title, textx, texty, txtbuf, COLOR_TEXT);
+ }
+
+ renderer->render_rectangle_outline(x,y,w,h, 1, COLOR_SCHEDULE_BORDER);
+}
+
+static void _insights_draw_chart(platform_window*window, bool invalid_location, float scale, money_data_collection* collection, s32 grid_rows, s32 grid_cols, s32 textpad, s32 x, s32 y, s32 w, s32 h, s32 width_per_item, s32 height_per_item)
+{
+ font* fnt = fnt_rd16;
+ font* fnt_big = fnt_rd24;
+
+ s32 xaxis_height = fnt_big->px_h;
+ h -= xaxis_height;
+
+ s32 max_val = 0;
+ s32 min_val = INT_MAX;
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {
+ if (!collection) break;
+ money_data data = collection->months[i];
+
+ #define CHECK_MIN_MAX(_val)\
+ if (_val > max_val) max_val = _val;\
+ if (_val < min_val) min_val = _val;
+
+ CHECK_MIN_MAX(data.income_from_trips);
+ CHECK_MIN_MAX(data.expenses_from_utility);
+ CHECK_MIN_MAX(data.expenses_from_healthcare);
+ CHECK_MIN_MAX(data.expenses_from_repairs);
+ CHECK_MIN_MAX(data.expenses_from_fuel);
+ CHECK_MIN_MAX(data.expenses_from_employees);
+ CHECK_MIN_MAX(data.expenses_from_trucks);
+ // ADD NEW ENTRY HERE
+ CHECK_MIN_MAX(data.total_income);
+ CHECK_MIN_MAX(data.total_expenses);
+ CHECK_MIN_MAX(data.total_profit);
+ }
+
+ if (min_val == INT_MAX) min_val = 0;
+
+ s32 steps = 10;
+ s32 step_size = 0;
+
+ // Round min and max to nearest 10k
+ {
+ s32 max = max_val >= abs(min_val) ? max_val : abs(min_val);
+ s32 round_to = 10000;
+ if (max > 10000) round_to = 10000;
+ if (max > 100000) round_to = 100000;
+ if (max > 1000000) round_to = 1000000;
+ if (max > 10000000) round_to = 10000000;
+ if (max > 100000000) round_to = 100000000;
+
+ max_val = max_val + round_to - max_val % round_to;
+ if (min_val > round_to) min_val = min_val - min_val % round_to;
+ else min_val = min_val - round_to - (min_val%round_to);
+
+ // make sure negative and positive y-axis is symmetrical
+ if (max_val > abs(min_val)) {
+ min_val = -max_val;
+ }
+ else if (max_val < abs(min_val)) {
+ max_val = abs(min_val);
+ }
+
+ step_size = (max_val-min_val)/steps;
+ }
+
+ static bool enabled_categories[10] = {1,1,1,1,1,1,1,1,1,1};
+
+ color colors[] = {
+ rgb(87, 82, 208),
+ rgb(3, 118, 247),
+ rgb(54, 166, 214),
+ rgb(50, 140, 250),
+ rgb(90, 196, 248),
+ rgb(78, 213, 95),
+ rgb(252, 200, 3),
+ rgb(249, 146, 5),
+ rgb(249, 59, 47),
+ rgb(249, 45, 82),
+ };
+
+ char* legenda_items[] = {
+ "Income",
+ "Utility",
+ "Employee Benefits",
+ "Repairs",
+ "Fuel",
+ "Salaries",
+ "Trucks",
+ // ADD NEW ENTRY HERE
+ "Total Income",
+ "Total Expenses",
+ "Total Profit",
+ };
+
+ // Legenda
+ {
+ s32 text_spacing = 10*scale;
+ s32 outline_spacing = text_spacing/2;
+ s32 _index = 0;
+
+ #define PUSH_LEGENDA_ITEM(_text){\
+ s32 yy = y+((fnt_big->px_h+text_spacing)*_index);\
+ s32 totalw = width_per_item*3;\
+ bool hovered = (_global_mouse.x >= x-outline_spacing && _global_mouse.x <= x+totalw+outline_spacing\
+ && _global_mouse.y >= yy-outline_spacing && _global_mouse.y <= yy + fnt_big->px_h+outline_spacing);\
+ if (hovered) {platform_set_cursor(window, CURSOR_POINTER); if (is_left_clicked())\
+ { enabled_categories[_index] = !enabled_categories[_index]; audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1); }}\
+ renderer->render_rectangle(x,yy,fnt_big->px_h, fnt_big->px_h, enabled_categories[_index] ? colors[_index] : LEGENDA_COLOR_DISABLED);\
+ if (hovered) renderer->render_rectangle(x-outline_spacing,yy-outline_spacing,totalw+(text_spacing),fnt_big->px_h+(text_spacing), LEGENDA_HOVER_BACKGROUND_COLOR);\
+ renderer->render_text(fnt_big,x+fnt_big->px_h+text_spacing,yy,_text,COLOR_TEXT);_index++;}
+
+ for (s32 i = 0; i < sizeof(legenda_items)/sizeof(char*); i++) {
+ PUSH_LEGENDA_ITEM(legenda_items[i]);
+ }
+ }
+
+ // Graph y axis
+ {
+ s32 linex = x + 4*width_per_item;
+
+ float step_h = (h)/(float)steps;
+ for (s32 i = 0; i < steps+1; i++) {
+ char buf[20];
+ s32 val = max_val - (step_size*i);
+ sprintf(buf, "%d", val);
+ s32 textw = renderer->calculate_text_width(fnt, buf);
+ renderer->render_text(fnt, x+(width_per_item*4)-textw-(10*scale), y+(step_h*i)-(fnt->px_h/2), buf, COLOR_TEXT);
+ renderer->render_rectangle(linex, y+h*(i/(float)steps), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_SUB_COLOR_DISABLED);
+ }
+
+ {
+ renderer->render_rectangle(linex, y + h - (h*1.0f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED);
+ renderer->render_rectangle(linex, y + h - (h*0.5f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED);
+ renderer->render_rectangle(linex, y + h - (h*0.0f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED);
+ }
+ }
+
+ // Graph x axis
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {
+ char buf[50];
+ buf[0] = 0;
+
+ switch(i+1) {
+ case 1: strcpy(buf, "Jan"); break;
+ case 2: strcpy(buf, "Feb"); break;
+ case 3: strcpy(buf, "Mar"); break;
+ case 4: strcpy(buf, "Apr"); break;
+ case 5: strcpy(buf, "May"); break;
+ case 6: strcpy(buf, "Jun"); break;
+ case 7: strcpy(buf, "Jul"); break;
+ case 8: strcpy(buf, "Aug"); break;
+ case 9: strcpy(buf, "Sep"); break;
+ case 10: strcpy(buf, "Oct"); break;
+ case 11: strcpy(buf, "Nov"); break;
+ case 12: strcpy(buf, "Dec"); break;
+ default: break;
+ }
+ s32 textw = renderer->calculate_text_width(fnt,buf);
+
+ renderer->render_text(fnt, x+(width_per_item*(i+4))-(textw/2), y+h+(10*scale), buf, COLOR_TEXT);
+ }
+
+ // Graph data
+ {
+ s32 total_diff = max_val-min_val;
+ if (total_diff == 0) total_diff = 1;
+
+ s32 dot_size = 4*scale;
+ s32 dot_offset =dot_size/2;
+ s32 _index = 0;
+ //if (min_val < 0) min_val = 0;
+
+ #define DRAW_LINES_FOR_DATA(_var){\
+ s32 last_dot_x = 0;\
+ s32 last_dot_y = 0;\
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {\
+ if (!collection) break;\
+ if (!enabled_categories[_index]) break;\
+ money_data data = collection->months[i];\
+ if (isnan(data.total_income)) continue;\
+ s32 val_diff = (_var) - min_val;\
+ s32 dot_x = x + (i+4)*width_per_item;\
+ s32 dot_y = y + h - (h*(val_diff/(float)total_diff));\
+ renderer->render_image_tint(img_dot, dot_x-dot_offset, dot_y-dot_offset, dot_size, dot_size, colors[_index]);\
+ if (mouse_interacts(dot_x-dot_offset, dot_y-dot_offset, dot_size, dot_size)) {\
+ reset_left_click();\
+ s32 info_x = dot_x;\
+ s32 info_y = dot_y+(dotsize/2);\
+ char info_txt[50];\
+ sprintf(info_txt, "%s: $%.0f", legenda_items[_index], _var);\
+ show_tooltip(info_x, info_y, info_txt);\
+ }\
+ if (last_dot_x != 0) {\
+ renderer->render_line(dot_x, dot_y, last_dot_x, last_dot_y, 1, colors[_index]);\
+ }\
+ last_dot_x = dot_x;\
+ last_dot_y = dot_y;\
+ }_index++;\
+ }
+
+ DRAW_LINES_FOR_DATA(data.income_from_trips);
+ DRAW_LINES_FOR_DATA(data.expenses_from_utility);
+ DRAW_LINES_FOR_DATA(data.expenses_from_healthcare);
+ DRAW_LINES_FOR_DATA(data.expenses_from_repairs);
+ DRAW_LINES_FOR_DATA(data.expenses_from_fuel);
+ DRAW_LINES_FOR_DATA(data.expenses_from_employees);
+ DRAW_LINES_FOR_DATA(data.expenses_from_trucks);
+ // ADD NEW ENTRY HERE
+ DRAW_LINES_FOR_DATA(data.total_income);
+ DRAW_LINES_FOR_DATA(data.total_expenses);
+ DRAW_LINES_FOR_DATA(data.total_profit);
+ }
+
+ if (!collection) {
+ char* txtbuf = invalid_location ? "Invalid location" : "No data for time period";
+ s32 textw = renderer->calculate_text_width(fnt_big, txtbuf);
+ s32 textx = x + (width_per_item*9) - (textw/2);
+ s32 texty = y + (h/2)-(fnt_big->px_h/2);
+ renderer->render_text(fnt_big, textx, texty, txtbuf, COLOR_TEXT);
+ }
+}
+
+static void world_map_draw_insights(platform_window* window)
+{
+ s32 w = area.w*0.9;
+ s32 h = area.h*0.7;
+ s32 x = area.x + area.w*0.05;
+ s32 y = area.y + area.w*0.05;
+ s32 w_orig = w;
+ s32 h_orig = h;
+ s32 x_orig = x;
+ s32 y_orig = y;
+ panel_render(scale, x, y, w, h);
+
+ #define GRID_ROWS ((sizeof(money_data)/sizeof(float))+2)
+ #define GRID_COLS (MONTHS_IN_YEAR+3)
+
+ s32 button_row_h = 44*scale;
+ s32 btn_size = 34*scale;
+ s32 spacing = 5*scale;
+
+ s32 pad = 40*scale;
+ s32 halfpad = pad/2;
+ s32 textpad = 20*scale;
+
+ w -= pad*2;
+ h -= pad*2;
+
+ h -= button_row_h+spacing;
+
+ s32 width_per_item = (w/GRID_COLS);
+ s32 height_per_item = (h/GRID_ROWS);
+ s32 new_w = width_per_item*GRID_COLS;
+ s32 new_h = height_per_item*GRID_ROWS;
+ s32 off_x = w - new_w;
+ s32 off_y = h - new_h;
+ w = new_w;
+ h = new_h;
+
+ s32 panel_w = w+(halfpad*2);
+
+ enum insights_panel_format
+ {
+ CHART,
+ GRID,
+ };
+ static enum insights_panel_format current_format = GRID;
+ static world_location* active_world_location_filter = 0;
+
+ {
+ s32 btn_row_x = x + off_x/2+halfpad;
+ s32 btn_row_y = y + off_y/2+halfpad;
+
+ s32 button_pad = (button_row_h - btn_size)/2;
+ s32 btn_start_x = btn_row_x + panel_w - (4*scale);
+ s32 btn_left_start_x = btn_row_x+(4*scale)+button_pad;
+ s32 year_w = (80*scale);
+ s32 year_text_w = year_w+(button_pad*2);
+ s32 btn_y = btn_row_y + button_pad;
+
+ // background
+ button_render(scale, BUTTON_STATIC, 0, btn_row_x, btn_row_y,panel_w, button_row_h);
+
+ // Buttons right
+ if (push_info_panel_button(scale, img_graph, btn_start_x - ((btn_size + button_pad)*1), btn_y, btn_size, current_format!=CHART, false)) (current_format = CHART);
+ if (push_info_panel_button(scale, img_grid, btn_start_x - ((btn_size + button_pad)*2), btn_y, btn_size, current_format!=GRID, false)) (current_format = GRID);
+
+ font* fnt = fnt_rd24;
+ s32 current_year = 1900+_active_world->start_year+insights_selected_year_index;
+
+ // Buttons left
+ button_render(scale, BUTTON_STATIC, 0, btn_left_start_x+btn_size+button_pad, btn_y,year_w, btn_size);
+ char buf[10];
+ sprintf(buf, "%d", current_year);
+ s32 textw = renderer->calculate_text_width(fnt,buf);
+ renderer->render_text(fnt,btn_left_start_x+(btn_size)+(year_text_w/2)-(textw/2), btn_y+(btn_size/2)-(fnt->px_h/2), buf, COLOR_TEXT);
+
+ s32 btn_right_x = btn_left_start_x + (btn_size) + year_text_w;
+ if (push_info_panel_button(scale, img_arrow_left, btn_left_start_x, btn_y, btn_size, insights_selected_year_index>=1, false)) (insights_selected_year_index--);
+ if (push_info_panel_button(scale, img_arrow_right, btn_right_x, btn_y,
+ btn_size, insights_selected_year_index<_active_world->insights.length-1, false)) (insights_selected_year_index++);
+
+ // Location selector
+ s32 tb_filter_x = btn_right_x + btn_size + button_pad;
+ s32 tb_width = 520*scale;
+ active_world_location_filter = location_selector_render(window, scale, true, active_world_location_filter, tb_filter_x, btn_y, tb_width, btn_size);
+
+ // Clear button
+ s32 clear_btn_x = tb_filter_x + tb_width + button_pad;
+ if (push_info_panel_button(scale, img_globe, clear_btn_x, btn_y, btn_size, _global_keyboard.input_text_len, false)) {
+ active_world_location_filter = 0;
+ keyboard_set_input_text("");
+ }
+ }
+
+ x+=off_x/2+pad;
+ y+=off_y/2+pad+button_row_h+spacing;
+
+ button_render(scale, BUTTON_STATIC, 0, x-halfpad,y-halfpad,panel_w,h+(halfpad*2));
+
+ static money_data_collection* prev_collection = 0;
+ money_data_collection* collection = get_current_insights_data(_active_world); // Get current year page, also a hack to make sure a new page exists at year switch.
+ if (!prev_collection || collection != prev_collection) {
+ prev_collection = collection;
+ insights_selected_year_index = _active_world->insights.length-1;
+ }
+
+ money_data_collection* collection_to_use = array_at(&_active_world->insights, insights_selected_year_index); // Get page to use
+ if (active_world_location_filter) {
+ if (active_world_location_filter->is_owned) {
+ s32 index_of_filter_page = insights_selected_year_index;
+ s32 purchase_year_diff = active_world_location_filter->purchase_year - _active_world->start_year;
+ index_of_filter_page -= purchase_year_diff;
+ if (index_of_filter_page < 0) collection_to_use = 0;
+ else if (index_of_filter_page > active_world_location_filter->insights.length-1) collection_to_use = 0;
+ else collection_to_use = array_at(&active_world_location_filter->insights, index_of_filter_page);
+ }
+ else {
+ collection_to_use = 0;
+ }
+ }
+
+ bool is_typing_in_filter_tb = (!active_world_location_filter && _global_keyboard.input_text_len);
+ if (is_typing_in_filter_tb) collection_to_use = 0;
+
+ if (current_format == GRID) _insights_draw_grid(scale, is_typing_in_filter_tb, collection_to_use, GRID_ROWS, GRID_COLS, textpad, x, y, w, h, width_per_item, height_per_item);
+ if (current_format == CHART) _insights_draw_chart(window, is_typing_in_filter_tb, scale, collection_to_use, GRID_ROWS, GRID_COLS, textpad, x, y, w, h, width_per_item, height_per_item);
+
+ if (mouse_interacts(x_orig, y_orig, w_orig, h_orig)) {
+ reset_left_click();
+ } else if (is_left_clicked()) {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+}
+
+static void world_map_draw_event_log(platform_window* window)
+{
+ _active_world->log.has_unread_messages = false;
+
+ font* fnt = fnt_rd16;
+
+ s32 panel_h = area.h*0.9f;
+ s32 panel_pad = area.h*0.05f;
+
+ s32 panel_w = area.w/3.5f;
+
+ s32 panel_x = area.x + panel_pad;
+ s32 panel_y = area.y + panel_pad;
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ float text_pad = panel_w*0.05f;
+
+ s32 text_y = panel_y + text_pad;
+ s32 text_x = panel_x + text_pad;
+ s32 text_w = panel_w - (text_pad*2);
+
+ renderer->render_set_scissor(window, text_x, text_y, panel_w, panel_h-(text_pad*2));
+
+ if (_active_world->log.events.length) {
+ s32 read_cursor = _active_world->log.write_cursor;
+ for (s32 i = 0; i < _active_world->log.events.length; i++) {
+ read_cursor--;
+ if (read_cursor < 0) read_cursor = _active_world->log.events.length-1;
+
+ event* e = array_at(&_active_world->log.events, read_cursor);
+
+ float inner_pad = 5*scale;
+
+
+ s32 texth = renderer->render_text_cutoff(fnt, text_x+inner_pad, text_y+inner_pad, e->message, COLOR_TEXT, text_w-(inner_pad*2));
+ s32 highlight_w = text_w;
+ s32 highlight_h = texth+(inner_pad);
+
+ if (mouse_interacts(text_x, text_y, highlight_w, highlight_h)) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ renderer->render_rectangle(text_x, text_y, text_w, highlight_h, rgba(255,255,255,20));
+
+ if (is_left_clicked()) {
+ switch (e->type)
+ {
+ case EVENT_TYPE_MISSED_SHIPMENT_NO_TRUCK:
+ place_detail_show_employee_detail((employee*)e->data);
+ break;
+ case EVENT_TYPE_MISSED_SHIPMENT_NO_ASSIGNEE:
+ case EVENT_TYPE_MISSED_SHIPMENT_NOT_AT_LOCATION: {
+ scheduled_job* job = (scheduled_job*)e->data;
+ place_detail_show_schedule_with_highlighted_job(job->location, job, e->job_time);
+ } break;
+ case EVENT_TYPE_EMPLOYEE_QUIT:
+ place_detail_show_schedule_with_highlighted_job((world_location*)e->data, 0, e->job_time);
+ break;
+
+ default:
+ log_assert(0, "Invalid event type.");
+ break;
+ }
+ }
+ }
+
+ text_y += highlight_h;
+ if (text_y > panel_y + panel_h) break;
+ }
+ }
+ else {
+ char* buf = "No events.";
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ renderer->render_text_cutoff(fnt, text_x + (text_w/2)-(tw/2), text_y, "No events.", COLOR_TEXT, text_w);
+ }
+
+ renderer->render_reset_scissor(window);
+
+ if (mouse_interacts(panel_x, panel_y, panel_w, panel_h)) {
+ reset_left_click();
+ } else if (is_left_clicked()) {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+}
+
+s32 hovered_investment_panel_item_index = -1;
+static s32 world_map_push_invest_panel_item(s32 x, s32 y, s32 w, s32 index, char* text, s32* fval)
+{
+ s32 pad = 40*scale;
+ s32 halfpad = pad/2;
+ s32 panel_w = w-(pad);
+ float item_pad = 30*scale;
+ float item_spacing = 5*scale;
+ float item_halfpad = item_pad/2;
+
+ font* fnt = fnt_rd24;
+ char value_str[30];
+ sprintf(value_str, "$%d", *fval);
+ float item_h = fnt->px_h+item_pad;
+ float item_x = x+halfpad;
+ float item_y = y+halfpad+(index*(item_h+item_spacing));
+ float item_w = panel_w;
+ float content_x = item_x+item_halfpad;
+ float content_y = item_y+item_halfpad;
+ float total_val_editor_w = item_w*0.3f;
+ float button_left_x = item_x + item_w - total_val_editor_w - item_halfpad;
+ float btn_size = fnt->px_h*2;
+ float btn_y = item_y + ((item_h-btn_size)/2);
+ button_render(scale, BUTTON_STATIC, 0, item_x, item_y,item_w,item_h);
+ renderer->render_text(fnt, content_x, content_y, text, COLOR_TEXT);
+ // Button decrease simulation speed
+ if (push_info_panel_button(scale, img_arrow_left, button_left_x, btn_y, btn_size, *fval > 0, false)) {
+ *fval -= 100.0f;
+ }
+ // Button increase simulation speed
+ if (push_info_panel_button(scale, img_arrow_right, button_left_x+total_val_editor_w-btn_size, btn_y, btn_size, true, false)) {
+ *fval += 100.0f;
+ }
+ s32 item_text_w = renderer->calculate_text_width(fnt, value_str);
+ s32 item_text_x = button_left_x + (total_val_editor_w/2) - (item_text_w/2);
+ renderer->render_text(fnt, item_text_x, content_y, value_str, COLOR_TEXT);
+
+ if (mouse_interacts_peak(item_x, item_y, item_w, item_h)) {
+ hovered_investment_panel_item_index = index;
+ }
+
+ return item_y + item_h;
+}
+
+static void world_map_draw_invest_panel(platform_window* window)
+{
+ s32 w = area.w*0.5;
+ s32 h = area.h*0.7;
+ s32 x = area.x + area.w*0.25;
+ s32 y = area.y + area.w*0.05;
+ panel_render(scale, x, y, w, h);
+
+ s32 pad = 40*scale;
+ s32 halfpad = pad/2;
+ s32 panel_w = w-(pad);
+
+ #define TOTAL_INVEST_ITEM_COUNT (5)
+
+ hovered_investment_panel_item_index = -1;
+
+ world_map_push_invest_panel_item(x, y, w, 0, "Workspace safety", (s32*)(&_active_world->investments.safety));
+ world_map_push_invest_panel_item(x, y, w, 1, "Marketing", (s32*)(&_active_world->investments.marketing));
+ world_map_push_invest_panel_item(x, y, w, 2, "Human resources", (s32*)(&_active_world->investments.human_resources));
+ world_map_push_invest_panel_item(x, y, w, 3, "Employee training", (s32*)(&_active_world->investments.training));
+ s32 item_bottom = world_map_push_invest_panel_item(x, y, w, 4, "Legal department", (s32*)(&_active_world->investments.legal));
+
+ float detail_panel_y = item_bottom + halfpad;
+ float detail_panel_h = h - (detail_panel_y-y)-halfpad;
+
+ button_render(scale, BUTTON_STATIC, 0, x+halfpad, detail_panel_y,panel_w,detail_panel_h);
+
+ s32 info_text_pad = 20*scale;
+
+ char* info_text = 0;
+ switch (hovered_investment_panel_item_index)
+ {
+ case 0: info_text = "Increasing the budget for workspace safety will ensure employees receive the proper workspace safety training.";
+ break;
+ case 1: info_text = "Increasing the marketing budget will give your business more publicity and will secure more work proposals.";
+ break;
+ case 2: info_text = "Investing in human resources will guarantee more responses to vacancies.";
+ break;
+ case 3: info_text = "Providing training for your employees will increase happiness for your employees and make them work more efficiently.";
+ break;
+ case 4: info_text = "The legal department is essential for settling legal disputes.";
+ break;
+ }
+
+ if (info_text)
+ renderer->render_text_cutoff(fnt_rd24, x+halfpad+info_text_pad, detail_panel_y+info_text_pad, info_text, COLOR_TEXT, panel_w - (info_text_pad*2));
+
+ if (mouse_interacts(x,y,w,h)) {
+ reset_left_click();
+ } else if (is_left_clicked()) {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+}
+
+static void world_map_draw_purchase_location_panel(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+
+ float vertical_pad = 20 * scale;
+
+ s32 panel_h = 160 * scale;
+ s32 panel_w = 280 * scale;
+
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // info text
+ {
+ font* font_title = FONT_REGULAR(SIZE_RD(area.w, 32));
+ {
+ char* title = scene_data.location_to_purchase->name;
+ s32 text_w = renderer->calculate_text_width(font_title, title);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = panel_y + (vertical_pad);
+ renderer->render_text(font_title, text_x+2, text_y+2, title, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_title, text_x, text_y, title, COLOR_TEXT);
+ }
+ {
+ char buf[100];
+ sprintf(buf, "Purchase a garage for $%.0f?", world_location_get_price(scene_data.location_to_purchase));
+ char* text = buf;
+ font* font_info = FONT_REGULAR(SIZE_RD(area.w, 20));
+ s32 text_w = renderer->calculate_text_width(font_info, text);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = panel_y + vertical_pad*1.5+font_title->px_h;
+ renderer->render_text(font_info, text_x+2, text_y+2, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_info, text_x, text_y, text, COLOR_TEXT);
+ }
+ }
+
+ s32 button_w = 178 * scale;
+ s32 button_h = 37 * scale;
+ if (button_render(scale, true, "Purchase", screen_center_x - (button_w/2), panel_y + panel_h - button_h - vertical_pad, button_w, button_h))
+ {
+ // Mark as owned.
+ scene_data.location_to_purchase->is_owned = true;
+ scene_data.location_to_purchase->purchase_year = _active_world->current_time.tm_year;
+
+ // Make sure insights are ready to display.
+ money_data_collection* collection = get_current_insights_data_for_location(_active_world, scene_data.location_to_purchase);
+ collection->months[_active_world->current_time.tm_mon].total_income = 0;
+
+ _active_world->money -= world_location_get_price(scene_data.location_to_purchase);
+
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+
+ button_w = 30 * scale;
+ if (button_render(scale, true, "X", panel_x+panel_w-button_w, panel_y+2, button_w, button_w))
+ {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ } else if (is_left_clicked()) {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+}
+
+static void world_map_draw_viewing_job(platform_window* window)
+{
+ active_job* job = get_active_job_by_ref(_active_world, currently_viewing_active_job);
+ if (!job) {
+ currently_viewing_active_job.offerid = INVALID_ID;
+ return;
+ }
+
+ s32 panel_offset_from_job = area.h*0.1f;
+ s32 panel_h = area.h*0.32f;
+ s32 panel_w = area.w*0.15f;
+
+ s32 panel_x = job->px_pos.x;
+ s32 panel_y = job->px_pos.y;
+
+ if (job->px_pos.y > area.y + (area.h/2)) {
+ panel_y -= panel_h - panel_offset_from_job;
+
+ renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3), panel_y+panel_h-5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION);
+ renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3*2), panel_y+panel_h-5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION);
+ }
+ else {
+ panel_y += panel_offset_from_job;
+
+ renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3), panel_y+5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION);
+ renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3*2), panel_y+5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION);
+ }
+
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ s32 panel_pad = 10*scale;
+ s32 truck_img_x = panel_x + panel_pad;
+ s32 truck_img_y = panel_y + panel_pad;
+ s32 truck_img_s = panel_w * 0.6f;
+
+ s32 portrait_s = truck_img_s / 2;
+
+ renderer->render_image(job->assigned_truck.logo, truck_img_x+(panel_pad), truck_img_y, truck_img_s, truck_img_s);
+ draw_employee_portrait(&job->assignee, truck_img_x+(panel_pad) + truck_img_s - (portrait_s/3), truck_img_y + (truck_img_s / 3), portrait_s, portrait_s);
+
+ {
+ s32 text_x = truck_img_x;
+ float text_pad = (5*scale);
+ s32 text_y = truck_img_y + truck_img_s + panel_pad;
+ font* fnt = fnt_rd16;
+ font* fnt_s = fnt_rd12;
+ renderer->render_text(fnt,text_x,text_y,job->assignee.name,COLOR_TEXT);
+ text_y += fnt->px_h + text_pad;
+
+ // Name + origin
+ {
+ world_location* origin = get_world_location_by_id(_active_world, job->assignee.original_location_id);
+ char buf[100];
+ sprintf(buf, "Works at %s", origin->name);
+ renderer->render_text(fnt_s,text_x,text_y,buf,COLOR_TEXT);
+ text_y += fnt_s->px_h + text_pad;
+ }
+
+ // Job info
+ {
+ text_y += (20*scale);
+
+ char daybuf[10];
+ switch(job->day) {
+ case 1: strcpy(daybuf, "Mon"); break;
+ case 2: strcpy(daybuf, "Tue"); break;
+ case 3: strcpy(daybuf, "Wed"); break;
+ case 4: strcpy(daybuf, "Thu"); break;
+ case 5: strcpy(daybuf, "Fri"); break;
+ case 6: strcpy(daybuf, "Sat"); break;
+ case 0: strcpy(daybuf, "Sun"); break;
+ }
+
+ char buf[100];
+ sprintf(buf, "Left on %s %02d:%02d", daybuf, WORK_HOUR_START + (job->timeslot/TIME_SLOTS_PER_HOUR), job->timeslot%TIME_SLOTS_PER_HOUR);
+ renderer->render_text(fnt_s,text_x,text_y,buf,COLOR_TEXT);
+ text_y += fnt_s->px_h + text_pad;
+ }
+
+ // Job status
+ if (!job->reversed)
+ {
+ job_endpoints endpoints = job_offer_get_endpoints(&job->offer);
+ char buf[100];
+ sprintf(buf, "Shipping %s to %s", job->offer.product->name, endpoints.dest->name);
+ text_y += renderer->render_text_cutoff(fnt_s,text_x,text_y,buf,COLOR_TEXT, panel_w - (panel_pad*2));
+ text_y += text_pad;
+ }
+ else {
+ world_location* source = *(world_location**)array_at(&job->offer.connections, 0); // Get source location
+ char buf[100];
+ sprintf(buf, "Returning to %s", source->name);
+ renderer->render_text_cutoff(fnt_s,text_x,text_y,buf,COLOR_TEXT, panel_w - (panel_pad*2));
+ text_y += fnt_s->px_h + text_pad;
+ }
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ } else if (is_left_clicked()) {
+ currently_viewing_active_job.offerid = INVALID_ID;
+ }
+}
+
+static void world_handle_scroll(platform_window* window)
+{
+ static float target_zoom = 1.0f;
+ if (global_ui_context.mouse->scroll_state == SCROLL_UP)
+ {
+ if (target_zoom < zoom) target_zoom = zoom;
+ target_zoom+=0.1f;
+ }
+ if (global_ui_context.mouse->scroll_state == SCROLL_DOWN)
+ {
+ if (target_zoom > zoom) target_zoom = zoom;
+ target_zoom-=0.1f;
+ }
+
+ // Keep camera position
+ if (target_zoom != zoom) {
+ vec4 area = camera_get_target_rectangle(window);
+ int orig_w = area.w * zoom;
+ int orig_h = area.h * zoom;
+ int new_w = area.w * target_zoom;
+ int new_h = area.h * target_zoom;
+
+ float errorw = new_w - orig_w;
+ float errorh = new_h - orig_h;
+ camera_x -= errorw / 25.0f;
+ camera_y -= errorh / 40.0f;
+ }
+
+ // Smooth scrolling
+ if (target_zoom != zoom)
+ {
+ float error = target_zoom - zoom;
+ zoom += error / 10;
+ }
+
+ if (zoom < 1.0f) zoom = 1.0f;
+ if (zoom > 5.0f) zoom = 5.0f;
+
+ if (camera_x > 0.0f) camera_x = 0.0f;
+ if (camera_y > 0.0f) camera_y = 0.0f;
+
+ //if (is_left_down_peak())
+ {
+
+ }
+}
+
+void world_map_scene_render(platform_window* window)
+{
+ renderer->set_render_depth(5);
+
+ world_handle_scroll(window);
+
+ world_map_draw_info_panel(window, true);
+
+ renderer->set_render_depth(4);
+ switch (scene_state)
+ {
+ case WORLD_SCENE_STATE_INSIGHTS:
+ world_map_draw_insights(window);
+ break;
+ case WORLD_SCENE_STATE_LOG:
+ world_map_draw_event_log(window);
+ break;
+ case WORLD_SCENE_STATE_IDLE: break;
+ case WORLD_SCENE_STATE_PURCHASE_LOCATION:
+ world_map_draw_purchase_location_panel(window);
+ break;
+ case WORLD_SCENE_STATE_INVEST:
+ world_map_draw_invest_panel(window);
+ break;
+ }
+
+ renderer->set_render_depth(3);
+ if (currently_viewing_active_job.offerid != INVALID_ID) world_map_draw_viewing_job(window);
+
+ if (_active_world) {
+ world_update_result click_result = world_render(window, _active_world);
+
+ if (click_result.clicked_location) {
+ if (click_result.clicked_location->is_owned) {
+ place_detail_set_active_location(click_result.clicked_location);
+ game_set_active_scene(GAME_STATE_PLACE_DETAIL);
+ }
+ else {
+ scene_data.location_to_purchase = click_result.clicked_location;
+ scene_state = WORLD_SCENE_STATE_PURCHASE_LOCATION;
+ }
+ }
+ else if (click_result.clicked_job) {
+ currently_viewing_active_job = (active_job_ref){click_result.clicked_job->day, click_result.clicked_job->timeslot, click_result.clicked_job->offer.id};
+ }
+ }
+
+ renderer->set_render_depth(0);
+
+ vec4 area = camera_get_target_rectangle(window);
+ renderer->render_rectangle(area.x, area.y, area.w, area.h, COLOR_WORLD_MAP_BACKGROUND);
+ renderer->render_image(img_world_map, area.x + camera_x, area.y + camera_y, area.w*zoom, area.h*zoom);
+}
+
+void world_map_scene_update(platform_window* window)
+{
+ world_update(window, _active_world);
+ if (keyboard_is_key_pressed(KEY_ESCAPE)) {
+ scene_state = WORLD_SCENE_STATE_IDLE;
+ }
+}
+
+void world_map_scene_destroy()
+{
+
+}
\ No newline at end of file diff --git a/src/tooltip.c b/src/tooltip.c new file mode 100644 index 0000000..5098ba7 --- /dev/null +++ b/src/tooltip.c @@ -0,0 +1,22 @@ +#define TOOLTIP_PAD (scale*14)
+
+void show_tooltip(s32 x, s32 y, char* buf) {
+ tooltop_visible = true;
+ string_copyn(tooltip_buffer, buf, 100);
+ tooltip_x = x+(20*scale);
+ tooltip_y = y-(fnt_rd16->px_h + (TOOLTIP_PAD))/2;
+}
+
+void update_render_tooltip() {
+ if (!tooltop_visible) return;
+ s32 current_render_depth = gl_render_depth;
+ renderer->set_render_depth(10);
+
+ s32 info_w = renderer->calculate_text_width(fnt_rd16, tooltip_buffer) + (TOOLTIP_PAD);
+ s32 info_h = fnt_rd16->px_h + (TOOLTIP_PAD);
+ button_draw_background(scale, tooltip_x, tooltip_y, info_w, info_h, COLOR_WHITE, COLOR_BUTTON);
+ renderer->render_text(fnt_rd16, tooltip_x+(TOOLTIP_PAD/2), tooltip_y+(TOOLTIP_PAD/2), tooltip_buffer, COLOR_TEXT);
+
+ renderer->set_render_depth(current_render_depth);
+ tooltop_visible = false;
+}
diff --git a/src/ui/animation.c b/src/ui/animation.c new file mode 100644 index 0000000..62775bf --- /dev/null +++ b/src/ui/animation.c @@ -0,0 +1,18 @@ +animation animation_create(s32 duration)
+{
+ animation an;
+ an.time = 0;
+ an.started = false;
+ an.duration = duration;
+ an.percentage = 0.0f;
+ return an;
+}
+
+float animation_update(animation* an)
+{
+ if (!an->started) return an->percentage;
+ an->time += frame_delta*1000.0f;
+ if (an->time > an->duration) an->time = an->duration;
+ an->percentage = an->time/an->duration;
+ return an->percentage;
+}
\ No newline at end of file diff --git a/src/ui/button.c b/src/ui/button.c new file mode 100644 index 0000000..773fb7b --- /dev/null +++ b/src/ui/button.c @@ -0,0 +1,101 @@ +bool button_draw_background_percentage(float scale, s32 x, s32 y, s32 w, s32 h, color tint, color fill, float percentage, color bar_fill)
+{
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image_tint(img_button_topleft, x, y, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_top, x + cornor_size, y, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_topright, x + cornor_size + top_width, y, cornor_size, cornor_size, tint);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), fill);
+ renderer->render_rectangle(x+pad, y+pad, (w-(pad*2))*percentage, h-(pad*2), bar_fill);
+
+ return _global_mouse.x >= x && _global_mouse.x <= x + w && _global_mouse.y >= y && _global_mouse.y <= y + h;
+}
+
+bool button_draw_background(float scale, s32 x, s32 y, s32 w, s32 h, color tint, color fill)
+{
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image_tint(img_button_topleft, x, y, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_top, x + cornor_size, y, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_topright, x + cornor_size + top_width, y, cornor_size, cornor_size, tint);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), fill);
+
+ return _global_mouse.x >= x && _global_mouse.x <= x + w && _global_mouse.y >= y && _global_mouse.y <= y + h;
+}
+
+bool button_render(float scale, button_type enabled, char* text, s32 x, s32 y, s32 w, s32 h)
+{
+ bool result = false;
+
+ color tint = COLOR_WHITE;
+ color fill = COLOR_BUTTON;
+
+ if (enabled == BUTTON_ENABLED || enabled == BUTTON_HIGHLIGHTED) {
+ if (mouse_interacts(x,y,w,h)) {
+ platform_set_cursor(main_window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ result = true;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ tint = COLOR_BUTTON_ACTIVE_TINT;
+ fill = COLOR_BUTTON_ACTIVE;
+ }
+
+ if (enabled == BUTTON_HIGHLIGHTED) {
+ tint = COLOR_BUTTON_HIGHLIGHTED_TINT;
+ fill = COLOR_BUTTON_HIGHLIGHTED_ACTIVE;
+ }
+ }
+ else if (enabled == BUTTON_DISABLED) {
+ tint = COLOR_BUTTON_DISABLED_TINT;
+ fill = COLOR_BUTTON_DISABLED;
+ }
+
+ button_draw_background(scale,x,y,w,h,tint,fill);
+
+ // text
+ if (text) {
+ font* font_sml = fnt_rd24;
+ s32 text_y = y + (h/2) - (font_sml->px_h/2);
+ s32 game_title_width = renderer->calculate_text_width(font_sml, text);
+ s32 text_x = x + (w/2) - (game_title_width/2);
+
+ renderer->render_text(font_sml, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_sml, text_x, text_y, text, COLOR_TEXT);
+ }
+ return result;
+}
\ No newline at end of file diff --git a/src/ui/panel.c b/src/ui/panel.c new file mode 100644 index 0000000..af24e66 --- /dev/null +++ b/src/ui/panel.c @@ -0,0 +1,29 @@ +
+void panel_render(float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ s32 cornor_size = img_panel_topleft->width*(scale/2);
+ log_assert(w > cornor_size*2, "Panel width too small");
+ log_assert(h > cornor_size*2, "Panel height too small");
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image(img_panel_topleft, x, y, cornor_size, cornor_size);
+ renderer->render_image(img_panel_top, x + cornor_size, y, top_width, cornor_size);
+ renderer->render_image(img_panel_topright, x + cornor_size + top_width, y, cornor_size, cornor_size);
+
+ // left
+ renderer->render_image(img_panel_left, x, y + cornor_size-1, cornor_size, size_height+2);
+
+ // right
+ renderer->render_image(img_panel_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2);
+
+ // bottom
+ renderer->render_image(img_panel_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size);
+ renderer->render_image(img_panel_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size);
+ renderer->render_image(img_panel_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), COLOR_PANEL_BACKGROUND);
+}
\ No newline at end of file diff --git a/src/ui/portrait.c b/src/ui/portrait.c new file mode 100644 index 0000000..09301fe --- /dev/null +++ b/src/ui/portrait.c @@ -0,0 +1,21 @@ +void draw_employee_portrait(employee* emp, float x, float y, float w, float h)
+{
+ float body_s = h*0.8f;
+ float body_x = x + (w/2)-(body_s/2);
+ float body_y = y+h-body_s;
+
+ float head_s = h*0.45f;
+ float head_x = x + (w/2)-(head_s/2);
+ float head_y = y+(h*0.11f);
+
+ float hair_s = h*0.6f;
+ float hair_x = x + (w/2)-(hair_s/2);
+ float hair_y = y;
+
+ //renderer->render_image(img_portrait, x,y,w,h);
+
+ renderer->render_image_tint(img_portrait_head, head_x, head_y, head_s, head_s, emp->face_color);
+ renderer->render_image_tint(img_portrait_body, body_x, body_y, body_s, body_s, emp->body_color);
+ renderer->render_image_tint(img_portrait_hair[emp->portrait_hair_type], hair_x, hair_y, hair_s, hair_s, emp->hair_color);
+
+}
\ No newline at end of file diff --git a/src/ui/selectors.c b/src/ui/selectors.c new file mode 100644 index 0000000..dc5a6bc --- /dev/null +++ b/src/ui/selectors.c @@ -0,0 +1,212 @@ +
+employee* employee_selector_render(platform_window* window, float scale, bool enabled, employee* current_val, s32 x, s32 y, s32 w, s32 h, animation an, scheduled_job* offer) {
+ #define ANIMATION_OFFSET (-30*scale)
+ color text_color = AN_LI_TINT(COLOR_TEXT, an);
+ color c_tb_tint = AN_LI_TINT(COLOR_TEXTBOX_TINT, an);
+ color c_tb_fill = AN_LI_TINT(COLOR_TEXTBOX_FILL, an);
+ color c_white = AN_LI_TINT(COLOR_WHITE, an);
+ color c_correct = AN_LI_TINT(COLOR_CORRECT, an);
+ color c_wrong = AN_LI_TINT(COLOR_WRONG, an);
+ color c_btn = AN_LI_TINT(COLOR_BUTTON, an);
+
+ employee* result = current_val;
+
+ s32 tb_pad = 20*scale;
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ s32 tb_width = 220*scale;
+ s32 tb_height = h-(tb_pad*2);
+ s32 tb_y = y+tb_pad;
+ s32 tb_x = x+tb_pad + (ANIMATION_OFFSET - (ANIMATION_OFFSET*an.percentage));
+
+ {
+ // Start taking input on click.
+ if (button_draw_background(scale, tb_x,tb_y,tb_width,tb_height, c_tb_tint, c_tb_fill) && enabled) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ _global_keyboard.take_input = true;
+ _global_keyboard.input_mode = INPUT_NUMERIC;
+ }
+ }
+ // Clear on outside click or enter.
+ else if (is_left_clicked_peak()) {
+ _global_keyboard.take_input = false;
+ }
+ if (keyboard_is_key_pressed(KEY_ENTER)) {
+ _global_keyboard.take_input = false;
+ }
+
+ bool is_editing = _global_keyboard.take_input;
+
+ // Limit input length
+ if (is_editing) {
+ if (_global_keyboard.input_text_len > MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR)
+ {
+ _global_keyboard.input_text_len = MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR;
+ _global_keyboard.cursor = MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR;
+ _global_keyboard.input_text[MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR] = 0;
+ }
+
+ {
+ // Activation underline.
+ s32 linew = tb_width*0.95f;
+ s32 offsetw = (tb_width - linew)/2;
+ renderer->render_rectangle(tb_x+offsetw, tb_y+tb_height - 6, linew, 2, COLOR_SELECTOR_UNDERLINE);
+ }
+ }
+
+ font* fnt_big = fnt_rd32;
+ s32 textx = tb_x+(10*scale);
+ s32 texty = tb_y+(tb_height/2)-(fnt_big->px_h/2);
+
+ u32 text_id = string_to_u32(_global_keyboard.input_text);
+ employee* emp = is_editing ? get_global_employee_by_id(_active_world, text_id) : current_val;
+
+ if (is_editing || emp || _global_keyboard.input_text_len) // Editing, employee is selected, or player is typing.
+ {
+ s32 cursorh = tb_height*0.6f;
+
+ // Either display keyboard input or selected employee.
+ char idbuf[20];
+ if (is_editing || !emp) sprintf(idbuf, "ID: %s", _global_keyboard.input_text);
+ else if (emp) sprintf(idbuf, "ID: %d", emp->id);
+
+ s32 textw = renderer->render_text(fnt_big, textx, texty, idbuf, text_color);
+ if (is_editing) renderer->render_rectangle(textx+textw, tb_y+(tb_height/2)-(cursorh/2), 3, cursorh, text_color);
+ result = emp;
+ }
+ else if (!is_editing && !emp) { // Not editing and no employee selected.
+ renderer->render_text(fnt_big, textx, texty, "Search by ID..", text_color);
+ }
+
+ s32 status_s = tb_height/2;
+ s32 status_x = tb_x + tb_width - (status_s/4*3);
+ s32 status_y = tb_y - (status_s/4);
+ button_draw_background(scale,status_x,status_y,status_s,status_s,c_white,c_btn);
+ s32 status_icon_s = status_s*0.5f;
+ s32 status_icon_offset = (status_s - status_icon_s)/2;
+ renderer->render_image_tint(result ? img_checkmark : img_questionmark,
+ status_x+status_icon_offset, status_y+status_icon_offset, status_icon_s, status_icon_s, result ? c_correct : c_wrong);
+ }
+
+ // Draw employee data
+ if (result) {
+ s32 por_x = tb_x + tb_width + tb_pad;
+ draw_employee_portrait(result, por_x, tb_y, tb_height, tb_height);
+
+ s32 text_x = por_x + tb_height + tb_pad;
+ font* fnt = fnt_rd24;
+ font* fnt_s = fnt_rd20;
+ renderer->render_text(fnt,text_x,tb_y,result->name,text_color);
+
+ tb_y += fnt->px_h + (5*scale);
+
+ {
+ world_location* origin = get_world_location_by_id(_active_world, result->original_location_id);
+ char buf[100];
+ sprintf(buf, "Works at %s", origin->name);
+ renderer->render_text(fnt_s,text_x,tb_y,buf,text_color);
+ tb_y += fnt->px_h + (12*scale);
+ }
+
+ float hours_for_this_job = (offer->offer.duration_sec_min * get_shiptime_factor(result)) / 3600.0f;
+ float total_hours = get_worked_hours_per_week_for_employee(_active_world, result, (_active_schedule_state == RESCHEDULING_JOB ? _active_selected_scheduled_job : 0));
+
+ // If being scheduled, also add timeslots that are currently being scheduled.
+ if (enabled) {
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ scheduled_job_time slot = offer->timeslots[i];
+ if (slot.assignee == result) {
+ total_hours += hours_for_this_job;
+ if (!slot.stay_at_destination) total_hours += hours_for_this_job;
+ }
+ }
+ }
+ bool overworked = (total_hours > MAX_WORKED_HOURS_WEEKLY);
+ total_hours = ceil(total_hours);
+
+ color c = COLOR_TEXT;
+ if (overworked) c = COLOR_TEXT_NEGATIVE;
+ char txt_status[50];
+ sprintf(txt_status, "Currently scheduled for %.0fh/week", total_hours);
+ renderer->render_text(fnt_s,text_x,tb_y,txt_status,c);
+ }
+
+ return result;
+ #undef ANIMATION_OFFSET
+}
+
+world_location* location_selector_render(platform_window* window, float scale, bool enabled, world_location* current_val, s32 x, s32 y, s32 w, s32 h)
+{
+ world_location* result = current_val;
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ s32 tb_width = w;
+ s32 tb_height = h;
+ s32 tb_y = y;
+ s32 tb_x = x;
+
+ {
+ // Start taking input on click.
+ if (button_draw_background(scale, tb_x,tb_y,tb_width,tb_height, COLOR_TEXTBOX_TINT, COLOR_TEXTBOX_FILL) && enabled) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ _global_keyboard.take_input = true;
+ _global_keyboard.input_mode = INPUT_FULL;
+ }
+ }
+ // Clear on outside click or enter.
+ else if (is_left_clicked_peak()) {
+ _global_keyboard.take_input = false;
+ }
+ if (keyboard_is_key_pressed(KEY_ENTER)) {
+ _global_keyboard.take_input = false;
+ }
+
+ bool is_editing = _global_keyboard.take_input;
+
+ // Limit input length
+ if (is_editing) {
+ if (_global_keyboard.input_text_len > MAX_WORLD_LOCATION_NAME_LENGTH)
+ {
+ _global_keyboard.input_text_len = MAX_WORLD_LOCATION_NAME_LENGTH;
+ _global_keyboard.cursor = MAX_WORLD_LOCATION_NAME_LENGTH;
+ _global_keyboard.input_text[MAX_WORLD_LOCATION_NAME_LENGTH] = 0;
+ }
+ }
+
+ font* fnt_big = fnt_rd32;
+ s32 textx = tb_x+(10*scale);
+ s32 texty = tb_y+(tb_height/2)-(fnt_big->px_h/2);
+
+ world_location* emp = is_editing ? get_world_location_by_name(_active_world, _global_keyboard.input_text) : current_val;
+
+ if (is_editing || emp || _global_keyboard.input_text_len) // Editing, employee is selected, or player is typing.
+ {
+ s32 cursorh = tb_height*0.6f;
+
+ // Either display keyboard input or selected employee.
+ char idbuf[50];
+ if (is_editing || !emp) sprintf(idbuf, "Name: %s", _global_keyboard.input_text);
+ else if (emp) sprintf(idbuf, "Name: %s", emp->name);
+
+ s32 textw = renderer->render_text(fnt_big, textx, texty, idbuf, COLOR_TEXT);
+ if (is_editing) renderer->render_rectangle(textx+textw, tb_y+(tb_height/2)-(cursorh/2), 3, cursorh, COLOR_TEXT);
+ result = emp;
+ }
+ else if (!is_editing && !emp) { // Not editing and no employee selected.
+ renderer->render_text(fnt_big, textx, texty, "Filter location..", COLOR_TEXT);
+ }
+
+ s32 status_s = tb_height/2;
+ s32 status_x = tb_x + tb_width - (status_s/4*3);
+ s32 status_y = tb_y - (status_s/4);
+ button_draw_background(scale,status_x,status_y,status_s,status_s,COLOR_WHITE,COLOR_BUTTON);
+ s32 status_icon_s = status_s*0.5f;
+ s32 status_icon_offset = (status_s - status_icon_s)/2;
+ renderer->render_image_tint(result ? img_checkmark : img_questionmark,
+ status_x+status_icon_offset, status_y+status_icon_offset, status_icon_s, status_icon_s, result ? COLOR_CORRECT : COLOR_WRONG);
+ }
+
+ return result;
+}
\ No newline at end of file diff --git a/src/world.c b/src/world.c new file mode 100644 index 0000000..fbb2ec2 --- /dev/null +++ b/src/world.c @@ -0,0 +1,1321 @@ +static void world_assign_new_job_offers(world* world);
+static double distance_between_location(world_location* location1, world_location* location2);
+static void world_payout_salaries(world* world);
+static void enable_insights_for_current_month(world* world);
+static vec2f get_world_location_for_job(platform_window* window, world* world, active_job* job);
+static employee* get_employee_by_id(world_location* location, u32 id);
+static void end_contract_with_employee(world* world, employee* emp);
+
+float dotsize = 5;
+
+static s32 get_random_number(s32 min, s32 max)
+{
+ log_assert(min < max, "Min cannot be larger than max");
+ // it is assumed srand has been initialized at world load.
+ return min + rand() % (max-min);
+}
+
+void world_report_event_ex(world* world, char* msg, event_type type, void* data, scheduled_job_time scheduled_time)
+{
+ event new_event;
+ new_event.data = data;
+ new_event.type = type;
+ new_event.job_time = scheduled_time;
+
+ char txt_buf[50];
+ struct tm* time = gmtime(&world->simulation_time);
+ strftime(txt_buf, 50, "%H:%M %d/%m/%Y", time);
+
+ snprintf(new_event.message, MAX_EVENT_MESSAGE_LENGTH, "[%s] %s", txt_buf, msg);
+
+ if (world->log.events.length < LOG_HISTORY_LENGTH) {
+ array_push(&world->log.events, &new_event);
+ world->log.write_cursor++;
+ world->log.has_unread_messages = true;
+ }
+ else {
+ if (world->log.write_cursor >= LOG_HISTORY_LENGTH) world->log.write_cursor = 0;
+ u16 write_location = world->log.write_cursor;
+ world->log.write_cursor++;
+
+ event* e = array_at(&world->log.events, write_location);
+ *e = new_event;
+ world->log.has_unread_messages = true;
+ }
+
+ audio_play_sound(snd_event, AUDIO_CHANNEL_SFX_2);
+}
+
+void world_report_event(world* world, char* msg, event_type type, void* data)
+{
+ world_report_event_ex(world, msg, type, data, (scheduled_job_time){0,0,0,0});
+}
+
+static job_endpoints job_offer_get_endpoints(job_offer* offer)
+{
+ world_location* source = *(world_location**)array_at(&offer->connections, 0);
+ world_location* dest = *(world_location**)array_at(&offer->connections, offer->connections.length-1);
+
+ return (job_endpoints){source,dest};
+}
+
+static s32 employee_calculate_happiness_stars(employee* emp)
+{
+ s32 stars = emp->happiness / 0.2f;
+ if (stars > 5) stars = 0;
+ return stars;
+}
+
+static world_location world_create_location(u8 size, double latitude, double longitude, char* name, bool is_owned)
+{
+ world_location location;
+ location.size = size;
+ location.latitude = latitude;
+ location.longitude = longitude;
+ string_copyn(location.name, name, MAX_WORLD_LOCATION_NAME_LENGTH);
+ location.is_owned = is_owned;
+ location.connections = array_create(sizeof(world_location*));
+
+ location.employees = array_create(sizeof(employee*));
+ array_reserve(&location.employees, MAX_EMPLOYEE_COUNT);
+
+ location.job_offers = array_create(sizeof(job_offer));
+ array_reserve(&location.job_offers, MAX_JOBOFFER_COUNT);
+
+ location.trucks = array_create(sizeof(truck));
+ array_reserve(&location.trucks, MAX_TRUCK_COUNT);
+
+ location.schedule.jobs = array_create(sizeof(scheduled_job));
+ array_reserve(&location.schedule.jobs, TIME_SLOTS_PER_DAY*NUM_DAYS);
+
+ location.insights = array_create(sizeof(money_data_collection));
+
+ location.resumes = array_create(sizeof(resume));
+ location.id = assets_hash_path(location.name);
+ location.reliability = 1.0f;
+
+ return location;
+}
+
+static void world_create_connections(world* world)
+{
+ const double max_distance = 2.5; // about 155km
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* source = array_at(&world->locations, i);
+ for (s32 d = 0; d < world->locations.length; d++)
+ {
+ world_location* destination = array_at(&world->locations, d);
+ if (destination == source) continue;
+
+ if (fabs(source->latitude - destination->latitude) < max_distance ||
+ fabs(source->longitude - destination->longitude) < max_distance) {
+ array_push(&source->connections, &destination);
+ }
+ }
+ }
+}
+
+world_location* get_world_location_by_id(world* world, s32 id)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* source = array_at(&world->locations, i);
+ if (source->id == id) return source;
+ }
+ return 0;
+}
+
+world_location* get_world_location_by_name(world* world, char* str)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* source = array_at(&world->locations, i);
+ if (strcmp(source->name, str) == 0) return source;
+ }
+ return 0;
+}
+
+void add_truck_to_world_location(world* world, world_location* location, truck* tr)
+{
+ log_assert(location->trucks.length < MAX_TRUCK_COUNT, "Too many trucks");
+ tr->id = world->next_id++;
+ array_push(&location->trucks, tr);
+}
+
+void add_employee_to_world_location(world_location* location, employee* employee)
+{
+ log_assert(location->employees.length < MAX_EMPLOYEE_COUNT, "Too many employees");
+ employee->current_location_id = location->id;
+ array_push(&location->employees, &employee);
+}
+
+static employee* create_employee(world* world, world_location* hired_at)
+{
+ employee* employee1 = mem_alloc(sizeof(employee));
+ char* firstname = array_at(&world->firstnames, get_random_number(0, world->firstnames.length));
+ char* lastname = array_at(&world->lastnames, get_random_number(0, world->lastnames.length));
+
+ snprintf(employee1->name, MAX_EMPLOYEE_NAME_LENGTH, "%s %s", firstname, lastname);
+ employee1->age = get_random_number(18, 60);
+ employee1->hire_date = world->current_time;
+ employee1->days_below_happiness_treshold = 0;
+ employee1->experience = (u8)((employee1->age - 18) * (get_random_number(1, 100)/100.0f));
+ employee1->salary = BASE_PAY + (employee1->experience * RAISE_PER_YEAR);
+ if (employee1->salary > MAX_PAY) employee1->salary = MAX_PAY;
+ employee1->happiness = 1.0f;
+ employee1->original_location_id = hired_at->id;
+ employee1->current_location_id = INVALID_ID;
+ employee1->assigned_truck = 0;
+ employee1->active_job_id = INVALID_ID;
+
+ // Portrait generation.
+ {
+ employee1->portrait_hair_type = get_random_number(0, PORTRAIT_MAX_HAIR_COUNT);
+ employee1->hair_color = hair_palette[get_random_number(0, (sizeof(hair_palette)/sizeof(color)))];
+ employee1->face_color = skin_palette[get_random_number(0, (sizeof(skin_palette)/sizeof(color)))];
+ employee1->body_color = body_palette[get_random_number(0, (sizeof(body_palette)/sizeof(color)))];
+ }
+
+ return employee1;
+}
+
+static bool world_create_default_state(world* world)
+{
+ world_location* start_location = get_world_location_by_name(world, "Maastricht");
+ if (!start_location) return false;
+ start_location->is_owned = true;
+ start_location->purchase_year = world->current_time.tm_year;
+
+ employee* employee1 = create_employee(world, start_location);
+ employee1->id = world->next_id++;
+ add_employee_to_world_location(start_location, employee1);
+
+ employee* employee2 = create_employee(world, start_location);
+ employee2->id = world->next_id++;
+ add_employee_to_world_location(start_location, employee2);
+
+ employee* employee3 = create_employee(world, start_location);
+ employee3->id = world->next_id++;
+ add_employee_to_world_location(start_location, employee3);
+
+ truck_dealer* dealer = array_at(&world->truck_dealers, 0);
+ truck* tr = array_at(&dealer->trucks, 0);
+ add_truck_to_world_location(world, start_location, tr);
+ add_truck_to_world_location(world, start_location, tr);
+ add_truck_to_world_location(world, start_location, tr);
+
+ {
+ truck* t1 = array_at(&start_location->trucks, 0);
+ truck* t2 = array_at(&start_location->trucks, 1);
+ t1->assigned_employee = employee1;
+ employee1->assigned_truck = t1;
+ t2->assigned_employee = employee2;
+ employee2->assigned_truck = t2;
+ }
+
+ return true;
+}
+
+static bool world_load_boat_routes_from_file(world* world)
+{
+ world->boat_routes = array_create(sizeof(boat_route));
+ file_content locations_file = platform_read_file_content("data/world/boat-routes.json", "rb");
+ if (locations_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(locations_file.content);
+ if (!json_object) return false;
+
+ cJSON *route;
+ cJSON_ArrayForEach(route, json_object)
+ {
+ boat_route new_route;
+ memset(&new_route, 0, sizeof(new_route));
+
+ boat_route_point new_point = (boat_route_point){0.0f,0.0f};
+ s32 index = 0;
+
+ cJSON *route_point;
+ cJSON_ArrayForEach(route_point, route)
+ {
+ if (index % 2 == 0) {
+ new_point.x = route_point->valuedouble;
+ }
+ else {
+ new_point.y = route_point->valuedouble;
+ new_route.points[new_route.count++] = new_point;
+ }
+
+ index++;
+ }
+
+ array_push(&world->boat_routes, &new_route);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&locations_file);
+
+ return true;
+}
+
+static bool world_load_companies_from_file(world* world)
+{
+ world->companies = array_create(sizeof(company));
+ file_content locations_file = platform_read_file_content("data/world/companies.json", "rb");
+ if (locations_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(locations_file.content);
+ if (!json_object) return false;
+
+ cJSON *country_entry;
+ cJSON_ArrayForEach(country_entry, json_object)
+ {
+ company new_company;
+ new_company.products = array_create(sizeof(product));
+
+ cJSON* name = cJSON_GetObjectItem(country_entry, "name");
+ if (!name) return false;
+
+ cJSON* logo = cJSON_GetObjectItem(country_entry, "logo");
+ if (!logo) return false;
+
+ string_copyn(new_company.name, name->valuestring, MAX_PRODUCT_NAME_LENGTH);
+ new_company.logo = assets_find_image_ref(0, assets_hash_path(logo->valuestring));
+ if (!new_company.logo) return false;
+
+ cJSON* products = cJSON_GetObjectItem(country_entry, "products");
+ if (!products) return false;
+
+ cJSON *product_entry;
+ cJSON_ArrayForEach(product_entry, products)
+ {
+ char tmp_buf[MAX_PRODUCT_NAME_LENGTH];
+ string_copyn(tmp_buf, product_entry->valuestring, MAX_PRODUCT_NAME_LENGTH);
+ array_push(&new_company.products, tmp_buf);
+ }
+
+ array_push(&world->companies, &new_company);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&locations_file);
+
+ return true;
+}
+
+static bool world_load_lastnames_from_file(world* world)
+{
+ world->lastnames = array_create(MAX_ENPOLYEE_LASTNAME_LENGTH);
+ array_reserve(&world->lastnames, 5000);
+
+ file_content firstname_file = platform_read_file_content("data/world/last-names.json", "rb");
+ if (firstname_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(firstname_file.content);
+ if (!json_object) return false;
+
+ cJSON *name_entry;
+ cJSON_ArrayForEach(name_entry, json_object)
+ {
+ char buffer[MAX_ENPOLYEE_LASTNAME_LENGTH];
+ string_copyn(buffer, name_entry->valuestring, MAX_ENPOLYEE_LASTNAME_LENGTH);
+ array_push(&world->lastnames, buffer);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&firstname_file);
+
+ world_create_connections(world);
+
+ return true;
+}
+
+static bool world_load_trucks_from_file(world* world)
+{
+ world->truck_dealers = array_create(sizeof(truck_dealer));
+ array_reserve(&world->firstnames, 5);
+
+ file_content firstname_file = platform_read_file_content("data/world/dealers.json", "rb");
+ if (firstname_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(firstname_file.content);
+ if (!json_object) return false;
+
+ cJSON *dealer_entry;
+ cJSON_ArrayForEach(dealer_entry, json_object)
+ {
+ truck_dealer new_dealer;
+ new_dealer.trucks = array_create(sizeof(truck));
+
+ cJSON* name = cJSON_GetObjectItem(dealer_entry, "name");
+ if (!name) return false;
+ string_copyn(new_dealer.name, name->valuestring, MAX_DEALER_NAME_LENGTH);
+
+ cJSON* logo = cJSON_GetObjectItem(dealer_entry, "logo");
+ if (!logo) return false;
+ new_dealer.logo = assets_find_image_ref(0, assets_hash_path(logo->valuestring));
+ if (!new_dealer.logo) return false;
+
+ cJSON* trucks = cJSON_GetObjectItem(dealer_entry, "trucks");
+
+ cJSON *truck_entry;
+ cJSON_ArrayForEach(truck_entry, trucks)
+ {
+ truck new_truck;
+ new_truck.assigned_employee = 0;
+
+ cJSON* logo = cJSON_GetObjectItem(truck_entry, "logo");
+ if (!logo) return false;
+ new_truck.logo = assets_find_image_ref(0, assets_hash_path(logo->valuestring));
+ if (!new_truck.logo) return false;
+
+ cJSON* name = cJSON_GetObjectItem(truck_entry, "name");
+ if (!name) return false;
+ string_copyn(new_truck.name, name->valuestring, MAX_TRUCK_NAME_LENGTH);
+ new_truck.type = assets_hash_path(new_truck.name);
+
+ cJSON* hp = cJSON_GetObjectItem(truck_entry, "power");
+ if (!hp) return false;
+ new_truck.hp = hp->valueint;
+
+ cJSON* price = cJSON_GetObjectItem(truck_entry, "price");
+ if (!price) return false;
+ new_truck.price = price->valueint;
+
+ cJSON* fuelcapacity = cJSON_GetObjectItem(truck_entry, "fuelcapacity");
+ if (!fuelcapacity) return false;
+ new_truck.fuelcapacity = fuelcapacity->valueint;
+
+ cJSON* torque = cJSON_GetObjectItem(truck_entry, "torque");
+ if (!torque) return false;
+ new_truck.torque = torque->valueint;
+
+ cJSON* fuelusage = cJSON_GetObjectItem(truck_entry, "fuelusage");
+ if (!fuelusage) return false;
+ new_truck.fuelusage = fuelusage->valuedouble;
+
+ array_push(&new_dealer.trucks, &new_truck);
+ }
+
+ array_push(&world->truck_dealers, &new_dealer);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&firstname_file);
+
+ world_create_connections(world);
+
+ return true;
+}
+
+static bool world_load_firstnames_from_file(world* world)
+{
+ world->firstnames = array_create(MAX_ENPOLYEE_FIRSTNAME_LENGTH);
+ array_reserve(&world->firstnames, 5000);
+
+ file_content firstname_file = platform_read_file_content("data/world/first-names.json", "rb");
+ if (firstname_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(firstname_file.content);
+ if (!json_object) return false;
+
+ cJSON *name_entry;
+ cJSON_ArrayForEach(name_entry, json_object)
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH];
+ string_copyn(buffer, name_entry->valuestring, MAX_ENPOLYEE_FIRSTNAME_LENGTH);
+ array_push(&world->firstnames, buffer);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&firstname_file);
+
+ world_create_connections(world);
+
+ return true;
+}
+
+static bool world_load_locations_from_file(world* world)
+{
+ world->locations = array_create(sizeof(world_location));
+ file_content locations_file = platform_read_file_content("data/world/locations.json", "rb");
+ if (locations_file.file_error) return false;
+
+ cJSON *json_object = cJSON_Parse(locations_file.content);
+ if (!json_object) return false;
+
+ cJSON *location_entry;
+ cJSON_ArrayForEach(location_entry, json_object)
+ {
+ cJSON* name = cJSON_GetObjectItem(location_entry, "name");
+ if (!name) return false;
+ cJSON* size = cJSON_GetObjectItem(location_entry, "size");
+ if (!size) return false;
+ cJSON* latitude = cJSON_GetObjectItem(location_entry, "latitude");
+ if (!latitude) return false;
+ cJSON* longitude = cJSON_GetObjectItem(location_entry, "longitude");
+ if (!longitude) return false;
+
+ world_location location = world_create_location(size->valueint, latitude->valuedouble, longitude->valuedouble, name->valuestring, false);
+ array_push(&world->locations, &location);
+ }
+
+ cJSON_Delete(json_object);
+ platform_destroy_file_content(&locations_file);
+
+ world_create_connections(world);
+
+ return true;
+}
+
+float world_location_get_price(world_location* location)
+{
+ float base_price = 300000.0f;
+ return base_price / location->size;
+}
+
+static money_data_collection* get_current_insights_data_for_location(world* world, world_location* location)
+{
+ s32 index = world->current_time.tm_year - location->purchase_year;
+ if (index >= location->insights.length) {
+ money_data_collection data = {0};
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {
+ data.months[i].total_income = NAN;
+ }
+ array_push(&location->insights, &data);
+ }
+
+ return (money_data_collection*)array_at(&location->insights, index);
+}
+
+static money_data_collection* get_current_insights_data(world* world)
+{
+ s32 index = world->current_time.tm_year - world->start_year;
+ if (index >= world->insights.length) {
+ money_data_collection data = {0};
+ for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {
+ data.months[i].total_income = NAN;
+ }
+ array_push(&world->insights, &data);
+ }
+
+ return (money_data_collection*)array_at(&world->insights, index);
+}
+
+world* world_create_new()
+{
+ world* new_world = mem_alloc(sizeof(world));
+ new_world->simulation_time = time(NULL);
+ new_world->start_year = gmtime(&new_world->simulation_time)->tm_year;
+ new_world->money = 100000.0f;
+ new_world->next_id = 1;
+ new_world->active_jobs = array_create(sizeof(active_job));
+ new_world->investments = (company_investments){0};
+ new_world->simulation_speed = 1;
+ new_world->days_since_last_random_event = 300;//-365; // No random events in the first year.
+ new_world->log.events = array_create(sizeof(event));
+ new_world->log.write_cursor = 0;
+ new_world->log.has_unread_messages = false;
+ array_reserve(&new_world->log.events, LOG_HISTORY_LENGTH);
+ new_world->insights = array_create(sizeof(money_data_collection));
+ array_reserve(&new_world->insights, 10);
+ new_world->insights.reserve_jump = 10;
+ array_reserve(&new_world->active_jobs, 100);
+ srand(new_world->simulation_time);
+ new_world->current_time = *gmtime(&new_world->simulation_time);
+
+ if (!world_load_locations_from_file(new_world)) {
+ log_info("Failed to load locations from data/world/locations.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_load_companies_from_file(new_world)) {
+ log_info("Missing companies in data/world/companies.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_load_firstnames_from_file(new_world)) {
+ log_info("Missing names in data/world/first-names.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_load_lastnames_from_file(new_world)) {
+ log_info("Missing names in data/world/last-names.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_load_trucks_from_file(new_world)) {
+ log_info("Missing names in data/world/dealers.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_load_boat_routes_from_file(new_world)) {
+ log_info("Missing names in data/world/boat-routes.json");
+ mem_free(new_world);
+ return 0;
+ }
+
+ if (!world_create_default_state(new_world)) {
+ log_info("Could not create world");
+ mem_free(new_world);
+ return 0;
+ }
+
+ world_assign_new_job_offers(new_world);
+ enable_insights_for_current_month(new_world);
+
+ return new_world;
+}
+
+static vec2f coords_to_px(platform_window* window, double lon, double lat)
+{
+ vec2f extra = {9 * scale, 4 * scale};
+ vec2f map_pos = {area.x + (float)(area.w * (180.0f + lon) / 360.0f),
+ area.y + (float)(area.h * (90.0f - lat) / 180.0f)};
+ map_pos.x += extra.x;
+ map_pos.y += extra.y;
+ return map_pos;
+}
+
+static void world_remove_expired_job_offers(world* world)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+
+ for (s32 x = 0; x < location->job_offers.length; x++)
+ {
+ job_offer* offer = array_at(&location->job_offers, x);
+ if (offer->expire_date <= world->simulation_time) {
+ // TODO: only free here when not scheduled!
+ //array_destroy(&offer->connections);
+ array_remove_at(&location->job_offers, x);
+ x--;
+ }
+ }
+ }
+}
+
+bool job_offer_has_ship_day(job_offer* offer, weekday day_to_find)
+{
+ for (s32 s = 0; s < offer->shipday_count; s++) {
+ weekday day = offer->shipdays[s];
+ if (day == day_to_find) return true;
+ }
+ return false;
+}
+
+static void world_find_location_deep(s32 depth, world_location* source, array* buf)
+{
+ world_location* current_source = source;
+ while (buf->length < depth) {
+ world_location* best_match = 0;
+ s32 attempt = 0;
+
+ try_again:
+ best_match = 0;
+ attempt++;
+ s32 rand_conn = get_random_number(0, current_source->connections.length);
+ world_location* connection = *(world_location**)array_at(¤t_source->connections, rand_conn);
+
+ bool already_in_path = false;
+ for (s32 c = 0; c < buf->length; c++) {
+ if (*(world_location**)array_at(buf, c) == connection) already_in_path = true;
+ }
+
+ if (already_in_path && attempt < current_source->connections.length) {
+ goto try_again;
+ }
+ best_match = already_in_path ? 0 : connection;
+
+ #if 0
+ double best_match_distance = 0;
+
+ for (s32 i = 0; i < current_source->connections.length; i++) {
+ world_location* connection = *(world_location**)array_at(¤t_source->connections, i);
+ if (connection == source) continue;
+
+ bool already_in_path = false;
+ for (s32 c = 0; c < buf->length; c++) {
+ if (*(world_location**)array_at(buf, c) == connection) already_in_path = true;
+ }
+
+ if (!already_in_path) {
+ double total_distance = fabs(connection->latitude - current_source->latitude) + fabs(connection->longitude - current_source->longitude);
+
+ if (!best_match || best_match_distance < total_distance) {
+ best_match_distance = total_distance;
+ best_match = connection;
+ }
+ }
+ }
+ #endif
+
+ if (!best_match) break;
+ array_push(buf, &best_match);
+ current_source = best_match;
+ }
+}
+
+static void world_assign_new_job_offers(world* world)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+ if (location->job_offers.length >= MAX_JOBOFFER_COUNT) continue;
+
+ s32 company_id = get_random_number(0, world->companies.length);
+ company* company = array_at(&world->companies, company_id);
+ s32 product_id = get_random_number(0, company->products.length);
+ product* product = array_at(&company->products, product_id);
+
+ job_offer new_offer = (job_offer){world->next_id++, world->simulation_time+DAYS(10), company, product, 0, {DAY_INVALID,DAY_INVALID,DAY_INVALID,DAY_INVALID}, 0};
+ new_offer.connections = array_create(sizeof(world_location*));
+
+ s32 amount_of_shipdays = get_random_number(1, MAX_SHIPDAYS+1);
+ for (s32 s = 0; s < amount_of_shipdays; s++) {
+ s32 random_day = get_random_number(0, NUM_DAYS);
+ if (!job_offer_has_ship_day(&new_offer, random_day)) {
+ new_offer.shipdays[new_offer.shipday_count++] = random_day;
+ }
+ else {
+ s--;
+ }
+ }
+
+ s32 amount_of_connections = get_random_number(1, 5) + 1; // +1 because we add original location to connection list.
+
+ array_push(&new_offer.connections, &location);
+ world_find_location_deep(amount_of_connections, location, &new_offer.connections);
+
+ float total_dist = 0.0;
+ for (s32 d = 0; d < new_offer.connections.length-1; d++)
+ {
+ world_location* source = *(world_location**)array_at(&new_offer.connections, d);
+ world_location* dest = *(world_location**)array_at(&new_offer.connections, d+1);
+ total_dist += distance_between_location(source, dest);
+ }
+ new_offer.total_distance = total_dist;
+ new_offer.reward = (u32)((JOB_OFFER_REWARD_PER_CONNECTION * location->reliability) * amount_of_connections-1); // -1 because source is is connection list.
+
+ // lest assume most experienced drivers drive at 95km/h
+ double min_duration_hours = (new_offer.total_distance/95.0);
+ double max_diration_hours = min_duration_hours * SHIPTIME_DURATION_MULTIPLIER_MIN;
+
+ new_offer.duration_sec_min = (time_t)(min_duration_hours * 60 * 60);
+ new_offer.duration_sec_max = (time_t)(max_diration_hours * 60 * 60);
+
+ // printf("Distance: %.0f, duration between %.2f and %.2f hours.", total_dist, min_duration_hours, max_diration_hours);
+
+ array_push(&location->job_offers, &new_offer);
+ }
+}
+
+static void world_assign_resumes_to_locations(world* world)
+{
+ // Expire old ones.
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+
+ for (s32 r = 0; r < location->resumes.length; r++)
+ {
+ resume* resume = array_at(&location->resumes, r);
+
+ // It is assumed a simulation day is longer than RESUME_FADEOUT_MS
+ // else the animation will be cut short.
+ if (resume->animation.started) {
+ array_remove_at(&location->resumes, r);
+ r--;
+ }
+
+ if (resume->expire_date <= world->simulation_time) {
+ resume->animation.started = true;
+ resume->hired = false;
+ }
+ }
+ }
+
+ // Assign new ones.
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ // 0.5 reliability = 0%
+ // 1.0 reliability = 10%
+ // 1.5 reliability = 20%
+ // etc.
+ // % = change of a new resume being submitted per day.
+ #if 1
+ if (get_random_number(0, 10) >= ceil(location->reliability)) continue;
+ #endif
+ resume new_resume;
+ new_resume.animation = animation_create(RESUME_FADEOUT_MS);
+ new_resume.expire_date = world->simulation_time+DAYS(10);
+ new_resume.employee = create_employee(world, location);
+
+ array_push(&location->resumes, &new_resume);
+ }
+}
+
+static double distance_between_location(world_location* location1, world_location* location2)
+{
+ double lat1 = location1->latitude;
+ double lat2 = location2->latitude;
+ double lon1 = location1->longitude;
+ double lon2 = location2->longitude;
+
+ double rlat1 = M_PI*lat1/180;
+ double rlat2 = M_PI*lat2/180;
+ double theta = lon1 - lon2;
+ double rtheta =M_PI*theta/180;
+ double dist =
+ sin(rlat1)*sin(rlat2) +cos(rlat1)*
+ cos(rlat2)*cos(rtheta);
+ dist = acos(dist);
+ dist = dist*180/M_PI;
+ dist = dist*60*1.1515;
+ return dist*1.609344; // Miles to km
+}
+
+static float get_employee_experience_factor(employee* emp)
+{
+ float experience_factor = emp->experience/MAX_EFFECTIVE_EXPERIENCE;
+ if (experience_factor > 1.0f) experience_factor = 1.0f;
+ return experience_factor;
+}
+
+static float get_shiptime_factor(employee* emp)
+{
+ float experience_factor = get_employee_experience_factor(emp);
+ float shiptime_factor = (SHIPTIME_DURATION_MULTIPLIER_MIN - (SHIPTIME_DURATION_MULTIPLIER_MIN - SHIPTIME_DURATION_MULTIPLIER_MAX) * experience_factor);
+ return shiptime_factor;
+}
+
+static void world_start_scheduled_job(world* world, scheduled_job* scheduled_job, scheduled_job_time scheduled_time)
+{
+ if (!scheduled_time.assignee) {
+ scheduled_job->trust -= MISSED_DELIVERY_TRUST_PENALTY;
+ char error_msg[MAX_EVENT_MESSAGE_LENGTH];
+ snprintf(error_msg, MAX_EVENT_MESSAGE_LENGTH, "A shipment has been missed because there is no assignee for the timeslot.");
+ world_report_event_ex(world, error_msg, EVENT_TYPE_MISSED_SHIPMENT_NO_ASSIGNEE, scheduled_job, scheduled_time);
+ return;
+ }
+
+ if (!scheduled_time.assignee->assigned_truck) {
+ scheduled_job->trust -= MISSED_DELIVERY_TRUST_PENALTY;
+ char error_msg[MAX_EVENT_MESSAGE_LENGTH];
+ snprintf(error_msg, MAX_EVENT_MESSAGE_LENGTH, "%s missed a shipment because they do not have a truck.", scheduled_time.assignee->name);
+ world_report_event(world, error_msg, EVENT_TYPE_MISSED_SHIPMENT_NO_TRUCK, scheduled_time.assignee);
+ return;
+ }
+
+ world_location* orig = *(world_location**)array_at(&scheduled_job->offer.connections, 0);
+ if (scheduled_time.assignee->current_location_id != orig->id) {
+ scheduled_job->trust -= MISSED_DELIVERY_TRUST_PENALTY;
+ char error_msg[MAX_EVENT_MESSAGE_LENGTH];
+ snprintf(error_msg, MAX_EVENT_MESSAGE_LENGTH, "%s missed a shipment because they are not at the right location.", scheduled_time.assignee->name);
+ world_report_event_ex(world, error_msg, EVENT_TYPE_MISSED_SHIPMENT_NOT_AT_LOCATION, scheduled_job, scheduled_time);
+ return;
+ }
+
+ // Remove employee from employee list when current location is external.
+ if (scheduled_time.assignee->current_location_id != scheduled_time.assignee->original_location_id) {
+ world_location* current_loc = get_world_location_by_id(world, scheduled_time.assignee->current_location_id);
+ log_assert(current_loc, "Current location cannot be 0");
+ employee* emp = get_employee_by_id(current_loc, scheduled_time.assignee->id);
+ if (emp) {
+ array_remove_by(¤t_loc->employees, &emp);
+ }
+ }
+
+ scheduled_time.assignee->current_location_id = INVALID_ID;
+ scheduled_time.assignee->active_job_id = scheduled_job->offer.id;
+
+ active_job new_job;
+ new_job.stay_at_destination = scheduled_time.stay_at_destination;
+ new_job.day = scheduled_time.day;
+ new_job.timeslot = scheduled_time.timeslot;
+ new_job.offer = scheduled_job->offer;
+ new_job.assignee = *scheduled_time.assignee;
+ new_job.assigned_truck = *scheduled_time.assignee->assigned_truck;
+
+ time_t leave_time = world->simulation_time-(world->simulation_time%(15*60));
+ new_job.left_at = leave_time;
+
+ float shiptime_factor = get_shiptime_factor(&new_job.assignee);
+ new_job.duration_sec = new_job.offer.duration_sec_min * shiptime_factor;
+
+ new_job.done_at = new_job.left_at + new_job.duration_sec;
+ new_job.reversed = false;
+
+ float gasprice = ((new_job.offer.total_distance/100.0f) * new_job.assigned_truck.fuelusage) * DIESEL_PRICE_PER_LITER;
+ ADD_EXPENSE(world, orig, expenses_from_fuel, gasprice);
+
+ array_push(&world->active_jobs, &new_job);
+
+ audio_set_sound_volume(snd_accelerate, 0.08f);
+ audio_play_sound(snd_accelerate, AUDIO_CHANNEL_SFX_3);
+}
+
+static void world_start_scheduled_jobs(world* world, s32 day, s32 timeslot)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ for (s32 r = 0; r < location->schedule.jobs.length; r++)
+ {
+ scheduled_job* scheduled_job = array_at(&location->schedule.jobs, r);
+
+ for (s32 t = 0; t < scheduled_job->offer.shipday_count; t++) {
+ scheduled_job_time scheduled_time = scheduled_job->timeslots[t];
+
+ if (scheduled_time.day == day && scheduled_time.timeslot == timeslot) {
+ world_start_scheduled_job(world, scheduled_job, scheduled_time);
+ }
+ }
+ }
+ }
+}
+
+static employee* get_global_employee_by_id(world* world, u32 id)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ for (s32 i = 0; i < location->employees.length; i++)
+ {
+ employee* em = *(employee**)array_at(&location->employees, i);
+ if (em->id == id) return em;
+ }
+ }
+ return 0;
+}
+
+static employee* get_employee_by_id(world_location* location, u32 id)
+{
+ for (s32 i = 0; i < location->employees.length; i++)
+ {
+ employee* em = *(employee**)array_at(&location->employees, i);
+ if (em->id == id) return em;
+ }
+ return 0;
+}
+
+static job_offer* get_job_offer_by_id(world_location* location, u32 id)
+{
+ for (s32 i = 0; i < location->job_offers.length; i++)
+ {
+ job_offer* job = array_at(&location->job_offers, i);
+ if (job->id == id) return job;
+ }
+ return 0;
+}
+
+static active_job* get_active_job_by_id(world* world, u32 id)
+{
+ for (s32 i = 0; i < world->active_jobs.length; i++)
+ {
+ active_job* job = array_at(&world->active_jobs, i);
+ if (job->offer.id == id) return job;
+ }
+ return 0;
+}
+
+static active_job* get_active_job_by_ref(world* world, active_job_ref ref)
+{
+ for (s32 i = 0; i < world->active_jobs.length; i++)
+ {
+ active_job* job = array_at(&world->active_jobs, i);
+ if (job->offer.id == ref.offerid && job->day == ref.day && job->timeslot == ref.timeslot) return job;
+ }
+ return 0;
+}
+
+static scheduled_job* get_scheduled_job_by_id(world_location* location, u32 id)
+{
+ for (s32 i = 0; i < location->schedule.jobs.length; i++)
+ {
+ scheduled_job* scheduled_job = array_at(&location->schedule.jobs, i);
+ if (scheduled_job->offer.id == id) return scheduled_job;
+ }
+ return 0;
+}
+
+static void world_update_active_jobs(world* world)
+{
+ for (s32 i = 0; i < world->active_jobs.length; i++)
+ {
+ active_job* job = array_at(&world->active_jobs, i);
+
+ if (job->done_at <= world->simulation_time) {
+ job_endpoints endpoints = job_offer_get_endpoints(&job->offer);
+ scheduled_job* sc_job = get_scheduled_job_by_id(endpoints.source, job->offer.id); // Get scheduled job from source location
+
+ if (job->reversed || job->stay_at_destination) { // Driver has returned from the round-trip or will stay at location.
+ world_location* orig_location = get_world_location_by_id(world, job->assignee.original_location_id);
+ employee* e = get_employee_by_id(orig_location, job->assignee.id);
+ e->current_location_id = job->stay_at_destination ? endpoints.dest->id : endpoints.source->id;
+ e->active_job_id = INVALID_ID;
+
+ // Employee is scheduled to stay at location
+ if (job->stay_at_destination) {
+ array_push(&endpoints.dest->employees, &e);
+ }
+ // Employee started the job from an external location and are returning
+ if (job->reversed && orig_location->id != e->current_location_id) {
+ array_push(&endpoints.source->employees, &e);
+ }
+
+ // Remove job.
+ array_remove_at(&world->active_jobs, i);
+ i--;
+ }
+ else { // Job is done, return to original location if not staying.
+ if (sc_job) sc_job->trust += (0.1f / sc_job->trust); // If job is still available, update trust.
+ ADD_INCOME(world, endpoints.source, income_from_trips, job->offer.reward);
+
+ float gasprice = ((job->offer.total_distance/100.0f) * job->assigned_truck.fuelusage) * DIESEL_PRICE_PER_LITER;
+ ADD_EXPENSE(world, endpoints.source, expenses_from_fuel, gasprice);
+
+ job->left_at = job->done_at;
+ job->done_at = job->left_at + job->duration_sec;
+ job->reversed = true;
+ }
+ }
+ }
+}
+
+static float get_worked_hours_per_week_for_employee(world* world, employee* emp, scheduled_job* excluding) {
+ float total = 0;
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ for (s32 f = 0; f < location->schedule.jobs.length; f++) {
+ scheduled_job* job = array_at(&location->schedule.jobs, f);
+ if (job == excluding) continue;
+
+ for (s32 s = 0; s < MAX_SHIPDAYS; s++) {
+ scheduled_job_time slot = job->timeslots[s];
+ if (slot.assignee == emp) {
+ float hworked = job->offer.duration_sec_min * get_shiptime_factor(emp);
+ if (!slot.stay_at_destination) hworked *= 2;
+ total += hworked;
+ }
+ }
+ }
+ }
+ return total / 3600.0f;
+}
+
+// Run once per day.
+static void world_update_employee_happiness(world* world, employee* emp) {
+ // Calculate overworking
+ float max_weekly_hours = MAX_WORKED_HOURS_WEEKLY;
+ float hours_worked = get_worked_hours_per_week_for_employee(world, emp, 0);
+ float hours_overworked = hours_worked - max_weekly_hours;
+ if (hours_overworked > 0) emp->happiness = 1.0f - ((hours_overworked/3.0f)*0.2f);
+ else emp->happiness = 1.0f;
+
+ // Calculate underpay
+ float expected_pay = BASE_PAY + (emp->experience * RAISE_PER_YEAR);
+ if (expected_pay > MAX_PAY) expected_pay = MAX_PAY;
+ float underpay = expected_pay - emp->salary;
+
+ emp->happiness -= (underpay/100.0f)*0.2f; // 1 Star per 100 euro underpay/overpay
+ if (emp->happiness < 0.0f) emp->happiness = 0.0f;
+ if (emp->happiness > 1.0f) emp->happiness = 1.0f;
+
+ if (emp->happiness < MINIMUM_EMPLOYEE_HAPPINESS) {
+ emp->days_below_happiness_treshold++;
+ }
+ else {
+ emp->days_below_happiness_treshold--;
+ }
+ if (emp->days_below_happiness_treshold < 0) emp->days_below_happiness_treshold = 0;
+
+ if (emp->days_below_happiness_treshold >= EMPLOYEE_MAX_UNHAPPY_DAYS_BEFORE_QUITTING) {
+
+ char error_msg[MAX_EVENT_MESSAGE_LENGTH];
+ snprintf(error_msg, MAX_EVENT_MESSAGE_LENGTH, "%s quit their job because they were unhappy for too long.", emp->name);
+ world_report_event(world, error_msg, EVENT_TYPE_EMPLOYEE_QUIT, get_world_location_by_id(world, emp->original_location_id));
+
+ end_contract_with_employee(world, emp);
+ }
+}
+
+// Pay investments daily. Run once per day.
+static void world_pay_investments(world* world)
+{
+ ADD_EXPENSE(world, 0, expenses_from_utility, world->investments.safety/28.0f);
+ ADD_EXPENSE(world, 0, expenses_from_utility, world->investments.marketing/28.0f);
+ ADD_EXPENSE(world, 0, expenses_from_utility, world->investments.human_resources/28.0f);
+ ADD_EXPENSE(world, 0, expenses_from_utility, world->investments.training/28.0f);
+ ADD_EXPENSE(world, 0, expenses_from_utility, world->investments.legal/28.0f);
+}
+
+// Payout salaries daily. Run once per day.
+static void world_payout_salaries(world* world)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ for (s32 r = 0; r < location->employees.length; r++)
+ {
+ employee* emp = *(employee**)array_at(&location->employees, r);
+
+ // Make sure employees are not paid twice when at external location.
+ if (emp->current_location_id == location->id) {
+ world_update_employee_happiness(world, emp);
+ ADD_EXPENSE(world, location, expenses_from_employees, (emp->salary/28.0f));
+ }
+ }
+ }
+}
+
+static void enable_insights_for_current_month(world* world)
+{
+ if (isnan(EXPENSES.total_income)) EXPENSES.total_income = 0; // Validate insights for current month.
+
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ money_data_collection* collection = get_current_insights_data_for_location(world, location);
+ collection->months[world->current_time.tm_mon].total_income = 0;
+ }
+}
+
+static void world_start_random_events(world* world)
+{
+ world->days_since_last_random_event++;
+
+ // Minor events
+ {
+ #define MIN_DELAY_BETWEEN_EVENTS (60)
+ float change_of_random_event = 0.0f;
+ if (world->days_since_last_random_event > MIN_DELAY_BETWEEN_EVENTS) {
+ change_of_random_event = ((world->days_since_last_random_event - MIN_DELAY_BETWEEN_EVENTS)*0.5f)/100.0f;
+ if (change_of_random_event > 1.0f) change_of_random_event = 1.0f;
+
+ bool run_event = change_of_random_event >= (get_random_number(0, 100)/100.0f);
+
+ (void)run_event; // TODO start event.
+ }
+ }
+}
+
+static void end_contract_with_employee(world* world, employee* emp)
+{
+ if (emp->assigned_truck) emp->assigned_truck->assigned_employee = 0;
+
+ // Remove assigned timeslots.
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ for (s32 r = 0; r < location->schedule.jobs.length; r++)
+ {
+ scheduled_job* scheduled_job = array_at(&location->schedule.jobs, r);
+
+ for (s32 t = 0; t < scheduled_job->offer.shipday_count; t++) {
+ scheduled_job_time scheduled_time = scheduled_job->timeslots[t];
+
+ if (scheduled_time.assignee == emp) {
+ scheduled_job->timeslots[t].assignee = 0;
+ }
+ }
+ }
+ }
+
+ // Remove active job
+ active_job* curr_job = get_active_job_by_id(world, emp->active_job_id);
+ array_remove_by(&world->active_jobs, curr_job);
+
+ // Remove employee from original location
+ world_location* orig_loc = get_world_location_by_id(world, emp->original_location_id);
+ array_remove_by(&orig_loc->employees, &emp);
+
+ // Remove employee from current location
+ world_location* curr_loc = get_world_location_by_id(world, emp->current_location_id);
+ if (curr_loc) array_remove_by(&curr_loc->employees, &emp);
+}
+
+static void world_run_simulation_tick(world* world)
+{
+ s32 elapsed_sec = MINUTES(world->simulation_speed);
+ s64 prev_stamp = world->simulation_time;
+ world->simulation_time += elapsed_sec;
+
+ struct tm prev_time_buf;
+ prev_time_buf = *gmtime(&prev_stamp);
+ struct tm* prev_time = &prev_time_buf;
+
+ struct tm curr_time_buf;
+ curr_time_buf = *gmtime(&world->simulation_time);
+ struct tm* curr_time = &curr_time_buf;
+ world->current_time = curr_time_buf;
+
+ if (prev_time->tm_wday != curr_time->tm_wday) { // Run once per day
+ world_remove_expired_job_offers(world);
+ world_assign_resumes_to_locations(world);
+ world_start_random_events(world);
+
+ if (curr_time->tm_mday <= 28) {
+ world_payout_salaries(world); // Pay salary first 28 days of month.
+ world_pay_investments(world);
+ }
+ }
+
+ if (prev_time->tm_wday == SUNDAY && curr_time->tm_wday == MONDAY) { // Run once per week
+ world_assign_new_job_offers(world);
+ }
+
+ if (curr_time->tm_hour >= WORK_HOUR_START && curr_time->tm_hour < WORK_HOUR_END) { // Run every 15min
+ s32 hour_part = 60 / TIME_SLOTS_PER_HOUR;
+ s32 prev_part = prev_time->tm_min / hour_part;
+ s32 curr_part = curr_time->tm_min / hour_part;
+ if (prev_part != curr_part) {
+ world_start_scheduled_jobs(world, curr_time->tm_wday, ((curr_time->tm_hour-WORK_HOUR_START)*TIME_SLOTS_PER_HOUR) + curr_part);
+ }
+ }
+
+ if (curr_time->tm_mday < prev_time->tm_mday) { // Run once per month
+ enable_insights_for_current_month(world);
+ }
+
+ world_update_active_jobs(world);
+}
+
+void world_update(platform_window* window, world* world)
+{
+ world_run_simulation_tick(world);
+}
+
+static vec2f get_world_location_for_job(platform_window* window, world* world, active_job* job)
+{
+ time_t total_time = job->done_at - job->left_at;
+ time_t elapsed_time = world->simulation_time - job->left_at;
+ float complete_percentage = elapsed_time/(float)total_time;
+ if (job->reversed) complete_percentage = 1.0f - complete_percentage;
+ if (complete_percentage > 1.0f) complete_percentage = 1.0f;
+ double current_km = job->offer.total_distance*complete_percentage;
+ double calculating_km = 0.0;
+ for (s32 d = 0; d < job->offer.connections.length-1; d++)
+ {
+ world_location* source = *(world_location**)array_at(&job->offer.connections, d);
+ world_location* dest = *(world_location**)array_at(&job->offer.connections, d+1);
+ double dist_between_points = distance_between_location(source, dest);
+ double next_landmark = calculating_km + dist_between_points;
+ double dist_from_source = current_km - calculating_km;
+
+ if (calculating_km < current_km && next_landmark >= current_km) {
+ float progress_between_points = dist_from_source / dist_between_points;
+ double lon = source->longitude + (dest->longitude - source->longitude) * progress_between_points;
+ double lat = source->latitude + (dest->latitude - source->latitude) * progress_between_points;
+
+ vec2f map_pos = coords_to_px(window, lon, lat);
+ return map_pos;
+ }
+ else {
+ calculating_km = next_landmark;
+ }
+ }
+ return (vec2f){0.0f, 0.0f};
+}
+
+world_update_result world_render(platform_window* window, world* world)
+{
+ world_update_result result = {0,0};
+
+ renderer->set_render_depth(3);
+ // Draw locations
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ vec2f map_pos = coords_to_px(window, location->longitude, location->latitude);
+ map_pos.x *= zoom;
+ map_pos.y *= zoom;
+ map_pos.x += camera_x;
+ map_pos.y += camera_y;
+
+ location->map_position_x = map_pos.x;
+ location->map_position_y = map_pos.y;
+
+ s32 circle_x = location->map_position_x - dotsize/2;
+ s32 circle_y = location->map_position_y - dotsize/2;
+ bool hovered = mouse_interacts(circle_x, circle_y, dotsize, dotsize);
+ location->is_hovered = hovered;
+ if (hovered) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ result.clicked_location = location;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ }
+
+ color tint = location->is_owned ? COLOR_LOCATION_DOT_OWNED : COLOR_LOCATION_DOT_UNOWNED;
+ if (location->is_hovered) {
+ tint = COLOR_DOT_HOVERED;
+ }
+ renderer->render_image_tint(img_locationdot, circle_x, circle_y, dotsize, dotsize, tint);
+ }
+
+ renderer->set_render_depth(2);
+ // Draw active jobs
+ for (s32 i = 0; i < world->active_jobs.length; i++)
+ {
+ active_job* job = array_at(&world->active_jobs, i);
+ vec2f pos = get_world_location_for_job(window, world, job);
+ job->px_pos = pos;
+
+ s32 circle_x = job->px_pos.x - dotsize/2;
+ s32 circle_y = job->px_pos.y - dotsize/2;
+ bool hovered = mouse_interacts(circle_x, circle_y, dotsize, dotsize);
+ job->is_hovered = hovered;
+ if (hovered) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) result.clicked_job = job;
+ }
+
+ renderer->render_image_tint(img_locationdot, job->px_pos.x-(dotsize/2),job->px_pos.y-(dotsize/2), dotsize,dotsize, job->is_hovered ? COLOR_DOT_HOVERED : rgb(255,0,0));
+ }
+
+ renderer->set_render_depth(1);
+ dotsize = 5 * scale * zoom;
+ // Draw connections
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* source = array_at(&world->locations, i);
+
+ for (s32 d = 0; d < source->connections.length; d++)
+ {
+ world_location* destination = *(world_location**)array_at(&source->connections, d);
+ if (destination == source) continue;
+
+ renderer->render_line(source->map_position_x, source->map_position_y, destination->map_position_x, destination->map_position_y, 1, rgb(255,0,0));
+ }
+ }
+
+ renderer->set_render_depth(1);
+ update_render_scenery(world);
+
+ return result;
+}
\ No newline at end of file |
