├── tests
├── .gitignore
├── saved_state
│ ├── .gitignore
│ ├── test.sh
│ └── CMakeLists.txt
├── CMakeLists.txt
├── go
│ └── go_tests.lua
└── chess
│ └── chess_test.lua
├── .dockerignore
├── src
├── android
│ ├── .idea
│ │ ├── .name
│ │ ├── compiler.xml
│ │ ├── kotlinc.xml
│ │ ├── vcs.xml
│ │ ├── deploymentTargetDropDown.xml
│ │ ├── gradle.xml
│ │ ├── jarRepositories.xml
│ │ └── misc.xml
│ ├── app
│ │ ├── .gitignore
│ │ ├── src
│ │ │ └── main
│ │ │ │ ├── assets
│ │ │ │ └── .gitignore
│ │ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── menu
│ │ │ │ │ └── menu_main.xml
│ │ │ │ ├── layout
│ │ │ │ │ ├── fragment_local_client_web_view.xml
│ │ │ │ │ ├── content_main.xml
│ │ │ │ │ ├── content_server_monitoring.xml
│ │ │ │ │ ├── server_monitor_activity.xml
│ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ ├── fragment_first.xml
│ │ │ │ │ ├── fragment_host_or_local.xml
│ │ │ │ │ └── fragment_second.xml
│ │ │ │ ├── drawable
│ │ │ │ │ └── ic_stop.xml
│ │ │ │ └── navigation
│ │ │ │ │ └── server_monitoring_nav_graph.xml
│ │ │ │ ├── ic_launcher-playstore.png
│ │ │ │ ├── java
│ │ │ │ └── net
│ │ │ │ │ └── alexbarry
│ │ │ │ │ └── alexgames
│ │ │ │ │ ├── network
│ │ │ │ │ ├── ISendMsg.java
│ │ │ │ │ ├── IMsgRecvd.java
│ │ │ │ │ └── ClientSession.java
│ │ │ │ │ ├── AlexConstants.java
│ │ │ │ │ ├── popup
│ │ │ │ │ ├── IAlexGamesPopupManager.java
│ │ │ │ │ └── PopupManagerImpl.java
│ │ │ │ │ ├── util
│ │ │ │ │ ├── StringFuncs.java
│ │ │ │ │ └── TouchEvtToClickEvt.java
│ │ │ │ │ ├── graphics
│ │ │ │ │ └── IAlexGamesCanvas.java
│ │ │ │ │ ├── AlexGamesViewModel.java
│ │ │ │ │ ├── server
│ │ │ │ │ ├── ServerMonitorViewModel.java
│ │ │ │ │ └── GameServerBinder.java
│ │ │ │ │ └── SecondFragment.java
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── cpp
│ │ │ │ └── CMakeLists.txt
│ │ ├── proguard-rules.pro
│ │ └── build.gradle
│ ├── settings.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── cp_games_assets.sh
│ ├── build.gradle
│ ├── gradle.properties
│ ├── adb_copy_files.sh
│ └── README.md
├── rust_games
│ ├── .gitignore
│ ├── trivia
│ │ └── mod.rs
│ ├── libs
│ │ ├── mod.rs
│ │ └── point.rs
│ ├── reversi
│ │ └── mod.rs
│ ├── config.toml
│ ├── gem_match
│ │ ├── mod.rs
│ │ └── gem_match_serialize.rs
│ ├── Cargo.toml
│ ├── rust_game_api.h
│ └── README.md
├── server
│ ├── socket
│ │ ├── test
│ │ │ ├── .gitignore
│ │ │ ├── build_client.sh
│ │ │ ├── build_server.sh
│ │ │ ├── test_client.c
│ │ │ └── test_server.c
│ │ └── socket_server.h
│ └── ws
│ │ └── requirements.txt
├── html
│ ├── cache.manifest
│ ├── manifest.json
│ ├── js
│ │ ├── collapsable.js
│ │ ├── url_args.js
│ │ ├── alexgames_c_dict.js
│ │ └── alexgames_colour_pref.js
│ └── css
│ │ ├── style_collapsable.css
│ │ ├── style_dark.css
│ │ └── style_very_dark.css
├── emscripten
│ ├── emscripten_dict_api.h
│ └── emscripten_c_dict_api.c
├── lua_api
│ ├── lua_api_dict.h
│ ├── lua_user_cfg.h
│ ├── lua_api_utils.h
│ ├── lua_api.h
│ └── lua_api_utils.c
├── cpp_libs
│ ├── game_api_helper
│ │ └── game_api_helper.h
│ ├── history_browse_ui
│ │ └── history_browse_ui.h
│ ├── sqlite_saved_state
│ │ ├── README.md
│ │ ├── CMakeLists.txt
│ │ └── sqlite_saved_state.h
│ ├── mouse_scroll_handler
│ │ ├── mouse_scroll_handler.h
│ │ └── mouse_scroll_handler.cpp
│ ├── utils
│ │ └── str_eq_literal.h
│ ├── touch_scroll_handler
│ │ ├── touch_scroll_handler.h
│ │ └── touch_scroll_handler.cpp
│ ├── touch_press_handler
│ │ ├── touch_press_handler.h
│ │ └── touch_press_handler.cpp
│ ├── saved_state_db
│ │ ├── saved_state_db_c_api.h
│ │ ├── README.md
│ │ └── saved_state_db_c_api.cpp
│ └── button_helper
│ │ └── button_helper.h
├── dictionary
│ ├── dict_utils.py
│ ├── c_dictionary.h
│ ├── CMakeLists.txt
│ ├── dictionary.h
│ └── wip
│ │ └── words_to_remove.txt
├── alexgames_config.h.in
├── game_api
│ ├── game_api_utils.h
│ ├── game_api_words.c
│ └── game_api_words.h
├── lua_scripts
│ ├── libs
│ │ ├── dice
│ │ │ ├── dice.lua
│ │ │ └── dice_draw.lua
│ │ ├── shuffle.lua
│ │ ├── cards
│ │ │ ├── cards_set.lua
│ │ │ └── card_test.lua
│ │ ├── draw
│ │ │ ├── draw_colours.lua
│ │ │ └── draw_shapes.lua
│ │ ├── ui
│ │ │ ├── show_buttons_popup.lua
│ │ │ └── touchpad.lua
│ │ ├── serialize
│ │ │ └── storage_helpers.lua
│ │ └── touch_to_mouse_evts.lua
│ └── games
│ │ ├── crossword_letters
│ │ ├── list_right_diffs.py
│ │ └── list_puzzle_words.lua
│ │ ├── sudoku
│ │ └── sudoku_main.lua
│ │ ├── go
│ │ └── go_ctrl.lua
│ │ ├── wu
│ │ └── wu_ctrl.lua
│ │ ├── chess
│ │ └── chess_serialize.lua
│ │ ├── blue
│ │ └── blue_main.lua
│ │ ├── life
│ │ ├── life_draw.lua
│ │ └── life_main.lua
│ │ ├── endless_runner
│ │ └── endless_runner_main.lua
│ │ ├── swarm
│ │ ├── swarm_keyboard_input.lua
│ │ └── swarm_main.lua
│ │ ├── thrust
│ │ └── thrust_keyboard_input.lua
│ │ ├── word_mastermind
│ │ └── word_mastermind_serialize.lua
│ │ ├── test
│ │ ├── draw_graphics_test.lua
│ │ └── timer_test.lua
│ │ └── fluid_mix
│ │ └── fluid_mix_serialize.lua
└── ui_wxWidgets
│ ├── wx_network_ui.h
│ ├── wx_game_popup.h
│ └── wx_network.h
├── metadata
└── en-US
│ ├── changelogs
│ └── 1.txt
│ ├── short_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── screenshot3-chess.png
│ │ ├── screenshot1-solitaire.png
│ │ ├── screenshot5-play_or_host.png
│ │ ├── screenshot4-word_mastermind.png
│ │ └── screenshot2-crossword_letters.png
│ └── full_description.txt
├── img
├── arrow.png
├── logo.png
├── spider.png
├── favicon.png
├── black_piece.png
├── brick_wall.png
├── cards
│ ├── clubs.png
│ ├── hearts.png
│ ├── spades.png
│ ├── blank_card.png
│ ├── diamonds.png
│ ├── card_facedown.png
│ ├── card_highlight.png
│ ├── blank_card.svg
│ └── card_highlight.svg
├── dice
│ ├── dice1.png
│ ├── dice2.png
│ ├── dice3.png
│ ├── dice4.png
│ ├── dice5.png
│ └── dice6.png
├── space
│ ├── ship1.png
│ └── lunar_lander.png
├── white_piece.png
├── game_icons
│ ├── go.png
│ ├── wu.png
│ ├── 31s.png
│ ├── chess.png
│ ├── crib.png
│ ├── life.png
│ ├── reversi.png
│ ├── thrust.png
│ ├── backgammon.png
│ ├── card_sim.png
│ ├── checkers.png
│ ├── fluid_mix.png
│ ├── gem_match.png
│ ├── hospital.png
│ ├── solitaire.png
│ ├── minesweeper.png
│ ├── spider_swing.png
│ ├── endless_runner.png
│ ├── word_mastermind.png
│ └── crossword_letters.png
├── hospital
│ ├── bed1.png
│ ├── doctor1.png
│ ├── doctor2.png
│ ├── doctor3.png
│ ├── doctor4.png
│ ├── favicon.png
│ ├── patient1.png
│ ├── ui
│ │ ├── dirpad.png
│ │ ├── menu_button.png
│ │ ├── thumb_buttons.png
│ │ ├── progress_circle.png
│ │ ├── action_needed_arrow.png
│ │ └── tutorial
│ │ │ ├── need_aed.png
│ │ │ └── need_cpr.png
│ ├── bed1-flipped.png
│ ├── doctor-head.png
│ ├── floor_tile.png
│ ├── oxygen_tank.png
│ ├── ventilator.png
│ ├── xray_sheet.png
│ ├── xray_source.png
│ ├── doctor-outline.png
│ ├── floor_tile_bad.png
│ ├── iv_stand_bag1.png
│ ├── patient_in_bed.png
│ ├── floor_highlight.png
│ ├── green_cross_icon.png
│ ├── defibrillator_sabrina.png
│ ├── patient_in_bed-flipped.png
│ ├── patient_need_icons
│ │ ├── bg.png
│ │ ├── bg_fixer.png
│ │ ├── attention.png
│ │ ├── low_fluids.png
│ │ ├── low_oxygen.png
│ │ ├── broken_bone.png
│ │ └── no_heartbeat.png
│ ├── patient_progress_bar_icon_needs.png
│ └── patient_progress_bar_icon_satisfied.png
├── more_info_btn.png
├── wooden_board.png
├── chess
│ ├── king_black.png
│ ├── king_white.png
│ ├── pawn_black.png
│ ├── pawn_white.png
│ ├── rook_black.png
│ ├── rook_white.png
│ ├── bishop_black.png
│ ├── bishop_white.png
│ ├── knight_black.png
│ ├── knight_white.png
│ ├── queen_black.png
│ ├── queen_white.png
│ ├── king_black_dark.png
│ ├── pawn_black_dark.png
│ ├── rook_black_dark.png
│ ├── bishop_black_dark.png
│ ├── knight_black_dark.png
│ └── queen_black_dark.png
├── logo-transparent.png
├── minesweeper
│ ├── box1.png
│ ├── box2.png
│ ├── box3.png
│ ├── box4.png
│ ├── box5.png
│ ├── box6.png
│ ├── box7.png
│ ├── box8.png
│ ├── mine.png
│ ├── box_empty.png
│ ├── box_unclicked.png
│ ├── box_flagged_blue.png
│ └── box_flagged_red.png
├── piece_highlight.png
├── piece_king_icon.png
├── swarm
│ └── grass_bg1.png
├── backgammon
│ ├── black_triangle.png
│ ├── triangle_black.png
│ ├── triangle_white.png
│ └── triangle_highlight.png
├── credits
│ └── Lua-Logo_128x128.png
├── black_piece.svg
├── white_piece.svg
├── wooden_board.svg
└── piece_highlight.svg
├── .gitignore
├── docker
├── http_server
│ ├── start_http_server.sh
│ ├── build.sh
│ └── Dockerfile.build_wasm
└── ws_server
│ └── Dockerfile
├── docker-compose.yml
├── .github
└── workflows
│ ├── build.yml
│ └── docker-image.yml
├── local_env.cmake
├── clean.sh
└── BUILD.md
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | out/
2 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | build/wasm/out/
2 |
--------------------------------------------------------------------------------
/src/android/.idea/.name:
--------------------------------------------------------------------------------
1 | AlexGames
--------------------------------------------------------------------------------
/src/android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/src/rust_games/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 |
--------------------------------------------------------------------------------
/src/server/socket/test/.gitignore:
--------------------------------------------------------------------------------
1 | out/
2 |
--------------------------------------------------------------------------------
/tests/saved_state/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | out/
3 |
--------------------------------------------------------------------------------
/src/rust_games/trivia/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod trivia_main;
2 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/1.txt:
--------------------------------------------------------------------------------
1 | Initial android release.
2 |
--------------------------------------------------------------------------------
/src/rust_games/libs/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod point;
2 | pub mod swipe_tracker;
3 |
--------------------------------------------------------------------------------
/src/server/ws/requirements.txt:
--------------------------------------------------------------------------------
1 | asyncio==3.4.3
2 | websockets==11.0.3
3 |
--------------------------------------------------------------------------------
/img/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/arrow.png
--------------------------------------------------------------------------------
/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/logo.png
--------------------------------------------------------------------------------
/img/spider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/spider.png
--------------------------------------------------------------------------------
/src/android/app/src/main/assets/.gitignore:
--------------------------------------------------------------------------------
1 | games/
2 | html/
3 | words-en.txt
4 |
--------------------------------------------------------------------------------
/src/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='AlexGames'
2 | include ':app'
3 |
--------------------------------------------------------------------------------
/src/rust_games/reversi/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod reversi_core;
2 | pub mod reversi_main;
3 |
--------------------------------------------------------------------------------
/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/favicon.png
--------------------------------------------------------------------------------
/src/html/cache.manifest:
--------------------------------------------------------------------------------
1 | CACHE MANIFEST
2 |
3 | # Version 1.0002
4 |
5 | NETWORK: *
6 |
--------------------------------------------------------------------------------
/src/rust_games/config.toml:
--------------------------------------------------------------------------------
1 | #[target.wasm32-unknown-unknown]
2 | #linker = "emcc"
3 |
--------------------------------------------------------------------------------
/src/server/socket/test/build_client.sh:
--------------------------------------------------------------------------------
1 | gcc test_client.c -I.. ../*.c -o out/client
2 |
--------------------------------------------------------------------------------
/img/black_piece.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/black_piece.png
--------------------------------------------------------------------------------
/img/brick_wall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/brick_wall.png
--------------------------------------------------------------------------------
/img/cards/clubs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/clubs.png
--------------------------------------------------------------------------------
/img/dice/dice1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice1.png
--------------------------------------------------------------------------------
/img/dice/dice2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice2.png
--------------------------------------------------------------------------------
/img/dice/dice3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice3.png
--------------------------------------------------------------------------------
/img/dice/dice4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice4.png
--------------------------------------------------------------------------------
/img/dice/dice5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice5.png
--------------------------------------------------------------------------------
/img/dice/dice6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/dice/dice6.png
--------------------------------------------------------------------------------
/img/space/ship1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/space/ship1.png
--------------------------------------------------------------------------------
/img/white_piece.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/white_piece.png
--------------------------------------------------------------------------------
/metadata/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Play simple Lua/Rust games, host web games server
2 |
--------------------------------------------------------------------------------
/img/cards/hearts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/hearts.png
--------------------------------------------------------------------------------
/img/cards/spades.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/spades.png
--------------------------------------------------------------------------------
/img/game_icons/go.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/go.png
--------------------------------------------------------------------------------
/img/game_icons/wu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/wu.png
--------------------------------------------------------------------------------
/img/hospital/bed1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/bed1.png
--------------------------------------------------------------------------------
/img/more_info_btn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/more_info_btn.png
--------------------------------------------------------------------------------
/img/wooden_board.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/wooden_board.png
--------------------------------------------------------------------------------
/img/cards/blank_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/blank_card.png
--------------------------------------------------------------------------------
/img/cards/diamonds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/diamonds.png
--------------------------------------------------------------------------------
/img/chess/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/king_black.png
--------------------------------------------------------------------------------
/img/chess/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/king_white.png
--------------------------------------------------------------------------------
/img/chess/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/pawn_black.png
--------------------------------------------------------------------------------
/img/chess/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/pawn_white.png
--------------------------------------------------------------------------------
/img/chess/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/rook_black.png
--------------------------------------------------------------------------------
/img/chess/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/rook_white.png
--------------------------------------------------------------------------------
/img/game_icons/31s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/31s.png
--------------------------------------------------------------------------------
/img/game_icons/chess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/chess.png
--------------------------------------------------------------------------------
/img/game_icons/crib.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/crib.png
--------------------------------------------------------------------------------
/img/game_icons/life.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/life.png
--------------------------------------------------------------------------------
/img/hospital/doctor1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor1.png
--------------------------------------------------------------------------------
/img/hospital/doctor2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor2.png
--------------------------------------------------------------------------------
/img/hospital/doctor3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor3.png
--------------------------------------------------------------------------------
/img/hospital/doctor4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor4.png
--------------------------------------------------------------------------------
/img/hospital/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/favicon.png
--------------------------------------------------------------------------------
/img/logo-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/logo-transparent.png
--------------------------------------------------------------------------------
/img/minesweeper/box1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box1.png
--------------------------------------------------------------------------------
/img/minesweeper/box2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box2.png
--------------------------------------------------------------------------------
/img/minesweeper/box3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box3.png
--------------------------------------------------------------------------------
/img/minesweeper/box4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box4.png
--------------------------------------------------------------------------------
/img/minesweeper/box5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box5.png
--------------------------------------------------------------------------------
/img/minesweeper/box6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box6.png
--------------------------------------------------------------------------------
/img/minesweeper/box7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box7.png
--------------------------------------------------------------------------------
/img/minesweeper/box8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box8.png
--------------------------------------------------------------------------------
/img/minesweeper/mine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/mine.png
--------------------------------------------------------------------------------
/img/piece_highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/piece_highlight.png
--------------------------------------------------------------------------------
/img/piece_king_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/piece_king_icon.png
--------------------------------------------------------------------------------
/img/swarm/grass_bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/swarm/grass_bg1.png
--------------------------------------------------------------------------------
/img/chess/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/bishop_black.png
--------------------------------------------------------------------------------
/img/chess/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/bishop_white.png
--------------------------------------------------------------------------------
/img/chess/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/knight_black.png
--------------------------------------------------------------------------------
/img/chess/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/knight_white.png
--------------------------------------------------------------------------------
/img/chess/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/queen_black.png
--------------------------------------------------------------------------------
/img/chess/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/queen_white.png
--------------------------------------------------------------------------------
/img/game_icons/reversi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/reversi.png
--------------------------------------------------------------------------------
/img/game_icons/thrust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/thrust.png
--------------------------------------------------------------------------------
/img/hospital/patient1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient1.png
--------------------------------------------------------------------------------
/img/hospital/ui/dirpad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/dirpad.png
--------------------------------------------------------------------------------
/img/space/lunar_lander.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/space/lunar_lander.png
--------------------------------------------------------------------------------
/img/cards/card_facedown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/card_facedown.png
--------------------------------------------------------------------------------
/img/cards/card_highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/cards/card_highlight.png
--------------------------------------------------------------------------------
/img/chess/king_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/king_black_dark.png
--------------------------------------------------------------------------------
/img/chess/pawn_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/pawn_black_dark.png
--------------------------------------------------------------------------------
/img/chess/rook_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/rook_black_dark.png
--------------------------------------------------------------------------------
/img/game_icons/backgammon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/backgammon.png
--------------------------------------------------------------------------------
/img/game_icons/card_sim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/card_sim.png
--------------------------------------------------------------------------------
/img/game_icons/checkers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/checkers.png
--------------------------------------------------------------------------------
/img/game_icons/fluid_mix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/fluid_mix.png
--------------------------------------------------------------------------------
/img/game_icons/gem_match.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/gem_match.png
--------------------------------------------------------------------------------
/img/game_icons/hospital.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/hospital.png
--------------------------------------------------------------------------------
/img/game_icons/solitaire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/solitaire.png
--------------------------------------------------------------------------------
/img/hospital/bed1-flipped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/bed1-flipped.png
--------------------------------------------------------------------------------
/img/hospital/doctor-head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor-head.png
--------------------------------------------------------------------------------
/img/hospital/floor_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/floor_tile.png
--------------------------------------------------------------------------------
/img/hospital/oxygen_tank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/oxygen_tank.png
--------------------------------------------------------------------------------
/img/hospital/ventilator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ventilator.png
--------------------------------------------------------------------------------
/img/hospital/xray_sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/xray_sheet.png
--------------------------------------------------------------------------------
/img/hospital/xray_source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/xray_source.png
--------------------------------------------------------------------------------
/img/minesweeper/box_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box_empty.png
--------------------------------------------------------------------------------
/img/chess/bishop_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/bishop_black_dark.png
--------------------------------------------------------------------------------
/img/chess/knight_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/knight_black_dark.png
--------------------------------------------------------------------------------
/img/chess/queen_black_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/chess/queen_black_dark.png
--------------------------------------------------------------------------------
/img/game_icons/minesweeper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/minesweeper.png
--------------------------------------------------------------------------------
/img/game_icons/spider_swing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/spider_swing.png
--------------------------------------------------------------------------------
/img/hospital/doctor-outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/doctor-outline.png
--------------------------------------------------------------------------------
/img/hospital/floor_tile_bad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/floor_tile_bad.png
--------------------------------------------------------------------------------
/img/hospital/iv_stand_bag1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/iv_stand_bag1.png
--------------------------------------------------------------------------------
/img/hospital/patient_in_bed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_in_bed.png
--------------------------------------------------------------------------------
/img/hospital/ui/menu_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/menu_button.png
--------------------------------------------------------------------------------
/metadata/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/icon.png
--------------------------------------------------------------------------------
/img/backgammon/black_triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/backgammon/black_triangle.png
--------------------------------------------------------------------------------
/img/backgammon/triangle_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/backgammon/triangle_black.png
--------------------------------------------------------------------------------
/img/backgammon/triangle_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/backgammon/triangle_white.png
--------------------------------------------------------------------------------
/img/credits/Lua-Logo_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/credits/Lua-Logo_128x128.png
--------------------------------------------------------------------------------
/img/game_icons/endless_runner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/endless_runner.png
--------------------------------------------------------------------------------
/img/game_icons/word_mastermind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/word_mastermind.png
--------------------------------------------------------------------------------
/img/hospital/floor_highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/floor_highlight.png
--------------------------------------------------------------------------------
/img/hospital/green_cross_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/green_cross_icon.png
--------------------------------------------------------------------------------
/img/hospital/ui/thumb_buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/thumb_buttons.png
--------------------------------------------------------------------------------
/img/minesweeper/box_unclicked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box_unclicked.png
--------------------------------------------------------------------------------
/img/game_icons/crossword_letters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/game_icons/crossword_letters.png
--------------------------------------------------------------------------------
/img/hospital/ui/progress_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/progress_circle.png
--------------------------------------------------------------------------------
/img/minesweeper/box_flagged_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box_flagged_blue.png
--------------------------------------------------------------------------------
/img/minesweeper/box_flagged_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/minesweeper/box_flagged_red.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
--------------------------------------------------------------------------------
/img/backgammon/triangle_highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/backgammon/triangle_highlight.png
--------------------------------------------------------------------------------
/img/hospital/defibrillator_sabrina.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/defibrillator_sabrina.png
--------------------------------------------------------------------------------
/img/hospital/patient_in_bed-flipped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_in_bed-flipped.png
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/bg.png
--------------------------------------------------------------------------------
/img/hospital/ui/action_needed_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/action_needed_arrow.png
--------------------------------------------------------------------------------
/img/hospital/ui/tutorial/need_aed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/tutorial/need_aed.png
--------------------------------------------------------------------------------
/img/hospital/ui/tutorial/need_cpr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/ui/tutorial/need_cpr.png
--------------------------------------------------------------------------------
/src/server/socket/test/build_server.sh:
--------------------------------------------------------------------------------
1 | set -e
2 | set -u
3 | set -x
4 |
5 | gcc test_server.c -I.. ../*.c -o out/server -lpthread
6 |
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/bg_fixer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/bg_fixer.png
--------------------------------------------------------------------------------
/src/emscripten/emscripten_dict_api.h:
--------------------------------------------------------------------------------
1 | #include "game_api_words.h"
2 |
3 | const struct game_dict_api *get_emscripten_game_dict_api(void);
4 |
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/attention.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/attention.png
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/low_fluids.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/low_fluids.png
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/low_oxygen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/low_oxygen.png
--------------------------------------------------------------------------------
/src/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/rust_games/gem_match/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod gem_match_core;
2 | pub mod gem_match_draw;
3 | pub mod gem_match_main;
4 | pub mod gem_match_serialize;
5 |
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/broken_bone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/broken_bone.png
--------------------------------------------------------------------------------
/img/hospital/patient_need_icons/no_heartbeat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_need_icons/no_heartbeat.png
--------------------------------------------------------------------------------
/img/hospital/patient_progress_bar_icon_needs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_progress_bar_icon_needs.png
--------------------------------------------------------------------------------
/src/lua_api/lua_api_dict.h:
--------------------------------------------------------------------------------
1 | #include "game_api_words.h"
2 |
3 | void init_lua_alex_dict(void *L, const char *name, const struct game_dict_api *api);
4 |
--------------------------------------------------------------------------------
/src/android/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/img/hospital/patient_progress_bar_icon_satisfied.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/img/hospital/patient_progress_bar_icon_satisfied.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot3-chess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/phoneScreenshots/screenshot3-chess.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot1-solitaire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/phoneScreenshots/screenshot1-solitaire.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/src/cpp_libs/game_api_helper/game_api_helper.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "game_api.h"
5 |
6 | struct game_api_callbacks create_default_callbacks(void);
7 |
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot5-play_or_host.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/phoneScreenshots/screenshot5-play_or_host.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot4-word_mastermind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/phoneScreenshots/screenshot4-word_mastermind.png
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #687071
4 |
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot2-crossword_letters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbarry/AlexGames/HEAD/metadata/en-US/images/phoneScreenshots/screenshot2-crossword_letters.png
--------------------------------------------------------------------------------
/src/android/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/android/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/android/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/network/ISendMsg.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.network;
2 |
3 | public interface ISendMsg {
4 | public void send_msg(String dst, byte[] msg, int msg_len);
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | cscope.out
2 | third_party/
3 | old/
4 | logs/
5 | out/
6 | .*.swp
7 | .*.swo
8 | .DS_Store
9 | __pycache__
10 |
11 | # LibreOffice spreadsheets in plaintext (to be git-friendly)
12 | .~lock.*.fods#
13 |
14 | venv
15 |
--------------------------------------------------------------------------------
/src/cpp_libs/history_browse_ui/history_browse_ui.h:
--------------------------------------------------------------------------------
1 | #include "game_api.h"
2 |
3 | #ifdef __cplusplus
4 | extern "C" {
5 | #endif
6 |
7 | const struct game_api *get_history_browse_api(void);
8 |
9 | #ifdef __cplusplus
10 | }
11 | #endif
12 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/AlexConstants.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames;
2 |
3 | public class AlexConstants {
4 | public static final String HOST_SERVER_SERVICE_NOTIFICATION_CHANNEL_ID = "ServiceNotifications";
5 | }
6 |
--------------------------------------------------------------------------------
/src/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/tests/saved_state/test.sh:
--------------------------------------------------------------------------------
1 | set -e
2 | set -u
3 | set -x
4 |
5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${DIR}"
7 |
8 | mkdir -p out
9 | cd out/
10 |
11 | cmake make ../
12 | cmake --build . $@
13 | ./test_saved_state
14 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/network/IMsgRecvd.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.network;
2 |
3 | public interface IMsgRecvd {
4 | public void handle_msg_received(String src, byte[] data, int data_len);
5 | public void disconnected(String src);
6 | }
7 |
--------------------------------------------------------------------------------
/src/dictionary/dict_utils.py:
--------------------------------------------------------------------------------
1 | def read_word_list(fname):
2 | words = set()
3 | with open(fname, 'r') as f:
4 | for line in f:
5 | if line.startswith('#'): continue
6 | if not line.strip(): continue
7 | word = line.strip()
8 | words.add(word)
9 | return words
10 |
11 |
--------------------------------------------------------------------------------
/src/cpp_libs/sqlite_saved_state/README.md:
--------------------------------------------------------------------------------
1 | # sqlite saved state
2 |
3 | In a browser, `window.localStorage` already provides a fairly convenient key/value storage that persists.
4 |
5 | In other platforms, one convenient option is to include sqlite and use an sqlite database for key/value storage.
6 |
--------------------------------------------------------------------------------
/docker/http_server/start_http_server.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
4 | cd "${DIR}/../../"
5 |
6 | sudo docker run \
7 | --rm \
8 | -v $(pwd)/build/wasm/out/http_out:/usr/share/nginx/html/ \
9 | -p 1234:80 \
10 | "nginx:latest"
11 |
--------------------------------------------------------------------------------
/src/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/src/cpp_libs/sqlite_saved_state/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | add_library(alexgames_sqlite_saved_state STATIC
4 | sqlite_saved_state.c)
5 | target_include_directories(alexgames_sqlite_saved_state PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
6 |
7 | target_link_libraries(alexgames_sqlite_saved_state PUBLIC sqlite3)
8 |
--------------------------------------------------------------------------------
/src/lua_api/lua_user_cfg.h:
--------------------------------------------------------------------------------
1 | int luaopen_alexlib(lua_State *L);
2 |
3 | // If I understand correctly, this is needed to include
4 | // the library in the command line lua interpreter.
5 | // But calling luaL_requiref(L, "alexgames", luaopen_alexlib, 0)
6 | // is enough
7 | //#define LUA_EXTRALIBS { "alexgames", luaopen_alexlib },
8 |
--------------------------------------------------------------------------------
/src/alexgames_config.h.in:
--------------------------------------------------------------------------------
1 |
2 | #define PROJECT_NAME "@PROJECT_NAME@"
3 | #define PROJECT_VERSION "@PROJECT_VERSION@"
4 | #define GIT_HEAD_HASH "@GIT_HEAD_HASH@"
5 |
6 | #define PROJECT_VERSION_MAJOR "@PROJECT_VERSION_MAJOR@"
7 | #define PROJECT_VERSION_MINOR "@PROJECT_VERSION_MINOR@"
8 | #define PROJECT_VERSION_PATCH "@PROJECT_VERSION_PATCH@"
9 |
--------------------------------------------------------------------------------
/src/dictionary/c_dictionary.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #include "game_api_words.h"
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 |
9 | void *build_word_dict_from_file(const char *fname);
10 |
11 |
12 | const struct game_dict_api *get_game_dict_api(void);
13 | const struct game_dict_api *get_c_dictionary_api(void);
14 |
15 | #ifdef __cplusplus
16 | }
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/game_api/game_api_utils.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | size_t b64_encoded_size_to_max_decoded_size(size_t encoded_input_len);
4 |
5 | size_t write_b64(char *state_out, size_t state_out_len, const uint8_t *input_buff, size_t input_buff_len);
6 | size_t decode_b64(uint8_t *decoded_out, size_t decoded_out_max_len,
7 | const char *encoded_input, size_t encoded_input_len);
8 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/dice/dice.lua:
--------------------------------------------------------------------------------
1 |
2 | local dice = {}
3 |
4 | function dice.roll_dice(dice_max)
5 | return math.random(1,dice_max)
6 | end
7 |
8 | function dice.roll_multiple_dice(num_dice, dice_max)
9 | local ary = {}
10 | for i=1,num_dice do
11 | table.insert(ary, dice.roll_dice(dice_max))
12 | end
13 | return ary
14 | end
15 |
16 | return dice
17 |
--------------------------------------------------------------------------------
/src/cpp_libs/mouse_scroll_handler/mouse_scroll_handler.h:
--------------------------------------------------------------------------------
1 | #include "game_api.h"
2 |
3 | class MouseScrollHandler {
4 |
5 | public:
6 | int handle_mousemove(int pos_y, int pos_x, int buttons);
7 | void handle_mouse_evt(int mouse_evt_id, int pos_y, int pos_x);
8 |
9 | private:
10 | bool mouse_down = false;
11 | bool mouse_left = false;
12 | int last_mouse_y;
13 | };
14 |
--------------------------------------------------------------------------------
/src/rust_games/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rust_games"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | libc = "0.2.155"
8 | rand = "0.8"
9 | serde = { version = "1.0", features = ["derive"] }
10 | bincode = "1.3.3"
11 | lazy_static = "1.4"
12 |
13 | [lib]
14 | name = "alexgames_rust"
15 | path = "rust_game_handler.rs"
16 | crate-type = ["staticlib"]
17 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/popup/IAlexGamesPopupManager.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.popup;
2 |
3 | public interface IAlexGamesPopupManager {
4 | interface Callback {
5 | void popup_button_clicked(String popup_id, int btn_id);
6 | }
7 |
8 | void set_callback(Callback callback);
9 | void show_popup(String popup_id, String title, String msg, String btns[]);
10 | }
11 |
--------------------------------------------------------------------------------
/src/android/cp_games_assets.sh:
--------------------------------------------------------------------------------
1 | set -e
2 | set -u
3 | set -x
4 |
5 |
6 | mkdir -p src/android/app/src/main/assets/games/preload/
7 | cp -r src/lua_scripts/* src/android/app/src/main/assets/games/preload/
8 | cp -r img/ src/android/app/src/main/assets/games/
9 |
10 | mkdir -p src/android/app/src/main/assets/html
11 | cp -r build/wasm/out/http_out/* src/android/app/src/main/assets/html/
12 | cp -r out/words-en.txt src/android/app/src/main/assets/
13 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/shuffle.lua:
--------------------------------------------------------------------------------
1 | local shuffle = {}
2 |
3 | local function swap(array, index1, index2)
4 | array[index1], array[index2] = array[index2], array[index1]
5 | end
6 |
7 | function shuffle.shuffle(array)
8 | local counter = #array
9 | while counter > 1 do
10 | local index = math.random(counter)
11 | swap(array, index, counter)
12 | counter = counter - 1
13 | end
14 | end
15 |
16 | return shuffle
17 |
--------------------------------------------------------------------------------
/src/lua_api/lua_api_utils.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | float lua_get_int_or_float_func(void *L, int stack_idx, const char *field_name, bool nil_ok, const char *func_name);
4 |
5 | #define lua_get_int_or_float(L, stack_idx, field_name) \
6 | lua_get_int_or_float_func(L, stack_idx, field_name, false, __func__)
7 |
8 | #define lua_get_int_or_float_or_nil(L, stack_idx, field_name) \
9 | lua_get_int_or_float_func(L, stack_idx, field_name, true, __func__)
10 |
--------------------------------------------------------------------------------
/src/html/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AlexGames",
3 | "short_name": "AlexGames",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "description": "Play simple games in your browser, alone, with friends on the same device, or with friends over the internet by sharing a link with them.",
7 | "background_color": "#000",
8 | "icons": [
9 | {
10 | "src": "icon/logo.png",
11 | "sizes": "any"
12 | }
13 | ],
14 | "splash_pages": null
15 | }
16 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/cards/cards_set.lua:
--------------------------------------------------------------------------------
1 | local cards_set = {}
2 |
3 | local cards = require("libs/cards/cards")
4 |
5 | function cards_set.card_list_to_set(card_list)
6 | local card_set = {
7 | suits = {},
8 | list = card_list,
9 | }
10 | for _, suit in ipairs(cards.suits) do
11 | card_set.suits[suit] = {}
12 | end
13 |
14 | for _, card in ipairs(card_list) do
15 | card_set.suits[card.suit][card.val] = true
16 | end
17 |
18 | return card_set
19 | end
20 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/crossword_letters/list_right_diffs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 |
4 |
5 | fname1 = sys.argv[1]
6 | fname2 = sys.argv[2]
7 |
8 | words1 = set()
9 | with open(fname1, 'r') as f:
10 | for line in f:
11 | word = line.strip()
12 | words1.add(word)
13 |
14 | print('Words in %s that are not present in %s:' % (fname2, fname1))
15 | with open(fname2, 'r') as f:
16 | for line in f:
17 | word = line.strip()
18 | if word not in words1:
19 | print(word)
20 |
--------------------------------------------------------------------------------
/docker/ws_server/Dockerfile:
--------------------------------------------------------------------------------
1 | # TODO have the ws and http server inherit from a common image
2 | # to avoid duplicating so many dependencies
3 | FROM nginx:latest
4 |
5 | RUN apt-get update && apt-get install -y \
6 | python3 \
7 | python3-pip \
8 | pipx
9 |
10 | RUN python3 -m venv /alexgames_python_venv
11 | ENV PATH="/alexgames_python_venv/bin:$PATH"
12 |
13 | RUN pip3 install websockets
14 |
15 |
16 | WORKDIR /app
17 | COPY . .
18 | ENTRYPOINT [ "python3", "src/server/ws/ws_server.py" ]
19 |
--------------------------------------------------------------------------------
/src/html/js/collapsable.js:
--------------------------------------------------------------------------------
1 |
2 | function init_collapsables() {
3 | console.debug("init_collapsables");
4 | let elems = document.getElementsByClassName("collapsable");
5 | for (let elem of elems) {
6 | elem.addEventListener('click', (e) => {
7 | console.debug("elem", elem, "clicked, toggling collapsable");
8 | if (elem.classList.contains("collapsed")) {
9 | elem.classList.remove("collapsed");
10 | } else {
11 | elem.classList.add("collapsed");
12 | }
13 | });
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tests/saved_state/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(SRC_DIR ../../src)
2 |
3 | # TODO remove this
4 | add_definitions(-DROOT_DIR="\\"\\"")
5 |
6 | add_subdirectory("${SRC_DIR}/" out/alexgames_core)
7 |
8 | add_executable(test_saved_state
9 | test_saved_state_db.cpp)
10 | target_link_libraries(test_saved_state PRIVATE alexgames_core)
11 | target_include_directories(test_saved_state PUBLIC
12 | ${SRC_DIR}/game_api
13 | ${SRC_DIR}/cpp_libs/game_api_helper)
14 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/cpp_libs/sqlite_saved_state/sqlite_saved_state.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #ifdef __cplusplus
4 | extern "C" {
5 | #endif
6 |
7 | void *init_sqlite_saved_state(const char *fname);
8 | int set_value(void *handle, const char *key,
9 | const uint8_t *value, size_t value_len);
10 | int get_value(void *handle, const char *key,
11 | uint8_t *value_out, size_t max_value_len);
12 | void destroy_sqlite_saved_state(void *handle);
13 |
14 |
15 | #ifdef __cplusplus
16 | }
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/rust_games/rust_game_api.h:
--------------------------------------------------------------------------------
1 | #ifndef RUST_GAME_API_H_
2 | #define RUST_GAME_API_H_
3 |
4 | #include "game_api.h"
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | bool rust_game_supported(const char *game_str, size_t game_str_len);
11 |
12 | void *start_rust_game(const char *game_str, size_t game_str_len, const struct game_api_callbacks *callbacks);
13 |
14 | const struct game_api * get_rust_api(void);
15 |
16 | #ifdef __cplusplus
17 | }
18 | #endif
19 |
20 |
21 | #endif /* ifndef GAME_API_H_ */
22 |
--------------------------------------------------------------------------------
/src/cpp_libs/utils/str_eq_literal.h:
--------------------------------------------------------------------------------
1 | // #include
2 |
3 | // The idea is that you can do
4 | // str_eq_literal(arg, "some_str", arg_len)
5 | // and:
6 | // * will stop searching if arg does not contain a null
7 | // * will not match "some" (note strncmp("some", "some_str", len("some")) would match)
8 | // * will even fail if arg contains extra null characters, e.g. "some_str\x00\x00\x00\x00"
9 | #define str_eq_literal(arg, literal, n) \
10 | ((n == sizeof(literal)-1) && memcmp(arg, literal, sizeof(literal)) == 0)
11 |
--------------------------------------------------------------------------------
/src/dictionary/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(dict_inputs build_word_list_w_freq.py wip/vulgar_or_weird_words.txt)
2 | set(dict_output ${CMAKE_SOURCE_DIR}/../out/words-en.txt)
3 |
4 | add_custom_command(
5 | OUTPUT ${dict_output}
6 | COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "Generating words-en.txt"
7 | COMMAND python3 ${PROJECT_ROOT}/src/dictionary/build_word_list_w_freq.py
8 | WORKING_DIRECTORY ${PROJECT_ROOT}
9 | DEPENDS ${dict_inputs}
10 | )
11 |
12 | add_custom_target(
13 | generate_dict_file ALL
14 | DEPENDS ${dict_output}
15 | )
16 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/fragment_local_client_web_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(SRC_DIR "../src")
2 |
3 | add_definitions(-DROOT_DIR=\\"\\")
4 |
5 | add_subdirectory("${SRC_DIR}/" out/alexgames_core)
6 |
7 | add_executable(test_varint
8 | utils/test_varint.cpp)
9 | target_include_directories(test_varint PRIVATE "${SRC_DIR}/cpp_libs/utils")
10 | target_link_libraries(test_varint PRIVATE alexgames_varint)
11 |
12 | add_executable(test_utf8
13 | utils/test_utf8_decode.cpp)
14 | target_include_directories(test_utf8 PRIVATE "${SRC_DIR}/cpp_libs/utils")
15 | target_link_libraries(test_utf8 PRIVATE alexgames_utf8)
16 |
--------------------------------------------------------------------------------
/src/cpp_libs/touch_scroll_handler/touch_scroll_handler.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "game_api.h"
4 |
5 | struct TouchScrollHandlerPoint {
6 | double y;
7 | double x;
8 | };
9 |
10 | class TouchScrollHandler {
11 | public:
12 | struct TouchScrollHandlerPoint handle_touch_evt(const char *evt_id_str, int evt_id_str_len,
13 | void *changed_touches, int changed_touches_len);
14 |
15 | private:
16 | bool active_touch_present = false;
17 | touch_id_t active_touch;
18 | double prev_touch_screen_y_pos;
19 | double prev_touch_screen_x_pos;
20 |
21 | };
22 |
--------------------------------------------------------------------------------
/src/dictionary/dictionary.h:
--------------------------------------------------------------------------------
1 | //typedef int (*create_word_table_t )(void *handle);
2 | typedef int (*add_word_to_list_func_t)(void *handle, int row_idx, int argc, const unsigned char **argv);
3 | //typedef int (*word_table_done_t )(void *handle);
4 |
5 | struct word_callback_data {
6 | void *handle;
7 | //create_word_table_t create_word_table;
8 | add_word_to_list_func_t add_word_to_list_func;
9 | //word_table_done_t word_table_done;
10 | };
11 |
12 | void *init_dict();
13 | void get_words(void *dict_handle, const char *query, struct word_callback_data *data);
14 | void teardown_dict(void *dict_handle);
15 |
--------------------------------------------------------------------------------
/src/rust_games/libs/point.rs:
--------------------------------------------------------------------------------
1 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
2 | pub struct Pt {
3 | pub x: i32,
4 | pub y: i32,
5 | }
6 |
7 | impl Pt {
8 | pub fn add(&self, arg: Pt) -> Pt {
9 | Pt {
10 | y: self.y + arg.y,
11 | x: self.x + arg.x,
12 | }
13 | }
14 |
15 | pub fn mult(&self, arg: i32) -> Pt {
16 | Pt {
17 | y: self.y * arg,
18 | x: self.x * arg,
19 | }
20 | }
21 |
22 | pub fn swap(&self) -> Pt {
23 | Pt {
24 | y: self.x,
25 | x: self.y,
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | http_build_wasm:
4 | build:
5 | context: .
6 | dockerfile: docker/http_server/Dockerfile.build_wasm
7 | volumes:
8 | - ./:/app
9 | http_serve:
10 | image: nginx:latest
11 | volumes:
12 | - ./build/wasm/out/http_out:/usr/share/nginx/html
13 | ports:
14 | - "1234:80"
15 | depends_on:
16 | - http_build_wasm
17 | ws_server:
18 | build:
19 | context: .
20 | dockerfile: docker/ws_server/Dockerfile
21 | ports:
22 | - "55433:55433"
23 |
--------------------------------------------------------------------------------
/src/android/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/drawable/ic_stop.xml:
--------------------------------------------------------------------------------
1 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/util/StringFuncs.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.util;
2 |
3 | public class StringFuncs {
4 | public static String byteary_to_nice_str(byte[] ary, int msg_len) {
5 | StringBuilder stringBuilder = new StringBuilder();
6 | stringBuilder.append("[");
7 | for (int i=0; i= msg_len) { break; }
9 | if (i != 0) { stringBuilder.append(","); }
10 | stringBuilder.append(String.format(" %02x", ary[i]));
11 | }
12 | stringBuilder.append("]");
13 | return stringBuilder.toString();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/cpp_libs/touch_press_handler/touch_press_handler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "game_api.h"
3 |
4 | #include
5 |
6 | class TouchPress {
7 | public:
8 | static TouchPress NoTouch();
9 | static TouchPress Touch(float y, float x);
10 | bool pressed;
11 | float y;
12 | float x;
13 | };
14 |
15 | class TouchPressHandler {
16 | public:
17 | TouchPress handle_touch_evt(std::string evt_id_str,
18 | const struct touch_info *changed_touches,
19 | int changed_touches_len);
20 |
21 | private:
22 | bool active_touch_present = false;
23 | struct touch_info active_touch;
24 | int max_touch_move = 20;
25 | };
26 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/navigation/server_monitoring_nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/src/cpp_libs/saved_state_db/saved_state_db_c_api.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifdef __cplusplus
4 | extern "C" {
5 | #endif
6 |
7 | #include "game_api.h"
8 |
9 | void *saved_state_db_init(void *L, const struct game_api_callbacks *callbacks);
10 | void saved_state_db_save_state(void *handle, const char *game_id, int session_id, const uint8_t *state, size_t state_len);
11 | int saved_state_db_get_new_session_id(void *handle);
12 | int saved_state_db_get_last_session_id(void *handle, const char *game_id);
13 | bool saved_state_db_has_saved_state_offset(void *handle, int session_id, int move_id_offset);
14 | int saved_state_db_get_saved_state_offset(void *handle, int session_id, int move_id_offset, uint8_t *state, size_t state_len);
15 |
16 |
17 |
18 | #ifdef __cplusplus
19 | }
20 | #endif
21 |
--------------------------------------------------------------------------------
/src/server/socket/test/test_client.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "socket_server.h"
4 |
5 | static const int port = 5678;
6 |
7 | int main(void) {
8 | void *handle;
9 | printf("Connecting to server on port %d\n", port);
10 | int rc = join_server("127.0.0.1", port, &handle);
11 |
12 | if (rc != 0) {
13 | printf("Unable to join server, rc=%d\n", rc);
14 | return -1;
15 | }
16 |
17 | char buff[1024];
18 | size_t bytes_recvd = 0;
19 | recv_msg(handle, sizeof(buff), buff, &bytes_recvd);
20 |
21 | printf("Recvd msg from server: %.*s\n", bytes_recvd, buff);
22 |
23 | for (int i=0; i<10; i++) {
24 | int msg_len = snprintf(buff, sizeof(buff), "Hello from client msg %d", i);
25 | send_msg(handle, buff, msg_len);
26 | sleep(1);
27 | }
28 |
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/src/html/css/style_collapsable.css:
--------------------------------------------------------------------------------
1 | .collapsable:hover, .toggle_collapsable_btn:hover {
2 | cursor: pointer;
3 | }
4 |
5 | .toggle_collapsable_btn {
6 | text-decoration: underline;
7 | }
8 |
9 | .toggle_collapsable_btn.content_collapsed:before {
10 | content: "(Expand)"
11 | }
12 | .toggle_collapsable_btn:not(.content_collapsed):before {
13 | content: "(Collapse)"
14 | }
15 |
16 | .collapsed {
17 | display: inline-block;
18 | inline-size: 400px;
19 | word-break: break-all;
20 | overflow-inline: hidden;
21 | white-space: nowrap;
22 | text-overflow: ellipsis;
23 | color: #888888;
24 | overflow: hidden;
25 | }
26 |
27 | /* TODO not sure how to make this work */
28 | .collapsed:after {
29 | content: 'Click to expand';
30 | }
31 |
32 | .toggle_collapsable.collapsed {
33 | display: none;
34 | }
35 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/graphics/IAlexGamesCanvas.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.graphics;
2 |
3 | public interface IAlexGamesCanvas {
4 | void draw_graphic(String img_id, int y, int x, int width, int height, int angle_degrees);
5 | void draw_line(String colour, int line_size, int y1, int x1, int y2, int x2);
6 | void draw_text(String text, String colour, int y, int x, int size, int align);
7 |
8 | void draw_rect(String colour, int y_start, int x_start, int y_end, int x_end);
9 |
10 | void draw_circle(String fill_colour, String outline_colour, int y, int x, int radius);
11 |
12 | void draw_clear();
13 |
14 | float getScale();
15 |
16 | // TODO remove
17 | boolean post(Runnable r);
18 |
19 | void draw_refresh();
20 | }
21 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/AlexGamesViewModel.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames;
2 |
3 | import androidx.lifecycle.LiveData;
4 | import androidx.lifecycle.MutableLiveData;
5 | import androidx.lifecycle.ViewModel;
6 |
7 | public class AlexGamesViewModel extends ViewModel {
8 | private MutableLiveData game_selected;
9 |
10 | public void setGameId(String game_id) {
11 | if (game_selected == null) {
12 | game_selected = new MutableLiveData<>();
13 | }
14 | game_selected.setValue(game_id);
15 | }
16 |
17 | public String getGameId() {
18 | if (game_selected != null) {
19 | return game_selected.getValue();
20 | } else {
21 | return "minesweeper";
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lua_api/lua_api.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #ifndef LUA_API_H_
7 | #define LUA_API_H_
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | #include "game_api.h"
14 |
15 | #define UPLOADED_GAME_MAIN_FILE "game.lua"
16 |
17 | extern const struct game_api lua_game_api;
18 | void *start_lua_game(const struct game_api_callbacks *api_callbacks, const char *game_path);
19 |
20 | // TODO maybe remove this one?
21 | void *init_lua_game(const struct game_api_callbacks *api_callbacks_arg,
22 | const char *lua_fpath);
23 | void destroy_lua_game(void *L);
24 |
25 | const char *get_lua_game_path(const char *game_id, size_t game_id_len);
26 |
27 |
28 | #ifdef __cplusplus
29 | }
30 | #endif
31 |
32 |
33 | #endif /* LUA_API_H_ */
34 |
--------------------------------------------------------------------------------
/src/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 |
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:7.4.2'
12 | classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10'
13 |
14 |
15 | // NOTE: Do not place your application dependencies here; they belong
16 | // in the individual module build.gradle files
17 | }
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | jcenter()
24 | mavenCentral()
25 |
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/tests/go/go_tests.lua:
--------------------------------------------------------------------------------
1 | go = require("src/lua_scripts/games/go/go")
2 |
3 | -- A game that Sabrina and I played on 2021-05-11
4 | -- my understanding is that I (1) control 46 territory and she (2) controls 35.
5 | -- It seems non trivial to determine this though.
6 | -- Maybe in our game it is fairly simple, we only have a few
7 | -- groups of points in each other's territory, and all of those ones
8 | -- have limited liberties that could probably be rulled out programatically.
9 | board = {
10 | {1, 1, 1, 1, 1, 1, 0, 1, 0},
11 | {2, 1, 2, 1, 2, 1, 2, 1, 0},
12 | {2, 2, 2, 2, 2, 1, 1, 1, 0},
13 | {2, 1, 0, 2, 2, 2, 1, 0, 1},
14 | {1, 1, 1, 2, 1, 1, 1, 1, 1},
15 | {2, 1, 0, 2, 1, 0, 1, 0, 1},
16 | {2, 2, 2, 2, 1, 0, 1, 0, 0},
17 | {0, 2, 0, 2, 2, 1, 1, 0, 2},
18 | {2, 0, 2, 2, 1, 1, 1, 1, 1},
19 | }
20 |
21 | go.print_board(board)
22 |
--------------------------------------------------------------------------------
/src/android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/server/socket/socket_server.h:
--------------------------------------------------------------------------------
1 | #ifdef __cplusplus
2 | extern "C" {
3 | #endif
4 |
5 | #include
6 | #include
7 |
8 | int network_init(void);
9 |
10 | int join_server(const char *addr, int port, void **handle_out);
11 |
12 | /**
13 | * call this once to setup a server socket
14 | */
15 | int host_server(int port, void **server_handle_out);
16 |
17 | /**
18 | * call this in a loop to handle client connctions to server socket
19 | */
20 | int wait_for_connections(const void *server_handle, void **client_handle_out);
21 |
22 | int send_msg(void *handle, const uint8_t *msg, size_t msg_size);
23 | int recv_msg(void *handle, size_t max_msg_size, uint8_t *msg, size_t *msg_size);
24 |
25 | void get_client_name(void *handle, const char *name_out, size_t max_name_len, size_t *name_len_out);
26 |
27 | #ifdef __cplusplus
28 | }
29 | #endif
30 |
--------------------------------------------------------------------------------
/tests/chess/chess_test.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 |
3 | package.path = 'src/lua_scripts/?.lua'
4 |
5 | local core = require("games/chess/chess_core")
6 |
7 | local state = {
8 | player_turn = core.PLAYER_WHITE,
9 | board = {
10 | { 8, 9, 10, 11, 0, 10, 9, 8 },
11 | { 7, 7, 7, 7, 7, 0, 7, 7 },
12 | { 0, 0, 0, 0, 0, 0, 0, 0 },
13 | { 0, 0, 0, 0, 12, 0, 0, 5 },
14 | { 0, 0, 0, 0, 0, 0, 0, 0 },
15 | { 0, 0, 0, 0, 0, 0, 0, 0 },
16 | { 1, 1, 1, 1, 0, 1, 1, 1 },
17 | { 2, 3, 4, 0, 6, 4, 3, 2 },
18 | },
19 | }
20 |
21 | -- core.print_state(state)
22 |
23 | --local white_in_check = core.in_check(state, core.PLAYER_WHITE)
24 | --print(string.format("white_in_check: %s", white_in_check))
25 |
26 | local black_in_check = core.in_check(state, core.PLAYER_BLACK)
27 | print(string.format("black_in_check: %s", black_in_check))
28 |
--------------------------------------------------------------------------------
/src/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/sudoku/sudoku_main.lua:
--------------------------------------------------------------------------------
1 |
2 | local core = require("games/sudoku/sudoku_core")
3 | local draw = require("games/sudoku/sudoku_draw")
4 |
5 | local ui_state = draw.init(480, 480)
6 | local state = core.new_game()
7 |
8 | function update()
9 | draw.draw_state(state, ui_state)
10 | end
11 |
12 | function handle_user_clicked(pos_y, pos_x)
13 | local cell = draw.get_cell_coords(pos_y, pos_x)
14 | if cell ~= nil then
15 | print("user clicked: " .. cell.y .. ", " .. cell.x)
16 | draw.handle_user_sel(ui_state, cell)
17 | end
18 |
19 |
20 | local num_choice = draw.get_num_choice(ui_state, pos_y, pos_x)
21 | if num_choice ~= nil and ui_state.selected ~= nil then
22 | print("user chose ", num_choice)
23 | core.user_enter(state, ui_state.selected.y, ui_state.selected.x, num_choice)
24 | end
25 |
26 | update()
27 |
28 | end
29 |
30 | function start_game()
31 | end
32 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/go/go_ctrl.lua:
--------------------------------------------------------------------------------
1 | local go_ctrl = {}
2 | -- This file should contain the state for things like deciding
3 | -- if players have been chosen yet (whether the player choice UI should be shown),
4 | -- and what player you are
5 |
6 | function go_ctrl.new_state()
7 | return {
8 | player_choice = nil,
9 | other_player_choice = nil,
10 | }
11 | end
12 |
13 | function go_ctrl.player_chosen(ctrl_state, player_idx)
14 | print(string.format("Storing player choice of %q", player_idx))
15 | ctrl_state.player_choice = player_idx
16 | end
17 |
18 | function go_ctrl.other_player_chosen(ctrl_state, player_idx)
19 | ctrl_state.other_player_choice = player_idx
20 | end
21 |
22 | function go_ctrl.get_player(ctrl_state)
23 | return ctrl_state.player_choice
24 | end
25 |
26 | function go_ctrl.get_other_player(ctrl_state)
27 | return ctrl_state.other_player_choice
28 | end
29 |
30 | return go_ctrl
31 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/draw/draw_colours.lua:
--------------------------------------------------------------------------------
1 | local draw_colours = {}
2 |
3 | -- highlight is bright yellow, useful for a "can click here" move
4 | -- alt highlight is blue (useful for highlighting a selected piece, where the
5 | -- yellow highlight is used to show possible destinations)
6 | --
7 | -- "..._remote" variants are for network multiplayer, to show what the
8 | -- other player is doing.
9 |
10 | draw_colours.HIGHLIGHT_OUTLINE = '#ffff44'
11 | draw_colours.HIGHLIGHT_FILL = '#ffff9966'
12 |
13 | draw_colours.ALT_HIGHLIGHT_OUTLINE = '#00ffff'
14 | draw_colours.ALT_HIGHLIGHT_FILL = '#00ffff88'
15 |
16 | draw_colours.HIGHLIGHT_OUTLINE_REMOTE = '#88885588'
17 | draw_colours.HIGHLIGHT_FILL_REMOTE = '#ffffcc88'
18 |
19 | draw_colours.ALT_HIGHLIGHT_OUTLINE_REMOTE = '#88cccc88'
20 | draw_colours.ALT_HIGHLIGHT_FILL_REMOTE = '#88cccc88'
21 |
22 |
23 | return draw_colours
24 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/ui/show_buttons_popup.lua:
--------------------------------------------------------------------------------
1 | local show_buttons_popup = {}
2 |
3 | local alexgames = require("alexgames")
4 |
5 | -- This shows a popup with a single message and 0 to many buttons.
6 | --
7 | -- This is originally how the show_popup API worked, so I'm adding
8 | -- this API for compatibility, rather than changing all the old
9 | -- games to use the new API.
10 | function show_buttons_popup.show_popup(popup_id, title, msg, btn_ary)
11 | local info = {
12 | title = title,
13 | items = {},
14 | }
15 |
16 | table.insert(info.items, {
17 | item_type = alexgames.POPUP_ITEM_TYPE_MSG,
18 | msg = msg,
19 | })
20 |
21 | for btn_id, btn_text in ipairs(btn_ary) do
22 | table.insert(info.items, {
23 | item_type = alexgames.POPUP_ITEM_TYPE_BTN,
24 | text = btn_ary[btn_id],
25 | id = (btn_id - 1),
26 | })
27 | end
28 |
29 | alexgames.show_popup(popup_id, info)
30 | end
31 |
32 | return show_buttons_popup
33 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/serialize/storage_helpers.lua:
--------------------------------------------------------------------------------
1 | local storage_helpers = {}
2 |
3 | local utils = require("libs/utils")
4 |
5 | local alexgames = require("alexgames")
6 |
7 | function storage_helpers.store_bool(key, val)
8 | if type(val) ~= 'boolean' then
9 | error(string.format("Expected arg val to be type boolean, was %s", type(val)),2)
10 | end
11 |
12 | data = { utils.boolean_to_number(val) }
13 |
14 | alexgames.store_data(key, data)
15 | end
16 |
17 | function storage_helpers.read_bool(key, default_val)
18 | local data = alexgames.read_stored_data(key)
19 |
20 | if data == nil then
21 | return default_val
22 | end
23 |
24 | if #data ~= 1 then
25 | error(string.format("Expected a single byte when reading stored value %s, received %d bytes", key, #data))
26 | end
27 |
28 | local val = string.byte(data:sub(1,1))
29 | print(string.format("val = %s", val))
30 |
31 | return utils.number_to_boolean(val)
32 | end
33 |
34 | return storage_helpers
35 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/wu/wu_ctrl.lua:
--------------------------------------------------------------------------------
1 | local wu_ctrl = {}
2 | -- This file should contain the state for things like deciding
3 | -- if players have been chosen yet (whether the player choice UI should be shown),
4 | -- and what player you are
5 |
6 | function wu_ctrl.new_state()
7 | return {
8 | player_choice = nil,
9 | other_player_choice = nil,
10 | }
11 | end
12 |
13 | function wu_ctrl.player_chosen(ctrl_state, player_idx)
14 | print(string.format("Storing player choice of %q", player_idx))
15 | ctrl_state.player_choice = player_idx
16 | end
17 |
18 | function wu_ctrl.other_player_chosen(ctrl_state, player_idx)
19 | print(string.format("Storing other player choice of %q", player_idx))
20 | ctrl_state.other_player_choice = player_idx
21 | end
22 |
23 | function wu_ctrl.get_player(ctrl_state)
24 | return ctrl_state.player_choice
25 | end
26 |
27 | function wu_ctrl.get_other_player(ctrl_state)
28 | return ctrl_state.other_player_choice
29 | end
30 |
31 | return wu_ctrl
32 |
--------------------------------------------------------------------------------
/src/ui_wxWidgets/wx_network_ui.h:
--------------------------------------------------------------------------------
1 | #include "wx/wx.h"
2 | #include "wx/defs.h"
3 | #include "wx/sizer.h"
4 | #include "wx/popupwin.h"
5 |
6 | typedef void (*host_server_callback_t)(const char *server_addr);
7 | typedef void (*join_server_callback_t)(const char *server_addr);
8 |
9 | class NetworkPopup : public wxDialog {
10 | public:
11 | NetworkPopup(wxFrame *parent);
12 | void set_host_server_callback(host_server_callback_t callback);
13 | void set_join_server_callback(join_server_callback_t callback);
14 | void set_default_port(int port);
15 |
16 | protected:
17 | void OnButton(wxCommandEvent& event);
18 |
19 | private:
20 | wxTextCtrl join_server_addr_input;
21 | wxButton join_server_btn;
22 |
23 | wxTextCtrl host_server_addr_input;
24 | wxButton host_server_btn;
25 |
26 | host_server_callback_t host_server_callback = nullptr;
27 | join_server_callback_t join_server_callback = nullptr;
28 | int default_port = 0;
29 |
30 | wxDECLARE_EVENT_TABLE();
31 | };
32 |
--------------------------------------------------------------------------------
/src/cpp_libs/mouse_scroll_handler/mouse_scroll_handler.cpp:
--------------------------------------------------------------------------------
1 | #include "mouse_scroll_handler.h"
2 |
3 |
4 | int MouseScrollHandler::handle_mousemove(int pos_y, int pos_x, int buttons) {
5 | if (this->mouse_left) {
6 | if (buttons & 1) {
7 | this->mouse_left = false;
8 | this->last_mouse_y = pos_y;
9 | } else {
10 | this->mouse_down = false;
11 | this->mouse_left = false;
12 | }
13 | }
14 |
15 | if (this->mouse_down) {
16 | int diff = pos_y - this->last_mouse_y;
17 | this->last_mouse_y = pos_y;
18 | return diff;
19 | } else {
20 | return 0;
21 | }
22 | }
23 |
24 | void MouseScrollHandler::handle_mouse_evt(int mouse_evt_id, int pos_y, int pos_x) {
25 | if (mouse_evt_id == MOUSE_EVT_DOWN) {
26 | this->mouse_left = false;
27 | this->mouse_down = true;
28 | this->last_mouse_y = pos_y;
29 | } else if (mouse_evt_id == MOUSE_EVT_UP) {
30 | this->mouse_down = false;
31 | } else if (mouse_evt_id == MOUSE_EVT_LEAVE) {
32 | this->mouse_left = true;
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/cards/card_test.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | local cards_draw = require("libs/cards/cards_draw")
4 |
5 | local canvas_width = 480
6 | local canvas_height = 480
7 |
8 | local card_width = 40
9 | local card_height = 70
10 | local font_size = 24
11 | local padding = 5
12 |
13 | if false then
14 | card_width = 70
15 | card_height = 120
16 | font_size = 48
17 | padding = 5
18 | end
19 |
20 | cards_draw.draw_facedown_card(padding, padding, card_width, card_height)
21 |
22 | local deck2 = cards.new_deck()
23 | cards.shuffle(deck2)
24 |
25 |
26 | local dx = card_width + padding
27 | local dy = card_height + padding
28 |
29 | local y = padding
30 | local x = padding + dx
31 |
32 | for i, card in ipairs(deck2) do
33 |
34 |
35 | print("Drawing card " .. cards.card_to_string(card))
36 | cards_draw.draw_card(card, y, x, card_width, card_height, font_size)
37 |
38 | x = x + dx
39 |
40 | if x + card_width + padding >= canvas_width then
41 | x = padding
42 | y = y + dy
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/content_server_monitoring.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Docker Build (WASM)
2 |
3 | on:
4 | pull_request:
5 | types:
6 | - opened
7 | - synchronize
8 | - reopened
9 |
10 | jobs:
11 |
12 |
13 | deploy:
14 | runs-on: ubuntu-22.04
15 |
16 | permissions:
17 | contents: write
18 |
19 | steps:
20 |
21 | - name: Checkout
22 | uses: actions/checkout@v3
23 |
24 | - name: Setup docker buildx
25 | uses: docker/setup-buildx-action@v1
26 |
27 | - name: Build main AlexGames docker image (get build dependencies)
28 | run: |
29 | docker build -t alexgames_build_wasm \
30 | --build-arg ALEXGAMES_BUILD_TYPE_LABEL=github-pages-main-build-only \
31 | -f docker/http_server/Dockerfile.build_wasm \
32 | .
33 |
34 | - name: Build main AlexGames static HTML via docker
35 | run: |
36 | docker run --rm \
37 | --build-arg ALEXGAMES_BUILD_TYPE_LABEL=github-pages-main-build-only \
38 | -v $(pwd):/app \
39 | alexgames_build_wasm
40 |
--------------------------------------------------------------------------------
/src/dictionary/wip/words_to_remove.txt:
--------------------------------------------------------------------------------
1 | # These are words that seem to be in the dictionary that I'm using, but don't
2 | # really seem like words that should even be accepted as guesses.
3 | # For words that are valid words but shouldn't show up as puzzles due to being
4 | # vulgar or weird, add them to `vulgar_or_weird_words.txt`
5 |
6 | tho
7 | soho
8 | est
9 | les
10 | ted
11 | tory
12 | troy
13 | cory
14 | tron
15 | shri
16 | tong
17 | ting
18 | tung
19 | las
20 | conte
21 | coven
22 | rhea
23 | rhine
24 | bree
25 | mona
26 | situ
27 | heres
28 | rees
29 | vera
30 | barre
31 | sahib
32 | nah
33 | san
34 | shan
35 | tel
36 | ooh
37 | org
38 | tor
39 | cor
40 | ryu
41 | roc
42 | sri
43 | ish
44 | uni
45 | lays
46 | franco
47 | conf
48 | offs
49 | rna
50 | fra
51 | eros
52 | lis
53 | ism
54 | emo
55 | alf
56 | hes
57 | hoo
58 | eth
59 | sho
60 | ute
61 | acer
62 | rec
63 | ren
64 | dae
65 | ard
66 | ave
67 | vee
68 | sos
69 | dui
70 | dun
71 | gnu
72 | din
73 | ser
74 | kay
75 | res
76 | ave
77 | hon
78 | ins
79 | theres
80 | carmen
81 | aero
82 | hart
83 | hale
84 | cert
85 | eric
86 |
--------------------------------------------------------------------------------
/src/cpp_libs/saved_state_db/README.md:
--------------------------------------------------------------------------------
1 | # Saved State DB
2 |
3 | This library allows games to blindly call a method that stores game state (as a bytearray) over and over in a data structure that handles moving between previous states (e.g. undo and redo buttons).
4 |
5 | It uses the these APIs defined in `game_api.h`:
6 | * `store_data(string key, byte[] data)`: write data (bytearray), referenced by key (string).
7 | * `byte[] read_stored_data(string key)`: read data stored at key.
8 |
9 | It provides new APIs used by games (or Lua bindings):
10 | * `int get_new_session_id()`: meant to be called by a game at the beginning of a new game session. This ID is used to group saved states together.
11 | * `save_state(int session_id, byte[] state)`: games can call repeatedly every time the player makes a significant move. The library should automatically store the state in a data structure that makes it easy to access later.
12 | * `bool has_saved_state_offset(int session_id, int move_id_offset)`:
13 | * `byte[] adjust_saved_state_offset(int session_id, int move_id_offset)`
14 |
15 | TODO: finish this
16 |
--------------------------------------------------------------------------------
/docker/http_server/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # I needed to run this when running docker desktop on macOS:
4 | #
5 | # docker pull nginx:latest
6 | #
7 | # But I don't remember having to do this on linux docker cli installed
8 | # from the package manager.
9 |
10 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
11 | cd "${DIR}/../../"
12 |
13 | DOCKER_TAG=alexgames_http_build
14 |
15 | set -eux
16 |
17 | # Change this to remove the old image
18 | if [ 1 -eq 0 ]; then
19 | prev_img_id=$(docker images -q ${DOCKER_TAG})
20 | if [ -n "${prev_img_id}" ]; then
21 | echo "Removing previous image ${prev_img_id}"
22 | sudo docker rmi "${prev_img_id}"
23 | fi
24 | fi
25 |
26 | prev_img_id=$(docker images -q ${DOCKER_TAG})
27 | if [ -z "${prev_img_id}" ]; then
28 |
29 | sudo docker build -t "${DOCKER_TAG}" \
30 | -f docker/http_server/Dockerfile.build_wasm \
31 | .
32 | img_id=$(docker images -q ${DOCKER_TAG})
33 |
34 | echo "Successfully built docker image ${DOCKER_TAG} to image id ${img_id}"
35 | fi
36 |
37 | sudo docker run \
38 | --rm \
39 | -v $(pwd):/app \
40 | "${DOCKER_TAG}"
41 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/chess/chess_serialize.lua:
--------------------------------------------------------------------------------
1 | local serialize = {}
2 |
3 | local core = require("games/chess/chess_core")
4 | local serialize_lib = require("libs/serialize/serialize")
5 |
6 | function serialize.deserialize_state(byte_str)
7 | local bytes = serialize_lib.bytestr_to_byteary(byte_str)
8 | local state = {}
9 | state.player_turn = serialize_lib.deserialize_byte(bytes)
10 | state.board = {}
11 | state.selected = nil
12 | for y=1,core.BOARD_SIZE do
13 | state.board[y] = {}
14 | for x=1,core.BOARD_SIZE do
15 | state.board[y][x] = serialize_lib.deserialize_byte(bytes)
16 | end
17 | end
18 |
19 | if #bytes ~= 0 then
20 | error(string.format("%d bytes remaining after deserializing", #bytes))
21 | end
22 |
23 | return state
24 | end
25 |
26 | function serialize.serialize_state(state)
27 | local output = ""
28 | output = output .. serialize_lib.serialize_byte(state.player_turn)
29 | for y=1,core.BOARD_SIZE do
30 | for x=1,core.BOARD_SIZE do
31 | output = output .. serialize_lib.serialize_byte(state.board[y][x])
32 | end
33 | end
34 |
35 | return output
36 | end
37 |
38 | return serialize
39 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/server_monitor_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/crossword_letters/list_puzzle_words.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | package.path = 'src/lua_scripts/?.lua'
3 |
4 | local puzzles = require("games/crossword_letters/crossword_letters_puzzles")
5 |
6 | local words_list = {}
7 | local words_count = {}
8 |
9 | for _, puzzle in ipairs(puzzles.puzzles) do
10 | for _, word_pos_info in ipairs(puzzle.word_positions) do
11 | local word = word_pos_info.word
12 | if not words_count[word] then
13 | table.insert(words_list, word)
14 | words_count[word] = 1
15 | else
16 | words_count[word] = words_count[word] + 1
17 | end
18 | end
19 | end
20 |
21 | --[[
22 | for word, count in pairs(words_count) do
23 | if count > 1 then
24 | print(string.format("Found word %-8s %d times", word, count))
25 | end
26 | end
27 | --]]
28 |
29 |
30 | local bad_words_list = {
31 | }
32 |
33 | local bad_words_set = {}
34 |
35 | for _, word in ipairs(bad_words_list) do
36 | bad_words_set[word] = true
37 | end
38 |
39 | for _, word in ipairs(words_list) do
40 | if bad_words_set[word] then
41 | goto next_word
42 | end
43 | print(string.format("%-6s", word))
44 | ::next_word::
45 | end
46 |
--------------------------------------------------------------------------------
/local_env.cmake:
--------------------------------------------------------------------------------
1 | # paths to where external dependencies are on your computer
2 | # I've changed this project to simply download its dependencies
3 | # so that you may not even need to do anything here.
4 |
5 | # I do this so I can build from WSL or windows command line.
6 | # It is fine to omit the "IF" entirely and just specify a single
7 | # value for each variable
8 | if(WIN32)
9 | #set(LUA_SRC_DIR C:/misc/lua_build/lua-5.4.3/src)
10 |
11 | # Uhh so all of this works fine on my linux desktop, I guess CMake is able to find it?
12 | # And trying to overwrite these variables must do nothing?
13 |
14 | # SET(wxWidgets_ROOT_DIR 'C:/misc/wx_test')
15 | #SET(wxWidgets_ROOT_DIR C:/misc/wx_test/)
16 | #SET(wxWidgets_LIB_DIR C:/misc/wx_test/lib/vc_lib)
17 |
18 | # I might have needed these when I built using visual studio
19 | # instead of msbuild, but I'm not sure
20 | #SET(wxWidgets_LIBRARIES C:/misc/wx_test/lib)
21 | #SET(wxWidgets_INCLUDE_DIRS C:/misc/wx_text/)
22 |
23 | # SET(wxWidgets_ROOT_DIR 'C:\\misc\\wx_test\\build\\vc_mswud')
24 | set(wxWidgets_CONFIGURATION mswud)
25 |
26 | else()
27 | #set(LUA_SRC_DIR "/home/alex/repo/lua/lua-5.4.3/src")
28 | endif()
29 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/blue/blue_main.lua:
--------------------------------------------------------------------------------
1 |
2 | --[[
3 | -- TODO:
4 | -- * draw player names (or just "Player 1" for now) by each game card
5 | -- * change player turn
6 | -- * on end of turn, commit pieces from staging area to card if possible, calculate points
7 | -- * implement state serialization for network multiplayer
8 | -- * use save state API
9 | --]]
10 |
11 |
12 | local ui = require("games/blue/blue_ui")
13 | local core = require("games/blue/blue_core")
14 | local draw = require("games/blue/blue_draw")
15 |
16 | local g_game_state = core.new_game(4)
17 | local g_ui_state = ui.new_state(g_game_state)
18 |
19 | local function get_player()
20 | return 1 -- TODO
21 | end
22 |
23 | function update()
24 | draw.draw_state(g_ui_state, get_player())
25 | end
26 |
27 | function handle_user_clicked(y_pos, x_pos)
28 | local click_info = draw.pos_to_action(g_ui_state, y_pos, x_pos)
29 | if click_info ~= nil then
30 | print(string.format("User clicked { action=%s, arg=%s }", click_info.action, click_info.action_arg_idx))
31 | local rc = ui.handle_action(g_ui_state, get_player(), click_info.action, click_info.action_arg_idx)
32 | update()
33 | end
34 | end
35 |
36 |
--------------------------------------------------------------------------------
/src/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/life/life_draw.lua:
--------------------------------------------------------------------------------
1 | local alexgames = require("alexgames")
2 |
3 | local lua_draw = {}
4 |
5 | local cell_size_y = nil
6 | local cell_size_x = nil
7 |
8 | local present_colour = '#000000'
9 | local absent_colour = '#ffffff'
10 |
11 | if alexgames.get_user_colour_pref() == "dark" then
12 | present_colour = '#888888'
13 | absent_colour = '#000000'
14 | end
15 |
16 | function lua_draw.init(cell_size)
17 | cell_size_y = cell_size
18 | cell_size_x = cell_size
19 | end
20 |
21 | function lua_draw.update(board)
22 | alexgames.draw_clear()
23 | for y=1,#board do
24 | for x=1,#board[y] do
25 | local fill_colour
26 | if board[y][x] ~= 0 then
27 | fill_colour = present_colour
28 | else
29 | fill_colour = absent_colour
30 | end
31 | alexgames.draw_rect(fill_colour,
32 | (y-1)*cell_size_y, (x-1)*cell_size_x,
33 | y * cell_size_y, x * cell_size_x)
34 | end
35 | end
36 | alexgames.draw_refresh()
37 | end
38 |
39 | function lua_draw.coords_to_cell_idx(coords_y, coords_x)
40 | return { y = 1 + math.floor(coords_y/cell_size_y),
41 | x = 1 + math.floor(coords_x/cell_size_x) }
42 | end
43 |
44 | return lua_draw
45 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/fragment_first.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
--------------------------------------------------------------------------------
/src/rust_games/gem_match/gem_match_serialize.rs:
--------------------------------------------------------------------------------
1 | use crate::gem_match::gem_match_core::State;
2 |
3 | use bincode;
4 |
5 | pub const VERSION: u8 = 1;
6 |
7 | pub enum Error {
8 | UnhandledVersion(u8),
9 | SerdeError(bincode::Error),
10 | }
11 |
12 | pub fn serialize(state: State) -> Result, bincode::Error> {
13 | let mut serialized_state = match bincode::serialize(&state) {
14 | Ok(state_encoded) => state_encoded,
15 | Err(e) => {
16 | return Err(e);
17 | }
18 | };
19 |
20 | serialized_state.insert(0, VERSION);
21 |
22 | return Ok(serialized_state);
23 | }
24 |
25 | pub fn deserialize(serialized_state: &Vec) -> Result {
26 | let mut serialized_state = serialized_state.clone();
27 | let version = serialized_state.remove(0);
28 |
29 | if version != VERSION {
30 | return Err(Error::UnhandledVersion(version));
31 | }
32 |
33 | let deserialize_result = bincode::deserialize::(&serialized_state);
34 | match deserialize_result {
35 | Ok(state) => {
36 | return Ok(state);
37 | }
38 | Err(bincode) => {
39 | return Err(Error::SerdeError(bincode));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/html/js/url_args.js:
--------------------------------------------------------------------------------
1 | var URL_args = function () {
2 | var query_string = {};
3 | var query = window.location.search.substring(1);
4 | var vars = query.split("&");
5 | for (var i=0;i possibleClickTouches = new HashMap<>();
20 |
21 | public TouchInfo handleTouchEvt(MotionEvent event) {
22 | TouchInfo click = null;
23 | if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
24 | possibleClickTouches.put(event.getActionIndex(), new TouchInfo(event.getY(), event.getX()));
25 | } else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
26 | possibleClickTouches.remove(event.getActionIndex());
27 | } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
28 | if (possibleClickTouches.containsKey(event.getActionIndex())) {
29 | click = possibleClickTouches.remove(event.getActionIndex());
30 | }
31 | }
32 | return click;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/game_api/game_api_words.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "game_api_words.h"
4 |
5 | #include "c_dictionary.h"
6 |
7 | static const struct game_dict_api *g_dict_api = NULL;
8 |
9 | struct word_query_params get_default_params(void) {
10 | struct word_query_params params = {
11 | .min_length = 0,
12 | .max_length = 99,
13 | .min_freq = 0e0,
14 | .include_weird_or_vulgar = false,
15 | };
16 |
17 | return params;
18 | }
19 |
20 |
21 | void set_game_dict_api(const struct game_dict_api *dict_api) {
22 | g_dict_api = dict_api;
23 | }
24 |
25 | const struct game_dict_api *get_game_dict_api(void) {
26 | if (g_dict_api != NULL) {
27 | printf("[dict] get_game_dict_api returning dict pointer set by set_game_dict_api\n");
28 | return g_dict_api;
29 | } else {
30 | #ifdef ALEXGAMES_C_DICT_NOT_INCLUDED
31 | fprintf(stderr, "WARNING: get_game_dict_api() called without being set "
32 | "by calling set_game_dict_api. Normally this would cause "
33 | "the C dictionary implementation to be used, but it is "
34 | "likely not linked in because ALEXGAMES_C_DICT_NOT_INCLUDED "
35 | "is set.\n");
36 | return NULL;
37 | #else
38 | printf("[dict] get_game_dict_api returning default C implementation\n");
39 | return get_c_dictionary_api();
40 | #endif
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/touch_to_mouse_evts.lua:
--------------------------------------------------------------------------------
1 | local touch_to_mouse_evts = {}
2 |
3 | local alexgames = require("alexgames")
4 |
5 | function touch_to_mouse_evts.init(funcs)
6 | local state = {
7 | active_touch_id = nil,
8 | handle_mouse_evt = funcs.handle_mouse_evt,
9 | handle_mousemove = funcs.handle_mousemove,
10 | }
11 | alexgames.enable_evt("touch")
12 | return state
13 | end
14 |
15 | function touch_to_mouse_evts.handle_touch_evt(state, evt_id, changed_touches)
16 | local params = {
17 | is_touch = true,
18 | }
19 | for _, touch in ipairs(changed_touches) do
20 | local y = math.floor(touch.y)
21 | local x = math.floor(touch.x)
22 | if state.active_touch == touch.id then
23 | if evt_id == 'touchmove' then
24 | state.handle_mousemove(y, x)
25 | elseif evt_id == 'touchend' then
26 | state.handle_mouse_evt(alexgames.MOUSE_EVT_UP, y, x, params)
27 | state.active_touch = nil
28 | elseif evt_id == 'touchcancel' then
29 | state.handle_mouse_evt(alexgames.MOUSE_EVT_DOWN, y, x, params)
30 | state.active_touch = nil
31 | end
32 | end
33 |
34 | if evt_id == 'touchstart' then
35 | if state.active_touch == nil then
36 | state.active_touch = touch.id
37 | state.handle_mouse_evt(alexgames.MOUSE_EVT_DOWN, y, x, params)
38 | end
39 | end
40 | end
41 |
42 | end
43 |
44 | return touch_to_mouse_evts
45 |
--------------------------------------------------------------------------------
/src/rust_games/README.md:
--------------------------------------------------------------------------------
1 | ## AlexGames Rust games
2 |
3 | See [gem match](gem_match) and [reversi](reversi) for an example of how to implement a game.
4 |
5 | Your game should implement `AlexGamesApi` (defined in [`rust_game_api.rs`](rust_game_api.rs)), and it can call the `*const CCallbacksPtr` it is passed to draw on the game canvas, initialize UI elements, send multiplayer messages, etc.
6 |
7 | When adding a new game, two changes need to be made to [`rust_game_handler.rs`](rust_game_handler.rs):
8 | * `get_rust_game_init_func`: need to match the `game_id` (string, e.g. `"reversi"` or `"gem_match`) to your game's implementation of `pub fn init(callbacks: *const rust_game_api::CCallbacksPtr) -> Box`.
9 | * `handle_void_ptr_to_trait_ref`: need to match the `game_id` string to the right cast of the `*mut AlexGamesHandle` field `api` to your game struct, which should implement the `AlexGamesApi` trait.
10 |
11 | The `handle_void_ptr_to_trait_ref` step for each game could maybe be removed in the future by passing a struct of function pointers to C instead, or something like that. I think in C++ each object's vtable is referenced in a generic place on the object, but in Rust it seems to work differently, and you need to cast to your struct first before you can call the struct functions, even if all the structs implement the `AlexGamesApi` trait.
12 |
--------------------------------------------------------------------------------
/src/lua_api/lua_api_utils.c:
--------------------------------------------------------------------------------
1 |
2 | #include "lua.h"
3 | #include "lualib.h"
4 | #include "lauxlib.h"
5 |
6 | #include
7 |
8 | float lua_get_int_or_float_func(void *L, int stack_idx, const char *field_name, bool nil_ok, const char *func_name) {
9 | // So at first I thought that Lua treated floats and integers separately.
10 | // Now I see that they don't, and really I should just call tonumberx instead of tointegerx.
11 | // I had originally just called tointegerx, then later added tonumberx.
12 |
13 | if (lua_gettop(L) < stack_idx) {
14 | if (nil_ok) {
15 | return 0;
16 | } else {
17 | luaL_error(L, "%s: expected stack idx %d to contain field %s, but top was %d", __func__, stack_idx, field_name, lua_gettop(L));
18 | }
19 | }
20 |
21 | if (lua_type(L, stack_idx) == LUA_TNIL) {
22 | if (nil_ok) {
23 | return 0;
24 | } else {
25 | luaL_error(L, "%s: param %s is nil", func_name, field_name);
26 | }
27 | }
28 |
29 | {
30 | int is_int = 0;
31 | lua_Integer val_int = lua_tointegerx(L, stack_idx, &is_int);
32 | if (is_int) {
33 | return val_int;
34 | }
35 | }
36 |
37 | {
38 | int is_float = 0;
39 | lua_Number val_float = lua_tonumberx(L, stack_idx, &is_float);
40 | if (is_float) {
41 | return val_float;
42 | }
43 | }
44 |
45 | luaL_error(L, "%s: could not convert %s to Lua number or int", func_name, field_name);
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/src/android/adb_copy_files.sh:
--------------------------------------------------------------------------------
1 | set -e
2 | set -u
3 | set -x
4 |
5 | DEVICE_ID=emulator-5554
6 | CACHE_DIR=/data/user/0/net.alexbarry.alexgames/files
7 |
8 | # adb -s $DEVICE_ID mkdir -p $CACHE_DIR
9 | adb -s $DEVICE_ID push src/lua_scripts $CACHE_DIR/src/lua_scripts
10 | adb -s $DEVICE_ID push img $CACHE_DIR/img
11 |
12 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*
13 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*/*
14 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*/*/*
15 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*/*/*/*
16 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*/*/*/*/*
17 | adb -s $DEVICE_ID shell chmod a+rwx $CACHE_DIR/*/*/*/*/*/*
18 |
19 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*
20 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*/*
21 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*/*/*
22 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*/*/*/*
23 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*/*/*/*/*
24 | adb -s $DEVICE_ID shell chown u0_a136 $CACHE_DIR/*/*/*/*/*/*
25 |
26 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*
27 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*/*
28 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*/*/*
29 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*/*/*/*
30 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*/*/*/*/*
31 | # adb -s $DEVICE_ID shell chgrp u0_a136 $CACHE_DIR/*/*/*/*/*/*
32 |
--------------------------------------------------------------------------------
/src/cpp_libs/saved_state_db/saved_state_db_c_api.cpp:
--------------------------------------------------------------------------------
1 | #include "saved_state_db.h"
2 | #include "saved_state_db_c_api.h"
3 |
4 | void *saved_state_db_init(void *L, const struct game_api_callbacks *callbacks) {
5 | SavedStateDb *db = new SavedStateDb(L, callbacks);
6 | db->refresh_internal_state();
7 | return db;
8 | }
9 |
10 | int saved_state_db_get_new_session_id(void *handle) {
11 | SavedStateDb *db = (SavedStateDb*)handle;
12 | return db->get_new_session_id();
13 | }
14 |
15 | int saved_state_db_get_last_session_id(void *handle, const char *game_id) {
16 | SavedStateDb *db = (SavedStateDb*)handle;
17 | return db->get_last_session_id(game_id);
18 | }
19 |
20 | void saved_state_db_save_state(void *handle, const char *game_id, int session_id, const uint8_t *state, size_t state_len) {
21 | SavedStateDb *db = (SavedStateDb*)handle;
22 |
23 | db->save_state(game_id, session_id, state, state_len);
24 | }
25 |
26 |
27 | bool saved_state_db_has_saved_state_offset(void *handle, int session_id, int move_id_offset) {
28 | SavedStateDb *db = (SavedStateDb*)handle;
29 |
30 | return db->has_saved_state_offset(session_id, move_id_offset);
31 | }
32 |
33 | int saved_state_db_get_saved_state_offset(void *handle, int session_id, int move_id_offset, uint8_t *state, size_t state_len) {
34 | SavedStateDb *db = (SavedStateDb*)handle;
35 |
36 | return db->adjust_saved_state_offset(session_id, move_id_offset, state, state_len);
37 | }
38 |
--------------------------------------------------------------------------------
/src/android/README.md:
--------------------------------------------------------------------------------
1 | # Before building the android app
2 |
3 | Need to run this script to copy some assets from `src/lua_scripts/` to the assets directory:
4 |
5 | src/android/cp_games_assets.sh
6 |
7 | ... until I figure out how to get gradle to do it.
8 |
9 | # Port forwarding to Android emulator
10 |
11 | When running the app on an Android emulator, at least on my system, the server
12 | wasn't easily accessible from my local network, or even from the same computer.
13 |
14 | Run these commands to forward connections from the computer running the emulator
15 | to the emulator itself:
16 |
17 | # `adb forward port1 port2`
18 | # forwards connections to your computer on port1
19 | # to your emulator on port2.
20 |
21 | # This is the default HTTP port used by the AlexGames android app
22 | adb forward tcp:55080 tcp:55080
23 |
24 | # This is the default WS port used by the AlexGames Android app
25 | adb forward tcp:55433 tcp:55433
26 |
27 | Now you should be able to access the server on your emulator by visiting http://localhost:55080 in a browser.
28 |
29 | Alternatively, others on your network should be able to visit the server by entering your computer's local IP followed by the port (default is 55080).
30 |
31 | ## Disable emulator port forwarding
32 |
33 | And to undo the above:
34 |
35 | adb forward --remove tcp:55080
36 | adb forward --remove tcp:55433
37 |
38 | Or:
39 |
40 | adb forward --remove-all
41 |
--------------------------------------------------------------------------------
/src/android/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/cpp_libs/button_helper/button_helper.h:
--------------------------------------------------------------------------------
1 | #include "game_api.h"
2 | #include "touch_press_handler.h"
3 |
4 | #include
5 | #include
6 |
7 | typedef int btn_id_t;
8 | typedef void(*button_callback_t)(void *L, btn_id_t btn_id);
9 |
10 | class ButtonInfo;
11 |
12 | /**
13 | * Client registers button positions, this class can
14 | * draw them, and handle detecting clicks on them.
15 | */
16 | class ButtonHelper {
17 |
18 | public:
19 | ButtonHelper(void *handle);
20 | void new_button(ButtonInfo btn_info);
21 | bool handle_user_pressed(int y_pos, int x_pos);
22 | bool handle_touch_evt(std::string evt_id_str,
23 | const struct touch_info *changed_touches,
24 | int changed_touches_len);
25 | void draw_buttons(const struct game_api_callbacks *callbacks);
26 |
27 | private:
28 |
29 | std::string btn_colour = "#aaaaaaaa";
30 | std::string btn_text_colour = "#000000";
31 | TouchPressHandler touch_press_handler;
32 | int btn_text_size = 18;
33 | void *handle;
34 | std::vector button_info;
35 |
36 | };
37 |
38 | // private class
39 | class ButtonInfo {
40 | public:
41 | static ButtonInfo fromSize(std::string text, int y_start, int x_start, int y_size, int x_size, btn_id_t btn_id, button_callback_t callback);
42 | std::string text;
43 | int y_start;
44 | int x_start;
45 | int y_end;
46 | int x_end;
47 | btn_id_t btn_id;
48 | button_callback_t callback;
49 | };
50 |
51 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/fragment_host_or_local.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
20 |
21 |
28 |
29 |
35 |
39 |
--------------------------------------------------------------------------------
/src/android/app/src/main/res/layout/fragment_second.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
23 |
32 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/ui/touchpad.lua:
--------------------------------------------------------------------------------
1 | local touchpad = {}
2 |
3 | function touchpad.new_state(touchpad_pos, touchpad_radius)
4 | return {
5 | pos = touchpad_pos,
6 | radius = touchpad_radius,
7 | active_touch = nil,
8 |
9 | player_vec = { y = 0, x = 0 },
10 | }
11 | end
12 |
13 | local function touch_in_dirpad(state, touch)
14 | local dy = (touch.y - state.pos.y)
15 | local dx = (touch.x - state.pos.x)
16 |
17 | return (math.abs(dy) <= state.radius and
18 | math.abs(dx) <= state.radius)
19 | end
20 |
21 | function touchpad.handle_touch_evts(state, evt_id, touches)
22 | local touch_changed = false
23 | for _, touch in ipairs(touches) do
24 | if evt_id == 'touchstart' and state.active_touch == nil and touch_in_dirpad(state, touch) then
25 | state.active_touch = touch.id
26 | touch_changed = true
27 | elseif (evt_id == 'touchend' or evt_id == 'touchcancel') and state.active_touch == touch.id then
28 | state.active_touch = nil
29 | state.player_vec = { y = 0, x = 0 }
30 | touch_changed = true
31 | end
32 |
33 | if state.active_touch == touch.id then
34 | local dy = (touch.y - state.pos.y)
35 | local dx = (touch.x - state.pos.x)
36 | local mag = math.sqrt(dy*dy + dx*dx) / state.radius
37 | mag = math.min(mag, 1)
38 | local angle = math.atan(dy,dx)
39 | state.player_vec = {
40 | y = mag*math.sin(angle),
41 | x = mag*math.cos(angle),
42 | }
43 | touch_changed = true
44 | end
45 | end
46 |
47 | if touch_changed then
48 | return state.player_vec
49 | else
50 | return nil
51 | end
52 | end
53 |
54 | return touchpad
55 |
--------------------------------------------------------------------------------
/src/server/socket/test/test_server.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "socket_server.h"
4 |
5 | #define MAX_CLIENTS 10
6 |
7 | static const int port = 5678;
8 |
9 |
10 | static void client_thread_handler(void **arg) {
11 | printf("Started client_thread_handler...\n");
12 |
13 | void *client_handle = *arg;
14 |
15 | static const char msg[] = "Hello, world! This is a message from the server.";
16 | send_msg(client_handle, msg, sizeof(msg));
17 |
18 | while (1) {
19 | char buff[1024];
20 | size_t bytes_recvd = 0;
21 | int rc = recv_msg(client_handle, sizeof(buff), buff, &bytes_recvd);
22 |
23 | if (rc <= 0) {
24 | printf("Received rc=%d, exiting client handler\n", rc);
25 | return;
26 | }
27 |
28 | printf("Recvd msg from client: %.*s\n", bytes_recvd, buff);
29 | }
30 | }
31 |
32 | int main(void) {
33 | void *server_handle;
34 | int rc = host_server(port, &server_handle);
35 | if (rc != 0) {
36 | printf("Unable to host server, rc=%d\n", rc);
37 | return 0;
38 | }
39 |
40 | int client_idx = 0;
41 | pthread_t client_threads[MAX_CLIENTS];
42 |
43 | while (client_idx < MAX_CLIENTS) {
44 | void **client_handle = malloc(sizeof(void*));
45 | int rc = wait_for_connections(server_handle, client_handle);
46 | if (rc != 0) {
47 | printf("Unable to wait for connection, rc=%d\n", rc);
48 | return 0;
49 | }
50 | printf("Received connection, creating thread...\n");
51 | rc = pthread_create(&client_threads[client_idx], NULL, client_thread_handler, client_handle);
52 | if (rc != 0) {
53 | printf("Unable to create pthread\n");
54 | return 0;
55 | }
56 | client_idx++;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/game_api/game_api_words.h:
--------------------------------------------------------------------------------
1 | #ifndef GAME_API_WORDS_H
2 | #define GAME_API_WORDS_H
3 |
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | #define MAX_WORD_LEN (64)
12 |
13 | typedef float word_freq_t;
14 |
15 | struct word_query_params {
16 | int min_length;
17 | int max_length;
18 | word_freq_t min_freq;
19 | bool include_weird_or_vulgar;
20 | };
21 |
22 |
23 | struct game_dict_api {
24 | bool (*is_ready)(void);
25 |
26 | void* (*init)(const char *language);
27 |
28 | /**
29 | * Checks if word is in the dictionary.
30 | */
31 | bool (*is_valid_word)(void *dict_handle, const char *word);
32 |
33 | word_freq_t (*get_word_freq)(void *dict_handle, const char *word);
34 |
35 | /**
36 | * Gets random word of specified length and minimum frequency.
37 | */
38 | int (*get_random_word)(void *dict_handle,
39 | const struct word_query_params *params,
40 | char *word_out, size_t max_word_out_len,
41 | int *possib_word_count_out);
42 |
43 | /**
44 | * Gets list of words that can be made from a subset of the
45 | * provided letters.
46 | */
47 | int (*get_words_made_from_letters)(void *dict_handle,
48 | const struct word_query_params *params,
49 | const char *letters);
50 | };
51 |
52 | struct word_query_params get_default_params(void);
53 |
54 | const struct game_dict_api *get_game_dict_api(void);
55 |
56 | void set_game_dict_api(const struct game_dict_api *dict_api);
57 |
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/dice/dice_draw.lua:
--------------------------------------------------------------------------------
1 | local dice_draw = {}
2 |
3 | local alexgames = require("alexgames")
4 | local draw_more = require("libs/draw/draw_more")
5 |
6 | local DICE_IMG_MAP = {
7 | "dice1",
8 | "dice2",
9 | "dice3",
10 | "dice4",
11 | "dice5",
12 | "dice6",
13 | }
14 |
15 | function dice_draw.draw_one_die(die_val, y_pos, x_pos, y_size, x_size, idx, args)
16 | if args ~= nil and args.background_colour ~= nil then
17 | alexgames.draw_rect(args.background_colour,
18 | y_pos, x_pos,
19 | y_pos + y_size, x_pos + x_size)
20 | end
21 | local img_id = DICE_IMG_MAP[die_val]
22 | local graphic_params = nil
23 | if args ~= nil then
24 | graphic_params = {
25 | brightness_percent = args.brightness_percent,
26 | invert = args.invert
27 | }
28 | end
29 | draw_more.draw_graphic_ul(img_id, y_pos, x_pos, x_size, y_size, graphic_params)
30 | if args.used_dice ~= nil and args.used_dice[idx] then
31 | if args.dice_used_overlay_colour == nil then
32 | error("args.dice_used_overlay_colour is nil, but args.used_dice is specified", 2)
33 | end
34 | alexgames.draw_rect(args.dice_used_overlay_colour, y_pos, x_pos, y_pos + y_size, x_pos + x_size)
35 | end
36 | end
37 |
38 | function dice_draw.draw_dice(dice_vals, y_pos, x_pos, y_size, x_size, args)
39 | for dice_idx, dice_val in ipairs(dice_vals) do
40 | x_pos2 = x_pos + (dice_idx-1)*x_size
41 | if args ~= nil and args.padding ~= nil then
42 | x_pos2 = x_pos2 + (dice_idx-1)*args.padding
43 | end
44 | dice_draw.draw_one_die(dice_val, y_pos, x_pos2, y_size, x_size, dice_idx, args)
45 | end
46 | end
47 |
48 | return dice_draw
49 |
50 |
--------------------------------------------------------------------------------
/clean.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -u
4 | set -x
5 |
6 | # navigate to same directory that this script is in
7 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
8 | cd "${DIR}"
9 |
10 | WX_WIDGETS_VS=build/wxWidgets/.vs
11 | ANDROID_GRADLE=src/android/.gradle
12 | ANDROID_IDEA=src/android/.idea
13 | ANDROID_CXX=src/android/app/.cxx
14 | ANDROID_COPIED_ASSETS=src/android/app/src/main/assets/games/*
15 | ANDROID_COPIED_HTML_GAMES=src/android/app/src/main/assets/html/*
16 |
17 | if ls logs/*.log >/dev/null 2>&1; then
18 | rm logs/*.log
19 | fi
20 |
21 | if ls build/*/out/ >/dev/null 2>&1; then
22 | rm -r build/*/out/
23 | fi
24 |
25 | if ls tests/*/out/ >/dev/null 2>&1; then
26 | rm -r tests/*/out/
27 | fi
28 |
29 | if ls third_party >/dev/null 2>&1; then
30 | rm -rf third_party
31 | fi
32 |
33 | if ls "$WX_WIDGETS_VS" 2>&1 1>/dev/null; then
34 | rm -r "$WX_WIDGETS_VS"
35 | fi
36 |
37 | if ls "$ANDROID_GRADLE" 2>&1 1>/dev/null; then
38 | rm -r "$ANDROID_GRADLE"
39 | fi
40 |
41 | if ls "$ANDROID_IDEA" 2>&1 1>/dev/null; then
42 | rm -r "$ANDROID_IDEA"
43 | fi
44 |
45 | if ls $ANDROID_COPIED_ASSETS 2>&1 1>/dev/null; then
46 | rm -r $ANDROID_COPIED_ASSETS
47 | fi
48 |
49 | if ls $ANDROID_COPIED_HTML_GAMES 2>&1 1>/dev/null; then
50 | rm -r $ANDROID_COPIED_HTML_GAMES
51 | fi
52 |
53 | if ls $ANDROID_CXX 2>&1 1>/dev/null; then
54 | rm -r $ANDROID_CXX
55 | fi
56 |
57 | if ls tests/out/ >/dev/null 2>&1; then
58 | rm -r tests/out/
59 | fi
60 |
61 | if ls cscope.out >/dev/null 2>&1; then
62 | rm cscope.out
63 | fi
64 |
65 | if ls out >/dev/null 2>&1; then
66 | rm -r out
67 | fi
68 |
69 | (
70 | cd src/rust_games;
71 | cargo clean;
72 | )
73 |
74 | (
75 | cd src/android;
76 | ./gradlew clean;
77 | )
78 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/server/ServerMonitorViewModel.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.server;
2 |
3 | import androidx.lifecycle.LiveData;
4 | import androidx.lifecycle.MutableLiveData;
5 | import androidx.lifecycle.ViewModel;
6 |
7 | import java.util.Date;
8 | import java.util.List;
9 |
10 | public class ServerMonitorViewModel extends ViewModel {
11 |
12 | private final MutableLiveData serverStartDate = new MutableLiveData<>();
13 | private final MutableLiveData serverAddr = new MutableLiveData<>();
14 | private final MutableLiveData> downloadInfoList =
15 | new MutableLiveData<>();
16 | private final MutableLiveData> activeConnInfoList =
17 | new MutableLiveData<>();
18 |
19 | public void setServerStartDate(Date date) { this.serverStartDate.setValue(date); }
20 | public void setServerAddr(String addr) { this.serverAddr.setValue(addr); }
21 | public void setDownloadInfoList(List dlInfoList) { this.downloadInfoList.setValue(dlInfoList); }
22 | public void setActiveConnInfoList(List connInfoList) { this.activeConnInfoList.setValue(connInfoList); }
23 |
24 | public LiveData getDate() { return this.serverStartDate; }
25 | public LiveData getServerAddr() { return this.serverAddr; }
26 | public LiveData> getDownloadInfoList() { return this.downloadInfoList; }
27 | public LiveData> getActiveConnInfoList() { return this.activeConnInfoList; }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/cpp_libs/touch_press_handler/touch_press_handler.cpp:
--------------------------------------------------------------------------------
1 | #include "touch_press_handler.h"
2 |
3 | #include
4 | #include
5 |
6 | TouchPress TouchPress::NoTouch() {
7 | TouchPress info;
8 | info.pressed = false;
9 | return info;
10 | }
11 | TouchPress TouchPress::Touch(float y, float x) {
12 | TouchPress info;
13 | info.pressed = true;
14 | info.y = y;
15 | info.x = x;
16 | return info;
17 | }
18 |
19 | extern const game_api_callbacks* g_callbacks;
20 |
21 | TouchPress TouchPressHandler::handle_touch_evt(std::string evt_id,
22 | const struct touch_info *changed_touches,
23 | int changed_touches_len) {
24 | for (int idx=0; idxactive_touch_present) {
27 | if (this->active_touch.id == touch->id) {
28 | if (evt_id == "touchcancel" ||
29 | (evt_id == "touchmove" &&
30 | abs(touch->y - this->active_touch.y) > max_touch_move &&
31 | abs(touch->x - this->active_touch.x) > max_touch_move)) {
32 | this->active_touch_present = false;
33 | } else if (evt_id == "touchend") {
34 | this->active_touch_present = false;
35 | if (abs(touch->y - this->active_touch.y) < max_touch_move &&
36 | abs(touch->x - this->active_touch.x) < max_touch_move) {
37 | return TouchPress::Touch(touch->y, touch->x);
38 | }
39 | }
40 |
41 | }
42 | } else {
43 | if (evt_id == "touchstart") {
44 | this->active_touch_present = true;
45 | this->active_touch = *touch;
46 | }
47 | }
48 | }
49 | return TouchPress::NoTouch();
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/endless_runner/endless_runner_main.lua:
--------------------------------------------------------------------------------
1 | local core = require("games/endless_runner/endless_runner_core")
2 | local draw = require("games/endless_runner/endless_runner_draw")
3 |
4 | local alexgames = require("alexgames")
5 |
6 | local FPS = 60
7 |
8 | local g_state = nil
9 |
10 | function update(dt_ms)
11 | if dt_ms and dt_ms > 0 then
12 | core.update_state(g_state, dt_ms)
13 | end
14 | draw.update(g_state)
15 | end
16 |
17 | local jump_keys = {
18 | ["Space"] = true,
19 | ["Enter"] = true,
20 | ["ArrowUp"] = true,
21 | ["KeyK"] = true,
22 | ["KeyW"] = true
23 | }
24 |
25 | local function new_game()
26 | g_state = core.new_state()
27 | end
28 |
29 | function handle_key_evt(key_evt, key_id)
30 | print(string.format("evt=%s, id=%s", key_evt, key_id))
31 | if jump_keys[key_id] then
32 | if key_evt == "keydown" then
33 | core.jump(g_state, core.JUMP_TYPE_KEY)
34 | end
35 | return true
36 | end
37 | return false
38 | end
39 |
40 | function handle_mouse_evt(evt_id, pos_y, pos_x)
41 | if evt_id == alexgames.MOUSE_EVT_DOWN then
42 | core.jump(g_state, core.JUMP_TYPE_KEY)
43 | if draw.in_new_game_btn(state, pos_y, pos_x) then
44 | new_game()
45 | end
46 | end
47 |
48 | end
49 |
50 | function handle_touch_evt(evt_id, touches)
51 | for _, touch in ipairs(touches) do
52 | if evt_id == "touchstart" then
53 | core.jump(g_state, core.JUMP_TYPE_TOUCH)
54 | if draw.in_new_game_btn(state, touch.y, touch.x) then
55 | new_game()
56 | end
57 | end
58 | end
59 |
60 | end
61 |
62 | function start_game(session_id_arg, serialized_state_arg)
63 | new_game()
64 |
65 | alexgames.set_timer_update_ms(1000/FPS)
66 | alexgames.enable_evt("key")
67 | alexgames.enable_evt("mouse_updown")
68 | alexgames.enable_evt("touch")
69 | end
70 |
--------------------------------------------------------------------------------
/src/cpp_libs/touch_scroll_handler/touch_scroll_handler.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "touch_scroll_handler.h"
5 |
6 | static struct TouchScrollHandlerPoint CreateTouchScrollHandlerPoint(double y, double x) {
7 | struct TouchScrollHandlerPoint pt;
8 | pt.y = y;
9 | pt.x = x;
10 | return pt;
11 | }
12 |
13 | struct TouchScrollHandlerPoint TouchScrollHandler::handle_touch_evt(const char *evt_id_str, int evt_id_str_len,
14 | void *changed_touches, int changed_touches_len) {
15 | std::string evt_id(evt_id_str);
16 |
17 | struct touch_info *touches = (struct touch_info *)changed_touches;
18 |
19 | //std::cout << "handle_touch_evt, id=" << evt_id << ", touch_len:" << changed_touches_len << std::endl;
20 |
21 | if (this->active_touch_present) {
22 | for (int i=0; iactive_touch) {
24 | if (evt_id == "touchmove") {
25 | double diff_y = touches[i].y - this->prev_touch_screen_y_pos;
26 | double diff_x = touches[i].x - this->prev_touch_screen_x_pos;
27 | this->prev_touch_screen_y_pos = touches[i].y;
28 | this->prev_touch_screen_x_pos = touches[i].x;
29 | return CreateTouchScrollHandlerPoint(diff_y, diff_x);
30 | } else if (evt_id == "touchend" || evt_id == "touchcancel" /* TODO? */ ) {
31 | this->active_touch_present = false;
32 | this->active_touch = 0;
33 | }
34 | }
35 | }
36 | } else {
37 | if (evt_id == "touchstart" && changed_touches_len > 0) {
38 | this->active_touch = touches[0].id;
39 | this->prev_touch_screen_y_pos = touches[0].y;
40 | this->prev_touch_screen_x_pos = touches[0].x;
41 | this->active_touch_present = true;
42 | }
43 | }
44 | //return 0;
45 | return CreateTouchScrollHandlerPoint(0, 0);
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/lua_scripts/libs/draw/draw_shapes.lua:
--------------------------------------------------------------------------------
1 |
2 | local draw_shapes = {}
3 | local alexgames = require("alexgames")
4 |
5 | function draw_shapes.draw_rect_outline(colour, line_width, y1, x1, y2, x2)
6 | alexgames.draw_line(colour, line_width, y1, x1, y1, x2)
7 | alexgames.draw_line(colour, line_width, y1, x1, y2, x1)
8 | alexgames.draw_line(colour, line_width, y2, x2, y1, x2)
9 | alexgames.draw_line(colour, line_width, y2, x2, y2, x1)
10 | end
11 |
12 | function draw_shapes.draw_triangle_lr(line_colour, line_width, bg_colour, pointing_left, y1, x1, y2, x2)
13 |
14 | local pt1, pt2, pt3
15 | if pointing_left then
16 | pt1 = { y = math.floor((y2 + y1)/2), x = x1 }
17 | pt2 = { y = y1, x = x2 }
18 | pt3 = { y = y2, x = x2 }
19 | else
20 | pt1 = { y = math.floor((y2 + y1)/2), x = x2 }
21 | pt2 = { y = y1, x = x1 }
22 | pt3 = { y = y2, x = x1 }
23 | end
24 |
25 | if bg_colour ~= nil then
26 | -- TODO this file was written before I added a "fill_triangle" API.
27 | -- obviously it should use that instead
28 | alexgames.draw_rect(bg_colour, y1, x1, y2, x2)
29 | end
30 |
31 | if line_colour ~= nil then
32 | alexgames.draw_line(line_colour, line_width, pt1.y, pt1.x, pt2.y, pt2.x)
33 | alexgames.draw_line(line_colour, line_width, pt2.y, pt2.x, pt3.y, pt3.x)
34 | alexgames.draw_line(line_colour, line_width, pt3.y, pt3.x, pt1.y, pt1.x)
35 | end
36 | end
37 |
38 | function draw_shapes.draw_triangle_outline(line_colour, line_width,
39 | y1, x1,
40 | y2, x2,
41 | y3, x3)
42 | alexgames.draw_line(line_colour, line_width, y1, x1, y2, x2)
43 | alexgames.draw_line(line_colour, line_width, y2, x2, y3, x3)
44 | alexgames.draw_line(line_colour, line_width, y3, x3, y1, x1)
45 | end
46 |
47 | return draw_shapes
48 |
--------------------------------------------------------------------------------
/docker/http_server/Dockerfile.build_wasm:
--------------------------------------------------------------------------------
1 | # TODO have the ws and http server inherit from a common image
2 | # to avoid duplicating so many dependencies
3 | FROM nginx:latest AS base
4 |
5 | ARG ALEXGAMES_BUILD_TYPE_LABEL
6 | ENV ALEXGAMES_BUILD_TYPE_LABEL=${ALEXGAMES_BUILD_TYPE_LABEL}
7 |
8 | # Install OS dependencies
9 | # TODO double check that all of these are actually needed
10 | # zip: used to zip some lua files as an example game to be uploaded
11 | RUN apt-get update && apt-get install -y \
12 | cmake \
13 | git \
14 | python3 \
15 | python3-pip \
16 | pipx \
17 | ninja-build \
18 | wget \
19 | xz-utils \
20 | zlib1g-dev \
21 | zip
22 |
23 | RUN which zip
24 |
25 | # Create a python venv to suppress nginx complaining about
26 | # installing packages to system python.
27 | # (Not sure why this is needed inside a docker container)
28 | RUN python3 -m venv /alexgames_python_venv
29 | ENV PATH="/alexgames_python_venv/bin:$PATH"
30 |
31 | # Install python dependencies
32 | RUN pip3 install wordfreq # needed to generate dictionary file
33 |
34 | # Install Emscripten
35 | WORKDIR /
36 | RUN if [ ! -f "emsdk" ]; then \
37 | echo "Cloning emsdk repo..."; \
38 | git clone https://github.com/emscripten-core/emsdk.git emsdk ; \
39 | else \
40 | echo "emsdk repo already present"; \
41 | fi
42 | WORKDIR /emsdk
43 | RUN ./emsdk install latest
44 | RUN ./emsdk activate latest
45 | RUN . ./emsdk_env.sh
46 | ENV PATH="${PATH}:/emsdk"
47 | RUN /bin/bash -c "source ./emsdk_env.sh"
48 | ENV PATH="${PATH}:/emsdk/upstream/emscripten"
49 | RUN emcc --version
50 |
51 | # Install rust
52 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
53 | ENV PATH="/root/.cargo/bin:${PATH}"
54 | RUN rustup target add wasm32-unknown-emscripten
55 |
56 | FROM base AS build_alexgames
57 | WORKDIR /app
58 |
59 | CMD ["bash", "build/wasm/build.sh" ]
60 |
--------------------------------------------------------------------------------
/src/ui_wxWidgets/wx_game_popup.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "wx/wx.h"
7 | #include "wx/defs.h"
8 | #include "wx/sizer.h"
9 | #include "wx/popupwin.h"
10 |
11 | typedef void (*popup_btn_pressed_callback_t)(void *game_handle,
12 | const char *popup_id,
13 | int popup_btn_id,
14 | const struct popup_state *popup_state);
15 |
16 | class GamePopupStateItem;
17 |
18 | class GamePopup : public wxDialog {
19 | public:
20 | GamePopup(wxFrame *parent, std::string popup_id, const struct popup_info *popup_info, void *game_handle);
21 | virtual ~GamePopup(void);
22 | void set_popup_btn_pressed_callback(popup_btn_pressed_callback_t callback);
23 |
24 | protected:
25 | void OnButton(wxCommandEvent& event);
26 |
27 | private:
28 | struct popup_state get_state(void) const;
29 |
30 | std::vector popup_state_items;
31 |
32 | wxBoxSizer *sizer;
33 | std::string popup_id;
34 | void *game_handle;
35 | popup_btn_pressed_callback_t callback;
36 | std::vector children;
37 | std::unordered_map button_game_ids;
38 |
39 | std::vector dropdown_choices_strings;
40 | std::vector dropdown_sizers;
41 |
42 | wxDECLARE_EVENT_TABLE();
43 | };
44 |
45 | class GamePopupStateItem {
46 | public:
47 | virtual struct popup_state_item get_state(void) const = 0;
48 | };
49 |
50 | class GamePopupStateItemDropdown : public GamePopupStateItem {
51 | public:
52 | GamePopupStateItemDropdown(uint32_t game_popup_item_id, wxChoice *elem);
53 |
54 | virtual struct popup_state_item get_state(void) const;
55 |
56 | private:
57 | uint32_t game_popup_item_id;
58 | wxChoice *elem;
59 | };
60 |
--------------------------------------------------------------------------------
/metadata/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | A collection of simple Lua and Rust games, and a web engine for playing them including an English dictionary (for word puzzles), websocket multiplayer, state sharing via URL, and auto saving with undo/redo. You can also upload your own games and play them.
2 |
3 | Some games incude:
4 | * Solitaire
5 | * "Word Mastermind": Guess 5 letter words, finding out if you guessed the right letter, or the right letter in the right position.
6 | * chess
7 | * "Crossword Letters": Try to make as many words as you can with the letters provided, with a crossword as a hint.
8 | * "Gem Match": Swap gems to make lines of three or more of the same kind.
9 | * Go/Weiqi/Baduk
10 | * Reversi
11 | * Checkers/Draughts
12 | * "Endless Runner": Tap the screen or press space bar to propel yourself upwards, dodging the endless oncoming obstacles.
13 | * Minesweeper
14 | * Fluid Mix: Rearrange the stacks where you can only move stacks onto empty stacks or stacks of the same colour, until each stack has only a single colour.
15 | * Backgammon
16 | * Cribbage
17 | * "Spider Swing": swing from point to point, being careful not to lose too much height or speed.
18 | * "Thrust": Race your space ship around the track, trying to control your momentum.
19 | * Gomoku/Wuziqi/Omok: Place stones on a Go board, trying to be the first to create a line of 5.
20 |
21 | The android app bundles the web version for offline play. (For network multiplayer, try the web version at https://alexbarry.github.io/AlexGames).
22 |
23 | On the Android version there are two prototype features:
24 | * you can host an HTTP/websocket server on your phone, to allow people on your local network to play web games together.
25 | * you can play the Android native version. The web version is more polished, but the Android one demonstrates how games can be played without using a browser or webview at all.
26 |
--------------------------------------------------------------------------------
/src/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/swarm/swarm_keyboard_input.lua:
--------------------------------------------------------------------------------
1 | local keyboard_input = {}
2 |
3 | local INV_SQRT2 = 1/math.sqrt(2)
4 |
5 | function keyboard_input.new_key_state()
6 | local state = {
7 | keys_pressed = {},
8 | }
9 | return state
10 | end
11 |
12 | local function abs(x)
13 | if x >= 0 then return x
14 | else return -x end
15 | end
16 |
17 | local function sign(x)
18 | if x >= 0 then return 1
19 | else return -1 end
20 | end
21 |
22 | function keyboard_input.get_move_vec_from_key_evt(state, evt, code)
23 | if state.keys_pressed[code] == nil then
24 | state.keys_pressed[code] = false
25 | end
26 |
27 | state.keys_pressed[code] = (evt == "keydown")
28 |
29 | local keys_handled = {
30 | ["ArrowLeft"] = true,
31 | ["ArrowRight"] = true,
32 | ["ArrowUp"] = true,
33 | ["ArrowDown"] = true,
34 |
35 | ["ArrowH"] = true,
36 | ["ArrowJ"] = true,
37 | ["ArrowK"] = true,
38 | ["ArrowL"] = true,
39 | }
40 |
41 | local left = state.keys_pressed["ArrowLeft"] or state.keys_pressed["KeyH"]
42 | local right = state.keys_pressed["ArrowRight"] or state.keys_pressed["KeyL"]
43 | local down = state.keys_pressed["ArrowDown"] or state.keys_pressed["KeyJ"]
44 | local up = state.keys_pressed["ArrowUp"] or state.keys_pressed["KeyK"]
45 |
46 | local move_vec_y = 0
47 | local move_vec_x = 0
48 |
49 | if left and right then
50 | -- pass
51 | elseif left then
52 | move_vec_x = -1
53 | elseif right then
54 | move_vec_x = 1
55 | end
56 |
57 | if up and down then
58 | -- pass
59 | elseif up then
60 | move_vec_y = -1
61 | elseif down then
62 | move_vec_y = 1
63 | end
64 |
65 | if abs(move_vec_y) > 0 and abs(move_vec_x) > 0 then
66 | move_vec_y = sign(move_vec_y)*INV_SQRT2
67 | move_vec_x = sign(move_vec_x)*INV_SQRT2
68 | end
69 |
70 | return {
71 | handled = keys_handled[code],
72 | vec = {
73 | y = move_vec_y,
74 | x = move_vec_x,
75 | },
76 | }
77 |
78 | end
79 |
80 | return keyboard_input
81 |
--------------------------------------------------------------------------------
/src/html/js/alexgames_c_dict.js:
--------------------------------------------------------------------------------
1 |
2 | function _write_chunk_to_file(reader, f, resolve) {
3 | return reader.read()
4 | .then( ({done, value}) => {
5 | if (!done) {
6 | // TODO actually write the chunk to the file here
7 | let dataView = new DataView(value.buffer, value.byteOffset, value.byteLength);
8 | write_data_view_to_file(null, f, dataView);
9 | // TODO how do you do this without going deeper and deeper
10 | // into the stack every time?
11 | _write_chunk_to_file(reader, f, resolve);
12 | } else {
13 | // TODO clean this up, this is bad
14 | //dict_is_init = true;
15 | close_file(null, f);
16 | resolve(true);
17 | }
18 | })
19 |
20 | }
21 |
22 | function fetch_words_list2(uri) {
23 | return new Promise((resolve, reject) => {
24 | fetch(uri)
25 | .then((response) => {
26 | const reader = response.body.getReader();
27 | const f = new_file(null, "words-en.txt");
28 | _write_chunk_to_file(reader, f, resolve);
29 | });
30 | });
31 | }
32 |
33 | function js_c_dict_init(language) {
34 | console.debug("[init] js_c_dict_init called");
35 | dict_needed = true;
36 |
37 | if (gfx.dict && gfx.language == language) {
38 | return true;
39 | } else {
40 | const msg = "Game has requested dictionary. Game will restart when it is downloaded.";
41 | set_status_msg(gfx, msg);
42 | console.log("[init]", msg);
43 | }
44 | console.debug("fetching dictionary file because", gfx.dict, gfx.language, language);
45 |
46 | const words_uri = "words-en.txt";
47 | fetch_words_list2(words_uri).then((dict) => {
48 | console.log("[init] Word dict loaded!");
49 | update_dict();
50 | dict_is_init = true;
51 | gfx.dict = dict;
52 | gfx.language = language;
53 |
54 | if (allReady()) {
55 | let msg = "Dictionary downloaded, re-initializing game";
56 | set_status_msg(gfx,msg);
57 | // Don't call an init API here, partial_init already does that
58 | }
59 |
60 | console.log("dict_init: calling partial init");
61 | partial_init();
62 | });
63 | }
64 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/server/GameServerBinder.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.server;
2 |
3 | import android.os.Binder;
4 |
5 | import java.util.Date;
6 | import java.util.List;
7 |
8 | public class GameServerBinder extends Binder {
9 |
10 | private Runnable updateListener = null;
11 |
12 | public static class ServerDownloadInfoEntry {
13 | private final String user;
14 | private final Date date;
15 | int downloads = 0;
16 |
17 | ServerDownloadInfoEntry(String user, Date date) {
18 | this.user = user;
19 | this.date = date;
20 | }
21 |
22 | public String getUser() { return this.user; }
23 | public Date getDate() { return this.date; }
24 | public int getDownloads() { return this.downloads; }
25 |
26 | }
27 |
28 | public static class ServerActiveConnectionEntry {
29 | private final String sessionId;
30 | private final String user;
31 | private final Date firstConnected;
32 | ServerActiveConnectionEntry(String sessionId, String user, Date firstConnected) {
33 | this.sessionId = sessionId;
34 | this.user = user;
35 | this.firstConnected = firstConnected;
36 | }
37 |
38 | public String getSessionId() { return this.sessionId; }
39 | public String getUser() { return this.user; }
40 | public Date getFirstConnected() { return this.firstConnected; }
41 | }
42 |
43 | private final GameServerService service;
44 |
45 | GameServerBinder(GameServerService service) {
46 | this.service = service;
47 | }
48 |
49 | public GameServerService getService() {
50 | return this.service;
51 | }
52 |
53 | // TODO maybe there should be a list here. What if more than one activity is opened?
54 | public void registerStatusUpdateListener(Runnable updateListener) {
55 | this.updateListener = updateListener;
56 | }
57 |
58 | void notifyUpdateListener() {
59 | if (this.updateListener != null) {
60 | this.updateListener.run();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/popup/PopupManagerImpl.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.popup;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.Dialog;
6 | import android.content.DialogInterface;
7 | import android.util.Log;
8 |
9 | public class PopupManagerImpl implements IAlexGamesPopupManager {
10 | private static final String TAG = "PopupManager";
11 | private final Activity activity;
12 | private Callback callback;
13 |
14 | AlertDialog activeDialog = null;
15 |
16 | public PopupManagerImpl(Activity activity) {
17 | this.activity = activity;
18 | }
19 |
20 | @Override
21 | public void set_callback(Callback callback) {
22 | this.callback = callback;
23 | }
24 |
25 | @Override
26 | public void show_popup(final String popup_id, final String title, final String msg, final String[] btns) {
27 | Log.i(TAG, String.format("Showing popup id=\"%s\"", popup_id));
28 | activity.runOnUiThread(new Runnable() {
29 | @Override
30 | public void run() {
31 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
32 | // TODO handle an arbitrary number of buttons
33 | builder.setTitle(title)
34 | .setMessage(msg);
35 | if (btns.length > 0) {
36 | builder.setPositiveButton(btns[0], new DialogInterface.OnClickListener() {
37 | @Override
38 | public void onClick(DialogInterface dialog, int which) {
39 | callback.popup_button_clicked(popup_id, 0);
40 | }
41 | });
42 | }
43 | if (activeDialog != null) { activeDialog.dismiss(); }
44 | activeDialog = builder.create();
45 | activeDialog.show();
46 | }
47 | });
48 |
49 | }
50 |
51 | public void destroy() {
52 | if (activeDialog != null) { activeDialog.dismiss(); }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/thrust/thrust_keyboard_input.lua:
--------------------------------------------------------------------------------
1 | local input = {}
2 |
3 | local need_to_rotate_enabled = true
4 |
5 | function input.new_input_state()
6 | return {
7 | rot_left = false,
8 | rot_right = false,
9 |
10 | thrust_left = false,
11 | thrust_right = false,
12 | thrust_up = false,
13 | thrust_down = false,
14 | }
15 | end
16 |
17 | function input.handle_key_evt(input_state, player_state, evt_id, code)
18 | --print(string.format("handle_key_evt, code=%s, evt=%s", code, evt_id))
19 | if need_to_rotate_enabled then
20 | if code == "ArrowLeft" then
21 | player_state.rot_left = (evt_id == "keydown")
22 | elseif code == "ArrowRight" then
23 | player_state.rot_right = (evt_id == "keydown")
24 | elseif code == "ArrowUp" then
25 | player_state.thrust_on = (evt_id == "keydown")
26 | elseif code == "ArrowDown" then
27 | player_state.brake_on = (evt_id == "keydown")
28 | else
29 | return false
30 | end
31 | return true
32 | else
33 | if code == "ArrowLeft" then
34 | input_state.thrust_left = (evt_id == "keydown")
35 | elseif code == "ArrowRight" then
36 | input_state.thrust_right = (evt_id == "keydown")
37 | elseif code == "ArrowUp" then
38 | input_state.thrust_up = (evt_id == "keydown")
39 | elseif code == "ArrowDown" then
40 | input_state.thrust_down = (evt_id == "keydown")
41 | else
42 | return false
43 | end
44 |
45 | local thrust_vec_y = 0
46 | local thrust_vec_x = 0
47 |
48 | if input_state.thrust_left and input_state.thrust_right then
49 | -- pass
50 | elseif input_state.thrust_left then
51 | thrust_vec_x = 1
52 | elseif input_state.thrust_right then
53 | thrust_vec_x = -1
54 | end
55 |
56 | if input_state.thrust_up and input_state.thrust_down then
57 | -- pass
58 | elseif input_state.thrust_up then
59 | thrust_vec_y = 1
60 | elseif input_state.thrust_down then
61 | thrust_vec_y = -1
62 | end
63 |
64 | if thrust_vec_y ~= 0 or thrust_vec_x ~= 0 then
65 | player_state.angle_degrees = math.atan(thrust_vec_y, thrust_vec_x) * 180 / math.pi - 90
66 | player_state.thrust_on = true
67 | else
68 | player_state.thrust_on = false
69 | end
70 | return true
71 | end
72 | end
73 |
74 | return input
75 |
--------------------------------------------------------------------------------
/src/emscripten/emscripten_c_dict_api.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "c_dictionary.h"
6 |
7 | EM_JS(void*, em_js_dict_init, (const char *language_ptr), {
8 | console.log("[dict] emscripten_c_dict_api: em_js_dict_init called. Using C dictionary after words file download complete.\n");
9 |
10 | if (em_js_dict_init.call_counts === undefined) {
11 | em_js_dict_init.call_counts = 0;
12 | }
13 | em_js_dict_init.call_counts += 1;
14 |
15 | if (em_js_dict_init.call_counts > 2) {
16 | console.error("em_js_dict_init.call_counts is", em_js_dict_init.call_counts);
17 | return;
18 | }
19 |
20 | js_c_dict_init();
21 |
22 | });
23 | static void *g_dict_handle = NULL;
24 |
25 | static bool dict2_is_dict_ready(void) {
26 | return g_dict_handle != NULL;
27 | }
28 |
29 | static bool dict2_is_valid_word(void *dict_handle, const char *word_ptr) {
30 | return get_c_dictionary_api()->is_valid_word(g_dict_handle, word_ptr);
31 | }
32 |
33 | static word_freq_t dict2_get_word_freq(void *dict_handle, const char *word_ptr) {
34 | return get_c_dictionary_api()->get_word_freq(g_dict_handle, word_ptr);
35 | }
36 |
37 | static int dict2_get_random_word(void *dict_handle,
38 | const struct word_query_params *params,
39 | char *word_out, size_t max_word_out_len,
40 | int *possib_word_count_out) {
41 | return get_c_dictionary_api()->get_random_word(g_dict_handle,
42 | params,
43 | word_out, max_word_out_len,
44 | possib_word_count_out);
45 | }
46 |
47 | static const struct game_dict_api api = {
48 | dict2_is_dict_ready,
49 | em_js_dict_init,
50 | dict2_is_valid_word,
51 | dict2_get_word_freq,
52 | dict2_get_random_word,
53 | NULL,
54 | };
55 |
56 | const struct game_dict_api *get_emscripten_game_dict_api(void) {
57 | return &api;
58 | }
59 |
60 | EMSCRIPTEN_KEEPALIVE
61 | void update_dict() {
62 | printf("update_dict called, seeding random number generator\n");
63 | srandom(time(NULL));
64 | g_dict_handle = build_word_dict_from_file("words-en.txt");
65 | }
66 |
--------------------------------------------------------------------------------
/src/html/js/alexgames_colour_pref.js:
--------------------------------------------------------------------------------
1 | const STORAGE_KEY_USER_COLOUR_PREF = "user_colour_pref";
2 |
3 | function user_colour_pref_to_game_format(colour_pref) {
4 | if (colour_pref == "very_dark") {
5 | return "dark"
6 | }
7 |
8 | return colour_pref;
9 | }
10 |
11 | function get_user_stored_colour_pref() {
12 | let storedPref = window.localStorage[STORAGE_KEY_USER_COLOUR_PREF];
13 | if (storedPref) {
14 | const colour_pref = user_colour_pref_to_game_format(storedPref);
15 | if (colour_pref != "auto") {
16 | return colour_pref;
17 | }
18 | }
19 |
20 | return undefined;
21 | }
22 |
23 | function get_user_colour_pref() {
24 | let stored_pref = get_user_stored_colour_pref();
25 | if (stored_pref) {
26 | return stored_pref;
27 | }
28 |
29 | const colour_pref_dark = window.matchMedia("(prefers-color-scheme: dark)");
30 | let colour_pref;
31 | if (colour_pref_dark && colour_pref_dark.matches) {
32 | colour_pref = "dark";
33 | } else {
34 | colour_pref = "light";
35 | }
36 | return colour_pref;
37 | }
38 |
39 |
40 | function set_user_colour_pref(pref) {
41 | window.localStorage[STORAGE_KEY_USER_COLOUR_PREF] = pref;
42 | }
43 |
44 | function set_html_colour_theme(theme) {
45 | document.body.classList.remove("dark");
46 | document.body.classList.remove("very_dark");
47 |
48 | if (!theme || theme == "auto") {
49 | theme = get_user_colour_pref();
50 | }
51 | document.body.classList.add(theme);
52 | }
53 |
54 | let g_on_colour_theme_change;
55 |
56 | function set_on_colour_theme_change_handler(callback) {
57 | g_on_colour_theme_change = callback;
58 | }
59 |
60 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', evt => {
61 | const colour_pref = evt.matches ? "dark" : "light";
62 | console.log("[colour_pref] User browser colour scheme preference changed to ", colour_pref, "updating html and game");
63 | const stored_colour_pref = get_user_stored_colour_pref();
64 | if (stored_colour_pref) {
65 | console.log("[colour_pref] Browser colour scheme pref changed, but user has specified explicit preference", stored_colour_pref, "so not changing anything");
66 | return;
67 | }
68 |
69 | if (g_on_colour_theme_change) {
70 | g_on_colour_theme_change(colour_pref);
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/word_mastermind/word_mastermind_serialize.lua:
--------------------------------------------------------------------------------
1 | local serialize = {}
2 |
3 | local serialize_lib = require("libs/serialize/serialize")
4 |
5 | local core = require("games/word_mastermind/word_mastermind_core")
6 |
7 | serialize.version = 1
8 |
9 | function serialize.serialize_state(state)
10 | if state == nil then return nil end
11 | local output = ""
12 |
13 | output = output .. serialize_lib.serialize_byte(serialize.version)
14 |
15 | output = output .. serialize_lib.serialize_byte(state.max_guesses)
16 | output = output .. serialize_lib.serialize_string(state.word)
17 | output = output .. serialize_lib.serialize_16bit(#state.guesses)
18 | for _, guess in ipairs(state.guesses) do
19 | output = output .. serialize_lib.serialize_string(guess.word)
20 | end
21 |
22 | return output
23 | end
24 |
25 | function serialize.deserialize_state(bytes)
26 | if bytes == nil then return nil end
27 | bytes = serialize_lib.bytestr_to_byteary(bytes)
28 |
29 | local version = serialize_lib.deserialize_byte(bytes)
30 |
31 | if version ~= serialize.version then
32 | error(string.format("can't deserialize state: received version %d, this implementation version is %d", version, serialize.version))
33 | end
34 |
35 | local partial_state = {}
36 | partial_state.max_guesses = serialize_lib.deserialize_byte(bytes)
37 | partial_state.word = serialize_lib.deserialize_string(bytes)
38 | partial_state.guesses = {}
39 | local guess_count = serialize_lib.deserialize_16bit(bytes)
40 | for i=1,guess_count do
41 | table.insert(partial_state.guesses, serialize_lib.deserialize_string(bytes))
42 | end
43 |
44 | local state = core.new_game(#partial_state.word, partial_state.max_guesses, partial_state.word)
45 | for guess_idx, guess in ipairs(partial_state.guesses) do
46 | core.force_guess(state, guess)
47 | end
48 |
49 | return state
50 | end
51 |
52 | function serialize.serialize_session_id(bytes)
53 | return serialize_lib.serialize_s32(bytes)
54 | end
55 |
56 | function serialize.deserialize_session_id(bytestr)
57 | if bytestr == nil then
58 | return nil
59 | end
60 | bytes = serialize_lib.bytestr_to_byteary(bytestr)
61 | return serialize_lib.deserialize_s32(bytes)
62 | end
63 |
64 | return serialize
65 |
--------------------------------------------------------------------------------
/BUILD.md:
--------------------------------------------------------------------------------
1 | # Building manually
2 |
3 | See README.md for how to build using docker. This page is for how to build manually, which I find more convenient for incremental builds while developing.
4 |
5 | ## Prerequisite: Install Emscripten
6 |
7 | Install emscripten following [these instructions](https://emscripten.org/docs/getting_started/downloads.html):
8 |
9 | mkdkir -p ~/repo/
10 | cd ~/repo/
11 | git clone https://github.com/emscripten-core/emsdk.git
12 | ./emsdk install latest
13 | ./emsdk activate latest
14 |
15 | Alternatively, install it anywhere, but update `build/wasm/setup_env.sh`.
16 |
17 | ## Prerequisite: Install virtualenv and python dependencies
18 |
19 | Install virtualenv with your package manager.
20 |
21 | virtualenv venv
22 | source venv/bin/activate
23 |
24 | Now install python dependencies
25 |
26 | # for generating the word dictionary
27 | pip3 install wordfreq
28 |
29 | # for hosting the websocket server
30 | pip3 install websockets
31 |
32 | Now you are ready to build the web version and host the websocket server in
33 | the next steps.
34 |
35 | Once you want to stop hosting the websocket server, and exit the virtual
36 | python environment, you can run this command:
37 |
38 | deactivate
39 |
40 | ## Building AlexGames web
41 |
42 | Simply run:
43 |
44 | build/wasm/build.sh -- -j32
45 |
46 | Optionally omitting the `-- -j32` to only use one thread when compiling,
47 | which makes finding errors in the output easier.
48 |
49 | This should automatically download all the dependencies you'd need into
50 | `third_party/`.
51 |
52 | Now you can just host the static HTML content in `build/wasm/out/http_out/`
53 | and you are mostly done. (See next section for guidance).
54 |
55 | ## How to host server
56 |
57 | Host websocket server (make sure you installed the `websocket` dependency
58 | already from a previous step):
59 |
60 | python3 src/server/ws/ws_server.py
61 |
62 | And in another terminal, host the HTTP server (note: don't do this on a
63 | public server, this is for development only):
64 |
65 | cd build/wasm/out/http_out
66 | python3 -m http.server 1234
67 |
68 | (Where 1234 is a port. You can choose a different number.)
69 |
70 | Then navigate to this in a browser:
71 |
72 | http://localhost:1234
73 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches: [ "main", "dev" ]
6 |
7 | jobs:
8 |
9 |
10 | deploy:
11 | # why can't this by nginx, like my docker images?
12 | runs-on: ubuntu-22.04
13 |
14 | permissions:
15 | contents: write
16 |
17 | steps:
18 |
19 | - name: Checkout
20 | uses: actions/checkout@v3
21 | with:
22 | fetch-depth: 0
23 | ref: ${{ github.ref }}
24 |
25 | - name: Fetch all branches
26 | run: git fetch --all
27 |
28 | - name: Setup docker buildx
29 | uses: docker/setup-buildx-action@v1
30 |
31 | - name: Build main AlexGames docker image (get build dependencies)
32 | run: |
33 | git checkout main
34 | docker build -t alexgames_build_wasm \
35 | --build-arg ALEXGAMES_BUILD_TYPE_LABEL=github-pages-main \
36 | -f docker/http_server/Dockerfile.build_wasm \
37 | .
38 |
39 | - name: Build main AlexGames static HTML via docker
40 | run: |
41 | docker run --rm \
42 | -v $(pwd):/app \
43 | alexgames_build_wasm
44 |
45 | - name: Copy main AlexGames static HTML to hosting path
46 | run: |
47 | mkdir -p public && \
48 | cp -r build/wasm/out/http_out/* ./public
49 |
50 | - name: Build dev AlexGames docker image (get build dependencies)
51 | run: |
52 | git checkout dev
53 | docker build -t alexgames_build_wasm \
54 | --build-arg ALEXGAMES_BUILD_TYPE_LABEL=github-pages-dev \
55 | -f docker/http_server/Dockerfile.build_wasm \
56 | .
57 |
58 | - name: Build dev AlexGames static HTML via docker
59 | run: |
60 | docker run --rm \
61 | -v $(pwd):/app \
62 | alexgames_build_wasm
63 |
64 | - name: Copy dev AlexGames static HTML to hosting path
65 | run: |
66 | mkdir -p public/dev && \
67 | cp -r build/wasm/out/http_out/* ./public/dev/
68 |
69 | - name: Deploy main and dev built HTML to GitHub Pages
70 | uses: peaceiris/actions-gh-pages@v3
71 | with:
72 | github_token: ${{ secrets.GITHUB_TOKEN }}
73 | publish_dir: ./public
74 | destination_dir: docs
75 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/SecondFragment.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.Adapter;
8 | import android.widget.AdapterView;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.ListView;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.fragment.app.Fragment;
14 | import androidx.fragment.app.FragmentManager;
15 | import androidx.lifecycle.ViewModelProvider;
16 | import androidx.navigation.fragment.NavHostFragment;
17 | import androidx.recyclerview.widget.RecyclerView;
18 |
19 | public class SecondFragment extends Fragment {
20 |
21 | private AlexGamesViewModel viewModel;
22 |
23 | @Override
24 | public View onCreateView(
25 | LayoutInflater inflater, ViewGroup container,
26 | Bundle savedInstanceState
27 | ) {
28 | // Inflate the layout for this fragment
29 | return inflater.inflate(R.layout.fragment_second, container, false);
30 | }
31 |
32 | public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
33 | super.onViewCreated(view, savedInstanceState);
34 |
35 | String[] games_list = new AlexGamesJni().getGamesList(); // TODO clean up
36 | ListView game_sel = view.findViewById(R.id.game_sel);
37 | ArrayAdapter adapter = new ArrayAdapter(view.getContext(), android.R.layout.simple_list_item_1, games_list);
38 | game_sel.setAdapter(adapter);
39 | viewModel = new ViewModelProvider(requireActivity()).get(AlexGamesViewModel.class);
40 | game_sel.setOnItemClickListener(new AdapterView.OnItemClickListener() {
41 | @Override
42 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
43 | String game_id = games_list[position];
44 | viewModel.setGameId(game_id);
45 | NavHostFragment.findNavController(SecondFragment.this)
46 | .navigate(R.id.action_SecondFragment_to_FirstFragment);
47 | }
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/img/black_piece.svg:
--------------------------------------------------------------------------------
1 |
2 |
67 |
--------------------------------------------------------------------------------
/img/white_piece.svg:
--------------------------------------------------------------------------------
1 |
2 |
67 |
--------------------------------------------------------------------------------
/src/ui_wxWidgets/wx_network.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "wx/wx.h"
4 |
5 | typedef void (*handle_msg_recvd_callback_t)(const char *src, size_t src_len,
6 | const uint8_t *msg, size_t msg_len);
7 | typedef void (*client_connected_callback_t)(const char *name, size_t name_len);
8 |
9 | void wx_network_init(void);
10 |
11 | class ClientHandlerThread;
12 |
13 | class ServerThread : public wxThread {
14 | public:
15 | ServerThread(wxWindow *parent, int port);
16 | void set_handle_msg_recvd_callback(handle_msg_recvd_callback_t callback);
17 | void set_client_connected_callback(client_connected_callback_t callback);
18 | void send_message(std::string dst, const uint8_t *msg, size_t msg_len);
19 | virtual ExitCode Entry(void);
20 | private:
21 | int port;
22 | wxWindow *parent;
23 | handle_msg_recvd_callback_t handle_msg_recvd_callback;
24 | client_connected_callback_t client_connected_callback;
25 | std::unordered_map client_threads;
26 | };
27 |
28 | class ClientHandlerThread : public wxThread {
29 | public:
30 | ClientHandlerThread(wxWindow *parent, void *client_handle, std::string client_name);
31 | virtual ~ClientHandlerThread(void) { };
32 | virtual ExitCode Entry();
33 | void set_handle_msg_recvd_callback(handle_msg_recvd_callback_t callback);
34 | void set_client_connected_callback(client_connected_callback_t callback);
35 | void send_message(const uint8_t *msg, size_t msg_len);
36 | private:
37 | wxWindow *parent;
38 | std::string client_name;
39 | void *client_handle;
40 | handle_msg_recvd_callback_t handle_msg_recvd_callback;
41 | client_connected_callback_t client_connected_callback;
42 | };
43 |
44 | class ClientThread : public wxThread {
45 | public:
46 | ClientThread(wxWindow *parent, std::string addr, int port);
47 | virtual ~ClientThread(void) { };
48 | virtual ExitCode Entry();
49 | void set_handle_msg_recvd_callback(handle_msg_recvd_callback_t callback);
50 | void send_message(std::string dst, const uint8_t *msg, size_t msg_len);
51 |
52 | private:
53 | wxWindow *parent;
54 | void *handle;
55 | std::string addr;
56 | int port;
57 | std::string client_name;
58 | handle_msg_recvd_callback_t handle_msg_recvd_callback;
59 | };
60 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/test/draw_graphics_test.lua:
--------------------------------------------------------------------------------
1 | local alexgames = require("alexgames")
2 |
3 | local y = 200
4 | local x = 100
5 |
6 | local width = 75
7 | local height = 75
8 |
9 | local i = 0
10 | local prop = 0
11 |
12 | function update()
13 | alexgames.draw_clear()
14 |
15 | if prop % 2 == 0 then
16 | flip_y_vals = { false, true }
17 | flip_x_vals = { false, true }
18 |
19 | local flip_y_used = nil
20 | local flip_x_used = nil
21 |
22 | local j = 0
23 |
24 | for _, flip_x in ipairs(flip_x_vals) do
25 | for _, flip_y in ipairs(flip_y_vals) do
26 | if j ~= i % 4 then
27 | goto next_iter
28 | end
29 |
30 | alexgames.draw_graphic('hospital_ventilator', y, x,
31 | width, height,
32 | { flip_y = flip_y, flip_x = flip_x })
33 | flip_y_used = flip_y
34 | flip_x_used = flip_x
35 | ::next_iter::
36 | j = j + 1
37 | end
38 |
39 | end
40 |
41 | local text1 = string.format("flip_y: %s", flip_y_used)
42 | local text2 = string.format("flip_x: %s", flip_x_used)
43 | alexgames.draw_text(text1, '#000000', 300, 0, 12, alexgames.TEXT_ALIGN_LEFT)
44 | alexgames.draw_text(text2, '#000000', 330, 0, 12, alexgames.TEXT_ALIGN_LEFT)
45 |
46 |
47 | else
48 | local angle_degrees = i * 15
49 | alexgames.draw_graphic('hospital_ventilator', y, x,
50 | width, height,
51 | { angle_degrees = angle_degrees })
52 |
53 | local text1 = string.format("angle: %s", angle_degrees)
54 | alexgames.draw_text(text1, '#000000', 300, 0, 12, alexgames.TEXT_ALIGN_LEFT)
55 |
56 | end
57 | alexgames.draw_circle('#ff0000', '#ff0000', y, x, 5)
58 |
59 | alexgames.draw_refresh()
60 | end
61 |
62 | local BTN_ID_NEXT_FRAME = "btn_next_frame"
63 | local BTN_ID_NEXT_PROP = "btn_next_prop"
64 |
65 | function handle_btn_clicked(btn_id)
66 | if btn_id == BTN_ID_NEXT_FRAME then
67 | i = i + 1
68 | update()
69 | elseif btn_id == BTN_ID_NEXT_PROP then
70 | prop = prop + 1
71 | update()
72 | else
73 | error(string.format("Unhandled btn id %s", btn_id))
74 | end
75 | end
76 |
77 | function start_game()
78 | alexgames.create_btn(BTN_ID_NEXT_FRAME, "Next Frame", 1)
79 | alexgames.create_btn(BTN_ID_NEXT_PROP, "Next Property", 1)
80 | end
81 |
--------------------------------------------------------------------------------
/src/android/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | # Not supported yet in the android native version. The web version embedded in the Android app should
4 | # still support this, though.
5 | set(ENABLE_ZIP_UPLOAD OFF CACHE BOOL "Enable the ability to upload custom games in zip files. Includes libzip and zlib." FORCE)
6 |
7 | # TODO Figure out how to support Rust for Android NDK
8 | set(ENABLE_RUST_GAMES OFF CACHE BOOL "" FORCE)
9 |
10 | set(SRC_DIR "../../../../..")
11 | # add_definitions(-DROOT_DIR="res/assets/")
12 | # TODO I think this works now for testing...
13 | # but long term this would have to be set at runtime, the output of getCacheDir()
14 | #add_definitions(-DROOT_DIR="/data/data/net.alexbarry.alexgames/cache/")
15 | # on the Nexus 5X emulator, this path is the cache directory
16 | # TODO I really need to set this at runtime
17 | #add_definitions(-DROOT_DIR="/data/user/0/net.alexbarry.alexgames/cache/")
18 | #add_definitions(-DROOT_DIR="/data/user/0/net.alexbarry.alexgames/files/games/")
19 |
20 |
21 | add_definitions(-DLUA_USE_APICHECK)
22 | # add_definitions(-DLUA_NOBUILTIN)
23 | add_definitions(-DLUAI_ASSERT)
24 | #add_definitions(-DLUA_ANSI)
25 | #add_definitions(-DLUA_USE_LINUX)
26 | # add_definitions(-O0)
27 |
28 | #SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
29 | #SET(CMAKE_CXX_CFLAGS "${CMAKE_CXX_CFLAGS} -O0")
30 |
31 | # add_subdirectory("${SRC_DIR}/lua_api" derp_out/lua_api)
32 | add_subdirectory("${SRC_DIR}" out/alexgames_core)
33 |
34 | add_library(alex_games_android_jni SHARED
35 | alex_games_android_jni.cpp)
36 |
37 | #SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,liblua_core.a")
38 | target_include_directories(alex_games_android_jni PUBLIC "${SRC_DIR}/game_api")
39 | target_include_directories(alex_games_android_jni PUBLIC "${SRC_DIR}/game_api/libzip_out")
40 | # target_compile_options(alexgames_core PRIVATE "-pie")
41 | # target_compile_options(alexgames_core PRIVATE "-fPIE")
42 | #target_compile_options(alexgames_core PRIVATE "-fPIC")
43 | target_link_libraries(alex_games_android_jni
44 | PRIVATE
45 | alexgames_core
46 | alexgames_c_dict
47 | android
48 | log dl)
49 | # "-Wl,--no-warn-shared-textrel" "-w" "-frtti")
50 |
51 |
--------------------------------------------------------------------------------
/src/html/css/style_dark.css:
--------------------------------------------------------------------------------
1 | body.dark {
2 | background-color: #000000;
3 | }
4 |
5 | body.dark .main {
6 | border:1px solid black;
7 | background-color:#111111;
8 | }
9 |
10 | body.dark .title {
11 | text-align:center;
12 | }
13 |
14 | body.dark h1,
15 | body.dark h2,
16 | body.dark h3,
17 | body.dark h4,
18 | body.dark h5,
19 | body.dark h6,
20 | body.dark button,
21 | body.dark p,
22 | body.dark span,
23 | body.dark label,
24 | body.dark select,
25 | body.dark input,
26 | body.dark li {
27 | font-family:sans-serif;
28 | color:#ccc;
29 | }
30 |
31 | body.dark a.no_underline {
32 | color:#ccc;
33 | }
34 |
35 |
36 | body.dark code, body.dark pre {
37 | color:#ccc;
38 | }
39 |
40 | body.dark a {
41 | color: #55f;
42 | }
43 |
44 | body.dark a.url_span {
45 | color: #00f;
46 | }
47 |
48 | body.dark button,
49 | body.dark select,
50 | body.dark input {
51 | background-color:#222;
52 | border:1px solid #444;
53 | }
54 |
55 | body.dark button:disabled {
56 | background-color:#222;
57 | color:#333;
58 | }
59 |
60 | body.dark button:hover:enabled {
61 | background-color:#444;
62 | border:1px solid #666;
63 | }
64 |
65 | /* while being clicked */
66 | body.dark button:active:enabled {
67 | background-color:#666;
68 | color: #ccc;
69 | border:1px solid #ccc;
70 | }
71 |
72 | body.dark .popup {
73 | background-color:#111111ee;
74 | border-radius:15px;
75 | border:1px solid grey;
76 | }
77 |
78 | body.dark .overlay {
79 | background-color:#111111dd;
80 | }
81 |
82 |
83 | body.dark .status {
84 | background-color:#22222255;
85 | border:1px dashed #555;
86 | }
87 |
88 | body.dark .status_error {
89 | color:#800;
90 | }
91 |
92 | body.dark .game_title {
93 | background-color: #222;
94 | }
95 | body.dark .game_row {
96 | background-color: #222;
97 | }
98 |
99 | body.dark .game_choice_popup:after {
100 | background-image: linear-gradient(to bottom, #00000000, #444444ff 95%);
101 | }
102 |
103 | body.dark .close_button {
104 | background-color: #400;
105 | }
106 |
107 | body.dark .url_container {
108 | border: 1px solid white;
109 | background-color: grey;
110 | }
111 |
112 | body.dark .not_supported {
113 | color: #585858;
114 | }
115 |
--------------------------------------------------------------------------------
/img/wooden_board.svg:
--------------------------------------------------------------------------------
1 |
2 |
68 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/swarm/swarm_main.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | --
3 | -- TODO better AoE damage:
4 | -- hard to do much AoE damage when the attacks are consumed as soon as they hit the edge of a mob of enemies, especially the hammer.
5 | -- should mark them as "remove in 300 ms" or something, so they get some time to do more damage.
6 | -- maybe also only let them do a certain amount of damage
7 | --
8 | -- TODO:
9 | -- * add touch dirpad, refactor into common library for use with other games like thrust and hospital/bound
10 | --
11 | --]]
12 | local core = require("games/swarm/swarm_core")
13 | local draw = require("games/swarm/swarm_draw")
14 | local keyboard_input = require("games/swarm/swarm_keyboard_input")
15 | local alexgames = require("alexgames")
16 |
17 | local FPS = 60
18 | --local FPS = 2
19 | local MS_PER_FRAME = math.floor(1000/FPS)
20 | local player_idx = 1
21 |
22 | local is_paused = false
23 |
24 | local height = 480
25 | local width = 480
26 |
27 | local g_state = {
28 | ui = draw.init(height, width),
29 | game = core.new_state(1),
30 | key_state = keyboard_input.new_key_state(),
31 | }
32 |
33 | function update()
34 | draw.draw_state(g_state.game, g_state.ui, player_idx)
35 | if not is_paused then
36 | core.update_state(g_state.game, MS_PER_FRAME)
37 | end
38 | end
39 |
40 | function handle_key_evt(evt, code)
41 | local handled = false
42 | if code == "KeyP" and evt == "keydown" then
43 | is_paused = not is_paused
44 | local pause_str
45 | if is_paused then
46 | pause_str = "paused"
47 | else
48 | pause_str = "unpaused"
49 | end
50 | alexgames.set_status_msg(string.format("Game %s. (Press \"P\" to toggle)", pause_str))
51 | handled = true
52 | end
53 | local info = keyboard_input.get_move_vec_from_key_evt(g_state.key_state, evt, code)
54 | handled = handled or info.handled
55 | core.set_player_move_vec(g_state.game, player_idx, info.vec)
56 | return handled
57 | end
58 |
59 | function handle_touch_evt(evt, touches)
60 | local actions = draw.handle_touch_evts(g_state.ui, evt, touches)
61 | for _, action in ipairs(actions) do
62 | if action.action_type == draw.ACTION_PLAYER_VEC_CHANGE then
63 | core.set_player_move_vec(g_state.game, player_idx, action.new_player_vec)
64 | end
65 | end
66 | end
67 |
68 | alexgames.set_timer_update_ms(MS_PER_FRAME)
69 | alexgames.enable_evt("key")
70 | alexgames.enable_evt("touch")
71 |
--------------------------------------------------------------------------------
/src/html/css/style_very_dark.css:
--------------------------------------------------------------------------------
1 | body.very_dark {
2 | background-color: #050505;
3 | }
4 |
5 | body.very_dark .main {
6 | border:1px solid black;
7 | background-color:#000;
8 | }
9 |
10 | body.very_dark .title {
11 | text-align:center;
12 | }
13 |
14 | body.very_dark h1,
15 | body.very_dark h2,
16 | body.very_dark h3,
17 | body.very_dark h4,
18 | body.very_dark h5,
19 | body.very_dark h6,
20 | body.very_dark button,
21 | body.very_dark p,
22 | body.very_dark span,
23 | body.very_dark label,
24 | body.very_dark select,
25 | body.very_dark input,
26 | body.very_dark li {
27 | font-family:sans-serif;
28 | color:#888;
29 | }
30 |
31 | body.dark a.no_underline {
32 | color:#888;
33 | }
34 |
35 | body.very_dark code, body.very_dark pre {
36 | color:#888;
37 | }
38 |
39 | body.very_dark button,
40 | body.very_dark select,
41 | body.very_dark input {
42 | background-color:#222;
43 | border:1px solid #444;
44 | }
45 |
46 |
47 | body.dark button:disabled {
48 | background-color:#222;
49 | color:#333;
50 | }
51 |
52 | body.very_dark button:hover:enabled {
53 | background-color:#444;
54 | border:1px solid #666;
55 | }
56 |
57 | /* while being clicked */
58 | body.very_dark button:active:enabled {
59 | background-color:#666;
60 | color: #ccc;
61 | border:1px solid #ccc;
62 | }
63 |
64 | body.very_dark .popup {
65 | background-color:#111111ee;
66 | border-radius:15px;
67 | border:1px solid grey;
68 | }
69 |
70 | body.very_dark .overlay {
71 | background-color:#111111dd;
72 | }
73 |
74 |
75 | body.very_dark .status {
76 | background-color:#22222255;
77 | border:1px dashed #555;
78 | }
79 |
80 | body.very_dark .status_error {
81 | color:#800;
82 | }
83 |
84 | body.very_dark .game_title {
85 | background-color: #222;
86 | }
87 | body.very_dark .game_row {
88 | background-color: #222;
89 | }
90 |
91 | body.very_dark .game_choice_popup:after {
92 | background-image: linear-gradient(to bottom, #00000000, #444444ff 95%);
93 | }
94 |
95 | body.very_dark .close_button {
96 | background-color: #200;
97 | }
98 |
99 | body.very_dark .url_container {
100 | border: 1px solid #444;
101 | background-color: #888;
102 | }
103 |
104 | body.very_dark .not_supported {
105 | color: #444;
106 | }
107 |
--------------------------------------------------------------------------------
/src/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'org.jetbrains.kotlin.android'
3 |
4 | android {
5 | compileSdkVersion 31
6 | ndkVersion = '21.2.6472646'
7 |
8 | defaultConfig {
9 | applicationId "net.alexbarry.alexgames"
10 | minSdkVersion 24
11 | targetSdkVersion 31
12 | versionCode 3
13 | versionName "0.0.4"
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | externalNativeBuild {
26 | cmake {
27 | path "src/main/cpp/CMakeLists.txt"
28 | // Specifying external directory for native build files because they get big
29 | // and I'm running out of room in my cloud storage backup
30 | // buildStagingDirectory "C:/tmp/android_native_build/alex_games/"
31 | }
32 | }
33 |
34 |
35 | flavorDimensions 'cpuArch'
36 | productFlavors {
37 | arm8 {
38 | dimension 'cpuArch'
39 | ndk {
40 | abiFilters 'arm64-v8a', 'armeabi-v7a'
41 | }
42 | }
43 | x86_64 {
44 | dimension 'cpuArch'
45 | ndk {
46 | abiFilters 'x86_64', 'x86'
47 | }
48 | }
49 | universal {
50 | dimension 'cpuArch'
51 | // include all default ABIs. with NDK-r16, it is:
52 | // armeabi-v7a, arm64-v8a, x86, x86_64
53 | }
54 | }
55 | namespace 'net.alexbarry.alexgames'
56 |
57 |
58 | }
59 |
60 | dependencies {
61 | implementation fileTree(dir: 'libs', include: ['*.jar'])
62 |
63 | api 'org.nanohttpd:nanohttpd:2.3.1'
64 | api 'org.nanohttpd:nanohttpd-websocket:2.3.1'
65 |
66 | implementation 'androidx.appcompat:appcompat:1.2.0'
67 | implementation 'com.google.android.material:material:1.3.0'
68 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
69 | implementation 'androidx.navigation:navigation-fragment:2.3.4'
70 | implementation 'androidx.navigation:navigation-ui:2.3.4'
71 | implementation 'androidx.webkit:webkit:1.4.0'
72 | testImplementation 'junit:junit:4.12'
73 | }
74 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/fluid_mix/fluid_mix_serialize.lua:
--------------------------------------------------------------------------------
1 | local serialize = {}
2 |
3 | local serialize_lib = require("libs/serialize/serialize")
4 |
5 | serialize.VERSION = 2
6 |
7 | function serialize.serialize(state)
8 | local output = ""
9 | output = output .. serialize_lib.serialize_byte(serialize.VERSION)
10 | output = output .. serialize_lib.serialize_byte(state.num_segments)
11 | output = output .. serialize_lib.serialize_byte(#state.vials)
12 | for _, vial in ipairs(state.vials) do
13 | output = output .. serialize_lib.serialize_byte(#vial)
14 | for _, seg_val in ipairs(vial) do
15 | output = output .. serialize_lib.serialize_byte(seg_val)
16 | end
17 | end
18 | output = output .. serialize_lib.serialize_u64(state.seed_x)
19 | output = output .. serialize_lib.serialize_u64(state.seed_y)
20 |
21 | return output
22 | end
23 |
24 | function serialize.deserialize(bytes)
25 | local state = {}
26 | bytes = serialize_lib.bytestr_to_byteary(bytes)
27 | local version
28 | -- version 1, I didn't have a version number for this one,
29 | -- and had 14 vials with... 4 segments each and 3 empty ones
30 | -- TODO remove this, there is probably some combination of parameters
31 | -- where versions > 1 can have the same number of bytes
32 | if #bytes == 2 + 14 + (14-3)*4 + 4*2 then
33 | version = 1
34 | else
35 | version = serialize_lib.deserialize_byte(bytes)
36 | if version ~= serialize.VERSION then
37 | error(string.format("Unhandled fluid_mix serialized state version %d", version))
38 | end
39 | end
40 | state.num_segments = serialize_lib.deserialize_byte(bytes)
41 | state.vials = {}
42 | local vial_count = serialize_lib.deserialize_byte(bytes)
43 | for _=1,vial_count do
44 | local segs_in_vial = serialize_lib.deserialize_byte(bytes)
45 | local vial = {}
46 | for _=1,segs_in_vial do
47 | table.insert(vial, serialize_lib.deserialize_byte(bytes))
48 | end
49 | table.insert(state.vials, vial)
50 | end
51 |
52 | if version == 1 then
53 | -- This is what I did before, but it's wrong-- on wxWidgets at least,
54 | -- the seed can be greater than 32 bits
55 | state.seed_x = serialize_lib.deserialize_s32(bytes)
56 | state.seed_y = serialize_lib.deserialize_s32(bytes)
57 | elseif version == serialize.VERSION then
58 | state.seed_x = serialize_lib.deserialize_u64(bytes)
59 | state.seed_y = serialize_lib.deserialize_u64(bytes)
60 | end
61 |
62 | assert(#bytes == 0)
63 |
64 | return state
65 | end
66 |
67 | return serialize
68 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/life/life_main.lua:
--------------------------------------------------------------------------------
1 | local life_core = require("games/life/life_core")
2 | local life_draw = require("games/life/life_draw")
3 | local alexgames = require("alexgames")
4 |
5 | local BTN_ID_TOGGLE_PLAY_PAUSE = "toggle_play_pause"
6 | local BTN_ID_STEP = "step"
7 | local BTN_ID_RANDOM = "random"
8 | local BTN_ID_CLEAR = "clear"
9 |
10 | local cell_size = 10
11 | local board_width = 480
12 | local board_height = 480
13 | --local cells_y = 40
14 | --local cells_x = 30
15 | local cells_y = math.floor(board_height/cell_size)
16 | local cells_x = math.floor(board_width/cell_size)
17 |
18 | local state = nil
19 | local is_drawing = true
20 |
21 | function draw_board_internal()
22 | life_core.update_state(state)
23 | life_draw.update(life_core.get_active_board(state))
24 | end
25 |
26 | function update()
27 | if is_drawing then
28 | draw_board_internal()
29 | end
30 | end
31 |
32 | function handle_user_clicked(y_coords, x_coords)
33 | local cell_pos = life_draw.coords_to_cell_idx(y_coords, x_coords)
34 | life_core.toggle_cell_state(state, cell_pos)
35 | life_draw.update(life_core.get_active_board(state))
36 | end
37 |
38 | function handle_btn_clicked(btn_id)
39 | if btn_id == BTN_ID_STEP then
40 | life_core.update_state(state)
41 | life_draw.update(life_core.get_active_board(state))
42 | elseif btn_id == BTN_ID_TOGGLE_PLAY_PAUSE then
43 | is_drawing = not is_drawing
44 | elseif btn_id == BTN_ID_RANDOM then
45 | life_core.random_board(state)
46 | life_draw.update(life_core.get_active_board(state))
47 | elseif btn_id == BTN_ID_CLEAR then
48 | life_core.clear_board(state)
49 | life_draw.update(life_core.get_active_board(state))
50 | else
51 | print(string.format("Unhandled btn_id \"%s\"", btn_id))
52 | end
53 | end
54 |
55 | function get_state()
56 | -- TODO it wouldn't be unreasonable to implement importing/exporting state for this, but
57 | -- since it's more of a tech demo than a game, I don't want to bother
58 | -- with it right now.
59 | return nil
60 | end
61 |
62 | life_draw.init(cell_size)
63 |
64 | function start_game()
65 | alexgames.create_btn(BTN_ID_TOGGLE_PLAY_PAUSE, "Play/pause", 1)
66 | alexgames.create_btn(BTN_ID_STEP, "Step", 1)
67 | alexgames.create_btn(BTN_ID_RANDOM, "Random", 1)
68 | alexgames.create_btn(BTN_ID_CLEAR, "Clear", 1)
69 |
70 | state = life_core.new_state(cells_y, cells_x)
71 |
72 | alexgames.set_timer_update_ms(math.floor(1000/20))
73 | end
74 |
--------------------------------------------------------------------------------
/img/cards/blank_card.svg:
--------------------------------------------------------------------------------
1 |
2 |
71 |
--------------------------------------------------------------------------------
/img/cards/card_highlight.svg:
--------------------------------------------------------------------------------
1 |
2 |
71 |
--------------------------------------------------------------------------------
/src/lua_scripts/games/test/timer_test.lua:
--------------------------------------------------------------------------------
1 |
2 | local alexgames = require("alexgames")
3 |
4 | local TEXT_SIZE = 12
5 | local PADDING = 5
6 | local TEXT_COLOUR = "#ff0000"
7 |
8 | local BTN_ID_TIMER1_TOGGLE = "timer1_toggle"
9 | local BTN_ID_TIMER2_TOGGLE = "timer2_toggle"
10 |
11 | local TIMER1_PERIOD_MS = 1000
12 | local TIMER2_PERIOD_MS = 1500
13 |
14 | local timer1 = nil
15 | local timer2 = nil
16 |
17 | local program_start_time = 0
18 |
19 | local total_updates = 0
20 | local recent_updates = {}
21 |
22 | local function internal_draw_board()
23 | alexgames.draw_clear()
24 |
25 | for i, info in ipairs(recent_updates) do
26 | local y = (TEXT_SIZE + PADDING) * (i)
27 | local msg = string.format("%3.3f: update fired, dt_ms: %d", info.time_ms/1000, info.dt_ms)
28 | alexgames.draw_text(msg, TEXT_COLOUR, y, 0, TEXT_SIZE, alexgames.TEXT_ALIGN_LEFT)
29 | end
30 |
31 | alexgames.draw_text(string.format("Timer 1 (1 s) handle: %s", timer1), TEXT_COLOUR,
32 | 400, 0, TEXT_SIZE, alexgames.TEXT_ALIGN_LEFT)
33 | alexgames.draw_text(string.format("Timer 2 (1.5 s) handle: %s", timer2), TEXT_COLOUR,
34 | 400 + TEXT_SIZE + PADDING, 0, TEXT_SIZE, alexgames.TEXT_ALIGN_LEFT)
35 | alexgames.draw_refresh()
36 | end
37 |
38 | function update(dt_ms)
39 | local time_ms = alexgames.get_time_ms() - program_start_time
40 | total_updates = total_updates + 1
41 | table.insert(recent_updates, { dt_ms = dt_ms, time_ms = time_ms })
42 | while #recent_updates > 15 do
43 | table.remove(recent_updates, 1)
44 | end
45 |
46 | internal_draw_board()
47 | end
48 |
49 | function handle_btn_clicked(btn_id)
50 | if btn_id == BTN_ID_TIMER1_TOGGLE then
51 | if timer1 == nil then
52 | timer1 = alexgames.set_timer_update_ms(TIMER1_PERIOD_MS)
53 | else
54 | alexgames.delete_timer(timer1)
55 | timer1 = nil
56 | end
57 | else
58 | if timer2 == nil then
59 | timer2 = alexgames.set_timer_update_ms(TIMER2_PERIOD_MS)
60 | else
61 | alexgames.delete_timer(timer2)
62 | timer2 = nil
63 | end
64 | end
65 |
66 | internal_draw_board()
67 | end
68 |
69 |
70 | function start_game()
71 | program_start_time = alexgames.get_time_ms()
72 | timer1 = alexgames.set_timer_update_ms(TIMER1_PERIOD_MS)
73 | timer2 = alexgames.set_timer_update_ms(TIMER2_PERIOD_MS)
74 |
75 | -- TODO remove
76 | --alexgames.delete_timer(timer1)
77 | --timer1 = nil
78 |
79 | alexgames.create_btn(BTN_ID_TIMER1_TOGGLE, "Toggle timer 1", 1)
80 | alexgames.create_btn(BTN_ID_TIMER2_TOGGLE, "Toggle timer 2", 1)
81 | end
82 |
--------------------------------------------------------------------------------
/src/android/app/src/main/java/net/alexbarry/alexgames/network/ClientSession.java:
--------------------------------------------------------------------------------
1 | package net.alexbarry.alexgames.network;
2 |
3 | import android.util.Log;
4 |
5 | import net.alexbarry.alexgames.util.StringFuncs;
6 |
7 | import java.io.IOException;
8 | import java.net.Socket;
9 |
10 | public class ClientSession {
11 |
12 | private static final String TAG = "ClientSession";
13 |
14 | public interface Callback {
15 | void recv(byte[] data, int len);
16 | void disconnected();
17 | }
18 |
19 | private final Runnable thread_handler = new Runnable() {
20 | @Override
21 | public void run() {
22 | byte[] buff = new byte[4096];
23 | while (true) {
24 | try {
25 | int len = recv_data(buff);
26 | if (len <= 0) {
27 | break;
28 | }
29 | callback.recv(buff, len);
30 | } catch (IOException e) {
31 | Log.e(TAG, "IOException reading from socket", e);
32 | callback.disconnected();
33 | break;
34 | }
35 | }
36 | }
37 | };
38 | private final Thread thread = new Thread(thread_handler);
39 |
40 | private final Socket socket;
41 | private final Callback callback;
42 | private String name;
43 |
44 |
45 | public static ClientSession createFromAddr(String addr, int port, Callback callback) throws IOException {
46 | Socket socket = new Socket(addr, port);
47 | return new ClientSession(socket, callback);
48 | }
49 |
50 | void set_name(String name) {
51 | this.name = name;
52 | }
53 |
54 |
55 | ClientSession(Socket socket, Callback callback) {
56 | this.socket = socket;
57 | this.callback = callback;
58 | thread.start();
59 | }
60 |
61 | public void send_message(byte[] data, int len) throws IOException {
62 | Log.d(TAG, String.format("Sending msg to %s: %s",
63 | get_name(), StringFuncs.byteary_to_nice_str(data, len)));
64 | this.socket.getOutputStream().write(data, 0, len);
65 | this.socket.getOutputStream().flush();
66 | }
67 |
68 | private int recv_data(byte[] buff) throws IOException {
69 | return this.socket.getInputStream().read(buff);
70 | }
71 |
72 | public String get_name() {
73 | return this.name;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/img/piece_highlight.svg:
--------------------------------------------------------------------------------
1 |
2 |
72 |
--------------------------------------------------------------------------------