Giter VIP home page Giter VIP logo

tactics's People

Contributors

aristocattsci avatar dependabot[bot] avatar enijar avatar gr8st avatar krystofnovotny avatar latin-programmer avatar lime-green avatar mainshayne233 avatar pongstylin avatar seand88 avatar shmiddty avatar yetibob avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tactics's Issues

Windows, NodeJs 12 error: RangeError [ERR_UNKNOWN_MODULE_FORMAT]: Unknown module format: esm

Reproduce:
After

git clone ...
npm config set script-shell "C:\Program Files\Git\bin\bash.exe"
cd tactics
npm install
npm start

I'm running into this error msg:

λ npm start

> [email protected] start C:\hij\github\tactics
> NODE_ENV=development webpack --watch --progress --hide-modules & node --experimental-modules --loader ./resolver.mjs --require dotenv/config src/server.js || true

(node:13796) ExperimentalWarning: The ESM module loader is experimental.
(node:13796) ExperimentalWarning: --loader is an experimental feature. This feature could change at any time
internal/modules/cjs/loader.js:830
      internalBinding('task_queue').triggerFatalException(
                                    ^

RangeError [ERR_UNKNOWN_MODULE_FORMAT]: Unknown module format: esm
    at Loader.getModuleJob (internal/modules/esm/loader.js:163:15)
    at async Loader.import (internal/modules/esm/loader.js:127:17)

C:\hij\github\tactics (master -> origin) ([email protected])
λ  10% building 0/0 modules 0 active
webpack is watching the files…

Hash: b3a08d73a6508f84301d
Version: webpack 4.33.0
Time: 6046ms
Built at: 2019-06-10 13:39:03
             Asset      Size       Chunks                    Chunk Names
  chaos-app.min.js  25.8 KiB    chaos-app  [emitted]         chaos-app
classic-app.min.js  26.2 KiB  classic-app  [emitted]         classic-app
 createGame.min.js   184 KiB   createGame  [emitted]         createGame
faceoff-app.min.js  25.4 KiB  faceoff-app  [emitted]         faceoff-app
   game-app.min.js  36.4 KiB     game-app  [emitted]         game-app
    tactics.min.js  4.96 MiB      tactics  [emitted]  [big]  tactics
         ww.min.js   830 KiB           ww  [emitted]  [big]  ww
Entrypoint tactics [big] = tactics.min.js
Entrypoint faceoff-app = faceoff-app.min.js
Entrypoint chaos-app = chaos-app.min.js
Entrypoint classic-app = classic-app.min.js
Entrypoint game-app = game-app.min.js
Entrypoint ww [big] = ww.min.js
Entrypoint createGame = createGame.min.js

Break Card Logic out of Board Class

In my quest to make the board class less monolithic by breaking out some logic to a separate Game class, I have determined that the card should continue to be managed by the board object, but via instantiating a new Card class. The Card object has a method that can take a unit object argument. Alternatively, it has a method that displays an arbitrary notice using the Trophy avatar and "Champion" name. The Trophy unit is instantiated and cached by the Card class.

Make it possible to deselect target by touching empty tile

So, the game does some subtle things to help protect against misclicks when using touch devices. But one of those measures can cause confusion for the player and needs to be adjusted for a better player experience. Here are the requirements:

  1. If your first action is to move a unit from A to B, selecting an orange attack tile shows you red-orange target tiles. If you touch an empty tile at this point. it should revert you back to viewing orange attack tiles. Right now, it does nothing, which is "usually" bad (see the 3rd requirement).
  2. If you select a unit without having made any action yet, switching to attack mode will show you orange attack tiles. Selecting an attack tile will show you red-orange target tiles. If you touch an empty tile at this point, it should deselect the unit completely. Right now, it does nothing, which is "usually" bad (see the 3rd requirement).
  3. Regardless of whether a selected unit is in "move", "attack", or "target" mode, touching any empty tile that is adjacent to a highlighted tile should do nothing. Fingers easily miss the intended target, so this protects against unintentional deselection of units or target tiles.

A word about the implementation...
Right now, only highlighted tiles are "interactive". That is, tapping them fires a tile selection event. If a tile is not highlighted, then the board receives the tap and will perform the appropriate deselection requirements. To give special treatment to some empty tiles, but not others, the simplest path forward is to "highlight" them with a transparent color. That way the transparent "highlighted" tiles adjacent to opaque highlighted tiles can intercept the event and prevent deselection.

Option for timed turns

This would allow people to choose to play real-time (timer enabled) or over a long period (no timer)

async functions in data adapters

I would like to contribute the mysqladapter code i have been working on but it requires that some calls to dataadapter methods be async.

here is an example method from my data adapter which returns a promise.

  async createGame(stateData) {
    let insertQuery = "INSERT INTO game ( name, created_by) values ( ?, ? )";
    return this.query(insertQuery, [stateData.name, stateData.createdBy]).then( result => {
        //create game object with new game id and save to database
       let gameId = result.insertId;
       stateData.id = gameId;
       let game = Game.create(stateData);
       return this.saveGame(game).then( res =>{
         return gameId;
       }, err => { return 0; })         
    }, err =>{
       return 0;
    })
  }

example await call from the game service

let gameId = await dataAdapter.createGame(stateData);

I think this would be a good convention going forward for the adapters, so it can handle async operations. It looks like the file operations are all synchronous.

Would like some opinions before I open up any pull request.

Thanks
Sean

WakeLock Screen During Game

People who wants to stare at the game board long enough for their screen to start dimming would appreciate this feature. Basically, prevent the screen from shutting off anytime you're playing a game. If the game ends, release the lock and allow the screen to shut off.

A standard WakeLock API spec is still under development, but there are other means for preventing a screen from shutting off, including playing an invisible, silent, and tiny video on a loop. An appropriate cross-browser NodeJS package would need to be selected and used to accomplish this purpose.

Unit creation

I'm programming on my own tactics since a few years in C++. I did a lot of thinking and work, how to use the images. Because I read, adobe is smartly loading and unloading images so the RAM isn't exploding and I didn't want to write my own image loader and unloader, I decided to use spritesheets. I exported all informations about the animations out of the orginal .swf files, so I got the spritesheets and the coordinate vectors of those. With this you will be able to write your own unit animation parser so you wont have to write a animation file for each unit by your self. This saves a lot of work and makes handling the images much more easy and saves a bit of overhead performance.

But here is an example:
The image:
https://i.imgur.com/8Pg9oHA.png
And the corresponding vectors for this image:

(function(window) {
sprite_3418_(Ambusher) = function() {
	this.initialize();
}
sprite_3418_(Ambusher)._SpriteSheet = new SpriteSheet({images: ["ambusher_normal.png"], frames: [[0,0,82,57,0,41,43.95],[0,0,82,57,0,41,43.95],[82,0,54,60,0,29,50.95],[136,0,65,63,0,42,53.95],[201,0,69,64,0,48,55.95],[270,0,66,63,0,50,57.95],[270,0,66,63,0,50,57.95],[336,0,52,61,0,50,64.95],[270,0,66,63,0,50,57.95],[201,0,69,64,0,48,55.95],[136,0,65,63,0,42,53.95],[82,0,54,60,0,29,50.95],[388,0,55,66,0,27,48.95],[443,0,58,67,0,25,47.95],[0,67,50,67,0,17,44.95],[336,0,52,61,0,6,36.95],[270,0,66,63,0,6,29.950000000000003],[50,67,69,64,0,4,27.950000000000003],[136,0,65,63,0,-2,25.950000000000003],[82,0,54,60,0,-15,22.950000000000003],[82,0,54,60,0,-15,22.950000000000003],[119,67,80,57,0,45,43.95],[199,67,82,61,0,50,46.95],[281,67,91,63,0,60,49.95],[372,67,118,80,0,71,65.95],[0,147,74,97,0,32,83.95],[74,147,76,68,0,30,53.95],[150,147,67,71,0,31,54.95],[217,147,65,63,0,31,47.95],[282,147,78,57,0,36,43.95],[282,147,78,57,0,36,43.95],[217,147,65,63,0,31,47.95],[360,147,40,64,0,19,45.95],[400,147,52,61,0,25,50.95],[452,147,50,66,0,12,58.95],[0,244,58,67,0,12,61.95],[58,244,57,66,0,7,62.95],[58,244,57,66,0,7,62.95],[115,244,54,61,0,5,64.95],[58,244,57,66,0,7,62.95],[0,244,58,67,0,12,61.95],[452,147,50,66,0,12,58.95],[400,147,52,61,0,25,50.95],[169,244,66,62,0,39,43.95],[235,244,69,65,0,44,41.95],[304,244,66,63,0,47,39.95],[115,244,54,61,0,49,36.95],[58,244,57,66,0,51,34.95],[370,244,58,67,0,56,33.95],[452,147,50,66,0,56,30.950000000000003],[400,147,52,61,0,69,22.950000000000003],[400,147,52,61,0,69,22.950000000000003],[428,244,49,65,0,27,46.95],[0,311,60,67,0,31,47.95],[60,311,71,65,0,30,46.95],[131,311,74,95,0,19,75.95],[205,311,70,112,0,36,91.95],[275,311,70,63,0,40,41.95],[345,311,75,57,0,42,37.95],[420,311,75,59,0,42,40.95],[0,423,47,64,0,25,45.95],[0,423,47,64,0,25,45.95],[420,311,75,59,0,42,40.95],[47,423,82,61,0,42,45.95],[129,423,54,64,0,26,52.95],[183,423,65,71,0,24,48.95],[248,423,70,72,0,22,47.95],[318,423,66,74,0,17,44.95],[318,423,66,74,0,17,44.95],[384,423,52,73,0,3,39.95],[318,423,66,74,0,17,44.95],[248,423,70,72,0,22,47.95],[183,423,65,71,0,24,48.95],[129,423,54,64,0,26,52.95],[436,423,56,67,0,29,57.95],[0,497,57,69,0,34,59.95],[57,497,51,67,0,34,61.95],[108,497,52,74,0,47,67.95],[160,497,66,75,0,61,72.95],[248,423,70,72,0,66,75.95],[183,423,65,71,0,68,76.95],[129,423,54,64,0,70,80.95],[129,423,54,64,0,70,80.95],[226,497,78,60,0,35,44.95],[304,497,82,67,0,33,45.95],[386,497,91,80,0,32,51.95],[0,577,118,61,0,48,43.95],[118,577,75,114,0,43,104.95],[193,577,77,59,0,47,52.95],[270,577,67,61,0,37,52.95],[337,577,65,62,0,35,50.95],[402,577,78,62,0,43,46.95],[402,577,78,62,0,43,46.95],[337,577,65,62,0,35,50.95],[0,691,40,70,0,22,48.95],[40,691,52,72,0,28,52.95],[92,691,51,67,0,39,47.95],[143,691,58,69,0,47,45.95],[201,691,56,68,0,50,43.95],[201,691,56,68,0,50,43.95],[257,691,54,65,0,50,39.95],[201,691,56,68,0,50,43.95],[143,691,58,69,0,47,45.95],[92,691,51,67,0,39,47.95],[40,691,52,72,0,28,52.95],[311,691,65,73,0,27,58.95],[376,691,69,72,0,26,61.95],[445,691,66,71,0,20,63.95],[257,691,54,65,0,6,67.95],[201,691,56,68,0,6,71.95],[143,691,58,69,0,3,73.95],[92,691,51,67,0,-5,75.95],[40,691,52,72,0,-16,80.95],[40,691,52,72,0,-16,80.95],[0,764,49,71,0,23,48.95],[49,764,61,83,0,31,49.95],[110,764,71,95,0,42,55.95],[181,764,74,92,0,56,64.95],[255,764,70,114,0,35,95.95],[325,764,69,61,0,30,52.95],[394,764,75,68,0,34,51.95],[0,878,75,68,0,34,48.95],[75,878,47,70,0,23,48.95],[75,878,47,70,0,23,48.95],[0,878,75,68,0,34,48.95]]});
var sprite_3418_(Ambusher)_p = sprite_3418_(Ambusher).prototype = new BitmapAnimation();
sprite_3418_(Ambusher)_p.BitmapAnimation_initialize = sprite_3418_(Ambusher)_p.initialize;
sprite_3418_(Ambusher)_p.initialize = function() {
	this.BitmapAnimation_initialize(sprite_3418_(Ambusher)._SpriteSheet);
	this.paused = false;
}
window.sprite_3418_(Ambusher) = sprite_3418_(Ambusher);
}(window));

Let me know if you are interested.

Btw. it's also possible to export .swf movies and embed them into HTML to play them.

PS. I'm coming from the C++ corner, what means I have to learn some things about web development and Javascript. But I will make some contributions in the future to this project. I'm really happy that I found this project.

Upgrade PIXI

The current pixi.js library is a customized variant of PIXI v3. Directly customizing 3rd-party libraries is bad practice and the newest version of PIXI is now at v4. Upgrade the game to use the latest version of PIXI. If possible, do not customize the PIXI code directly, but find an alternative that would not alter the game experience.

MVP Server-Based PvP

Right now it is possible for people to share their screens and play PvP. The next milestone is to play PvP with a server handling the communication.

(MVP) User Requirements:

  1. User A clicks a public link to start a game.
  2. User A is prompted to enter a "display name" if their client is not associated with an account.
  3. Upon submitting a "display name", an account is created and associated with the client.
  4. User A is then provided with a URL that has been tagged with the created game.
  5. User B clicks the URL after User A shares it via email, text, or IM.
  6. User B is prompted to enter a "display name" if their client is not associated with an account.
  7. Upon submitting a "display name", an account is created and associated with the client.
  8. The new game begins and is persisted indefinitely if the players go offline in case they come back.

(FULL) User Requirements:

  1. When launching the app, the client will check to see if it already possesses a token.
  2. If no token was found, then the user is prompted to provide a display name or login with email and password.
  3. If the user provided a display name, then a new account is created without an email or password.
  4. Regardless of new or existing account, a token is required to proceed.
  5. If the app was launched via a Game URL, then the user is presented with the game board.
  6. If the app was not launched via a Game URL, then the user is presented with a lobby where they can chat or see a list of people available to play.
  7. For accounts that don't have an email and password, a button will allow a user to register their account so that it may be accessed on other devices.

(FULL) Authentication/Authorization requirements:

  1. Valid expired tokens must never require the user to log in to obtain new tokens. This is necessary for users that do not have log in credentials, but remains a convenience for users that do.
  2. For better performance, non-expired tokens must not be checked for validity.
  3. More than one client may be logged into the same account at the same time.
  4. A given client may only be logged into one account at any given time.
  5. Token must be protected against unauthorized use by:
    • Assigning each client unique tokens.
    • Refreshing expired tokens such that old tokens are revoked and cannot be used again.
    • *** Automatically revoking the client's token if an attempt is made to use an old token.
      • This requirement no longer seems advisable after realizing that race conditions between multiple browser tabs can result in the accidental use of an old token. I do not want such to cause a user to lose their account if they had not verified it with an email address or other authentication provider.
    • Allowing a user to revoke tokens for one or all clients.
    • Keeping track of each client ID / token pair on the server. (No need to track revoked tokens)

Some comments about implementation, but they are negotiable.

  • When using AWS Cognito, explore not providing a username and using whatever username it uses by default. If a username is required, provide a UUID. Regardless, the "sub" value (User ID generated by AWS Cognito) will not be communicated to clients.
  • A JWT can be used to meet all the authentication/authorization requirements. But, after the JWT expires, it must be exchanged for a new one - assuming the expired token is still valid. I think it is best for the client to exchange tokens every time it is launched. It should also have the ability to unpack the JWT to learn when it expires so that it can proactively exchange tokens again before it expires in the event that the client remains open for longer than the expiration time. Unpacking a JWT should be possible. I believe they are not usually encrypted, but rather "signed" so that they can be read, but not modified (e.g. to increase the expiration value) without a secret key. Every time the JWT is submitted to the server, it checks the signature, but not token validity.
  • The secret key used to sign JWT tokens must be accessible to both the authentication service and any other service that accepts JWT tokens. It may be a single secret key used for all accounts.
  • Since a JWT can be unpacked, it must only contain "claims" that a client may read. But it should also contain sufficient details for server-side validation. The claims should only include data that is relevant for authentication and authorization as opposed to user profile or session data. Some JWT claims are part of the JWT specification and are marked with "(spec)".
    • exp: (spec) The timestamp when the JWT will expire. Very important.
    • iat: (spec) The timestamp when the JWT was issued. This can be used by the client to adjust for an inaccurate time on the local system.
    • sub: (spec) The account ID. This may be the username generated by AWS Cognito (or UUID if generation is not possible or preferable)
    • client_id: The unique ID assigned to the client. If a client tries to exchange a revoked (or never-issued) JWT, then we need this value to revoke the current token for the client that was compromised.
  • Revoking a client's token may not immediately revoke access to the account. If a token has not expired, it is not checked for validity and may be used. I recommend that the token is only checked for validity before it is exchanged for a new one. Since the client may exchange tokens (expired or not) every time it is launched, validity checking would occur with every launch of the client. Even so, the expiration value should be no longer than an hour and may be less.
  • A client submits the JWT token using an "Authorization" header. This applies to all HTTP endpoints including both the authentication and game services.

Two people are assigned to this very large issue. I expect Enijar will be responsible for server-side logic while I will be responsible for client-side logic.

More undo

There are two situations where undo can be permitted, but isn't:

  1. The player passed their turn without taking any action. In this case, the undo operation is completely unavailable.
  2. The player passed without changing direction after attacking. In this case, the player can undo, but only with opponent permission. Once permitted, the attack is undone. Pressing undo once should allow the player to change their direction, which does not require opponent permission. Pressing undo twice would undo the attack, with opponent permission.

The reason #1 does not allow undo is because there are times when the player was forced to pass their turn since all available units are required to wait X number of turns. In this case, an undo should not go back to the previous turn, but back to the last turn the player was able to move, with opponent permission if the opponent has made a move since then. To distinguish between the player passing a turn and the player being forced to pass a turn, the "endTurn" action should have a "forced" boolean property. If true, then the undo skips that turn. If false (omitted), then the undo reverts TO that turn.

The reason #2 doesn't auto approve the undo and allow the player to change direction is simply because only the last action is factored into the decision of whether or not approval is required. And, once approved, it does not recognize that a 'turn' action has not taken place. Such intelligence can be added without changing the data format.

Remove jQuery dependency

The game interacts with the DOM in very few ways, and native JavaScript is far more capable than it was when the game was first created. So, replace all jQuery code with native JavaScript code (or, on occasion, an alternative library for operations such as deep cloning) except for the src/*-app.js files and static/ directory.

Bear in mind that there are plugins that depend upon jQuery, so replacing them will also be necessary.

Scout - tile is not defined

Happens when I attack with the blue scout and move it all the way forward to attack the witch.

Weirdly, the red scout attack worked.

The game just doesn't do anything, and three errors show up with the same message in the console:
unit.js?9fa2:303 Uncaught (in promise) ReferenceError: tile is not defined
at Tactics.Unit.targetLOS (unit.js?9fa2:303)
at Tactics.Unit.calcAttack (unit.js?9fa2:348)
at Tactics.Unit.onAttackFocus (unit.js?9fa2:1830)
at self.getAttackTiles.forEach.tile (unit.js?9fa2:823)
at Array.forEach ()
at Tactics.Unit.highlightAttack (unit.js?9fa2:813)
at Tactics.Unit.showMode (unit.js?9fa2:1144)
at Tactics.Unit.activate (unit.js?9fa2:1191)
at Tactics.Board.setSelectMode (board.js?f9ff:787)
at self.deploy.then (unit.js?9fa2:130)

Suggestions

Macro keys for pre set formations - V formation, etc.
Macro for retreat all - straight line back
Macro for advance all - straight line forward
Additional neutral pills:
Speed Boost
Limited Invulnerability
Wormhole entrance and exit

Notification Page

Before introducing more notifications, we need a page that will provide a history of notifications. The reason for this is so that we never annoy players by popping up multiple notifications on their screen. If there are multiple types of notifications, then we say so and link them to the notifications page. The notification page should also keep track of the most recently seen notification.

In a follow-up ticket, we'll make the notification page accessible from any page on the site via an icon button - similar to Facebook.

Here's a quick list of notification types that will be implemented in follow-up tickets.

  1. Your Turn: Already implemented. Sent when not actively looking at this game as it becomes the player's turn.
  2. You Win! / You Lose!: Sent when not actively looking at this game as the game ends.
  3. New Message: Only in-game chat is supported right now, so only sent when not actively looking at the game in which the message was sent.

Add Lightning Ward Unit

Now that the default gray formation is supported, the next step is all gray units including wards, starting with the Lightning Ward.

Undo button!

As I've been fixing various bugs this month, I decided that this game badly needs an undo button. Right now, it is possible to undo most operations through various means. But the usage and coding of it is fairly complex when weighed against a purpose-designed undo button.

Right now, you can undo various operations like this:

  • Click an empty tile to cancel selection of a unit that has either made no action or has only moved. This functionality will go away. Clicking empty tiles will do nothing. The new means for canceling selection is tapping the selected unit again.
  • Click the attack button after choosing a target to revert back to showing all attack tiles. This functionality will remain since targeting is not, technically, an action.
  • Click the move button after moving, targeting, (not attacking), and/or turning a unit to reset the selected unit back to its original state. This functionality will go away. Once a unit is moved, the move button will be disabled.
  • Click the move or attack button after turning a unit to reset the turn. This functionality will go away. If you turn a unit, both the move and attack buttons will be disabled.
  • It is possible to take back Enchantress attack if you haven't moved yet. It was intentional, but a little strange.

Clicking the undo button will reset the most recent action. For example:

  • If the last action was a turn, it will undo the turn.
  • If the last action was an attack, it will undo the attack if it didn't involve luck. For example, if you attacked with cleric, enchantress, witch, or pyromancer, it will undo the attack and restore affected units to the state before being attacked. We MAY consider also allowing you to take back an attack if a scout, knight, or assassin attacked another unit that can't block either because they have zero blocking, was paralyzed, or because they were attacked from behind. But, if the attack required luck to succeed, you will not be allowed to take it back at this time.
  • If the last action was moving, it will undo the move, restoring the unit to its original position.

Create PoC for Client <=> Server Interaction

This involves creating a webpage that has two side-by-side instances of the game loaded that each represent the two players. The left side is Player 1 and the right side is Player 2. When it is Player 1's turn, Player 2 is unable to move any units but is capable of selecting/viewing units and visa-versa. The two instances of the game will communicate with an instance of a virtual server class that will be responsible for echoing actions taken during a turn to the two client instances.'

As part of the refactoring, the offline apps vs bots (Chaos and Faceoff) will work similar to Player vs Player. That is, the player client instance will communicate with a virtual server instance, which will relay actions between the player and the bot.

All work will be done in the "client" branch until it is complete. Upon completion, the client branch will be merged into master since it should continue to work even when a true server is absent.

Save client-side settings

Certain game settings should be saved and persisted across sessions. This includes:

  • Sound muted vs not muted
  • Board rotation (Placement of YOUR team on the board)
  • Left-or-right placement of button bar in phone landscape orientation

These settings can be saved to localStorage or IndexedDB. This choice is left to the prerogative of the person working on it. Certainly these settings should not be persisted to the server since different clients should have different settings.

Rematch Games

When a game completes, both players should have the option to request a rematch.

Requirements

  • Rematch request status is tracked on the completed game. It tracks each player's disposition toward a rematch, which can be any of "Approved", "Unknown", and "Declined".
  • A rematch can only be requested within 1 week of the game ending.
  • A rematch can only be requested if no opponents have already "Declined" a rematch.
  • A rematch can be requested by a player if they have previously declined or cancelled it as long as the previous two rules aren't violated.
  • A game is in a "rematch requested" state if no players have a "Declined" rematch disposition. In this state, a popup asking for a rematch is presented to players with an "Unknown" rematch disposition. Also, a popup allowing a player to cancel a rematch is presented to players with an "Approved" rematch disposition.
  • When a player requests a rematch, their rematch disposition is changed to "Approved".
  • If a player cancels a rematch request, their rematch disposition is changed to "Declined".
  • After a game ends, a player may choose to proactively "Decline" a rematch even before it is requested.
  • When a game enters the "rematch requested" state, offline players will receive a notification saying that a rematch was requested. Rematch notification should have the same semantics as Your Turn notifications. They should call the server to ensure freshness, grouped when there is more than one, and auto-closed if no rematch requests are pending.
  • Completed games with active rematch requests are displayed in the "Active" game list above the "Your Turn" section. They ALSO appear in the completed games section, per normal.
  • When all players approve a rematch request, a new game is created with the same game type and sets as the old except that the first turn will be awarded to the 2nd-turn player. This player should then receive a notification that it is their turn. This is true regardless of whether the old game had a randomized first turn.

Rework Unit Card Health Status

When viewing a unit using the unit card, it can be harder to assess the health condition of a unit. This game uses words like "Hurt!" and "Dying!" and there is some small text that describes the precise health, but the original game made it look and read better. So, remove "Ready!", "Hurt!" and "Dying!" from the unit card and replace it with a health bar and numbers like this and this.

Manage WebSockets Across Multiple Tabs

Right now a WebSocket connection is created on every tab. This connection can remain open even if tabs are hidden. This environment allows a single user to establish multiple connections with the server. This can be an unnecessary burden on the server. There are changes that would improve the situation:

  • For browsers that support it, a Shared Worker can be accessed from multiple tabs. This worker will manage the WebSocket connection and proxy messages between the server and the tabs.
  • If the page is talking directly to the server and is not using a Shared Worker proxy for any reason, the Page LifeCycle API is used to detect when the page becomes "Hidden" or "Active/Passive" and close and reopen the server connection in response.

Add means for returning to "online" page from in-game.

Some mechanism needs to be added to allow a player to leave a game that is still in progress or had just ended and return to the "online" page. It should not be a "back" button since they might not have just come from the "online" page.

Observe the current game observers

There should be some mechanism by which you can see who-all is currently watching the game. If you want to work on this task, please provide some suggestions on the best way to make this accessible on both large and small screens.

Improve Undo UX

Right now, undo is an event. That is, it is sent with no expectation of a response. However, an undo might not be acted upon in a timely manner. The user might hit the undo button multiple times without any sort of feedback that their undo request was received. To fix the frustration around this, undo events should be converted to undo requests - expecting a response. Until a response is received, a popup is displayed indicating that the undo request is pending. It cannot be cancelled until the server responds saying that the request is approved or that approval is pending.

Status bar broken when unit is killed

First of all, I am so excited to see this project. I loved playing TAO back in the day and hoped it would someday be resurrected. I played around with the idea of trying to do it but never got around to it. Really awesome work so far!

As I was playing around with it just now, I noticed that there is an issue with the status bar breaking when a unit is killed.
screen shot 2019-02-13 at 11 22 09 am
screen shot 2019-02-13 at 11 23 49 am

I hope to be able to contribute to the project sometime soon. I'll try to take a look at the source soon and get up to speed.

Random side setting

When customizing your set, you should be able to specify whether the set can be flipped randomly with each game. This is especially useful for corner sets by randomly switching sides to possibly avoid being countered.

Code Style

There should be some sort of linter config in the project root to reduce issues due to code style conflicts when merging pull requests. Thoughts?

Group push notifications

Right now, if a player receives two "It's Your Turn!" notifications, each from different games, the last notification received will replace the earlier one. This is partly a good thing, because it avoids cluttering up the player's notification area with lots of notifications. But it would be better if the service worker looked for an existing "It's Your Turn!" notification. If one is found, then it will replace the existing notification with one that reads like this:

title: 'It's Your Turn!"
body: "{n} games are waiting..." ({n} is the number of games)
data: (includes a property indicating the number of games)

Upon clicking a notification group such as this, the user is taken to the "online" page instead of any individual game page. At that point, the player may choose which game/turn they want to play first.

Use ES6 class and module syntax

The game source code does not use ES6 classes nor make use of ES6 module syntax. Refactor the game modules to use this syntax without altering the game experience.

When using ES6 constructs, make sure they are compatible with modern browsers. If necessary, the "webpack" module can be used to add shims or otherwise transform the code to something browsers can handle.

Server branch integration with game

I've been working on the server branch getting things setup and ready to be reviewed for a merge into master. However the game doesn't load. I see this in the console:

Uncaught Error: Cannot add resources while the loader is running.
    at Loader.add (Loader.js:336)
    at classic-app.js:309
    at Array.forEach (<anonymous>)
    at load (classic-app.js:305)
    at classic-app.js:265
    at dispatch (jquery.min.js:3)
    at r.handle (jquery.min.js:3)

Steps to reproduce:

• Checkout to the server branch
• Run

make install
cp env/server.example.json env/server.json
cp env/common.example.json env/common.json
make dev -j2

• Open http://localhost:3000/play?mode=faceoff

AWS Cognito Integration

Here is some sample code I've written to try to create a means for logging in without using the generated login page provided by AWS. I don't remember if the code works and it doesn't appear to try to aspire to do anything by obtain a login token. But it is interesting that it is using the "amazon-cognito-identity-js" package. So that might be helpful. To use it, you need the fetch API, which typically only exists in browsers, but I used the "node-fetch" package to make it accessible on the back-end.

const APIError = require('./src/lib/APIError.js');

module.exports = api => {
  if (api.request.method !== 'POST')
    throw new APIError(405, {
      message: 'Only the POST method can be used to login.',
    });

  const username = api.request.params.username;
  if (username === undefined)
    throw new APIError(400, {
      message: 'A username is required to login.',
      source: { parameter: 'username' },
    });

  const password = api.request.params.password;
  if (password === undefined)
    throw new APIError(400, {
      message: 'A password is required to login.',
      source: { parameter: 'password' },
    });

  global.fetch = require('node-fetch');
  const AWSCognito = require('amazon-cognito-identity-js');
  const API = require('node-rest-client').Client;
  const authenticationDetails = new AWSCognito.AuthenticationDetails({
    Username: username,
    Password: password,
  });

  const userPool = new AWSCognito.CognitoUserPool({
    UserPoolId: 'us-east-1_redacted',
    ClientId: 'redactedrab1st130u1kbivbd',
  });

  const cognitoUser = new AWSCognito.CognitoUser({
    Username: username,
    Pool: userPool,
  });

  return new Promise((resolve, reject) => {
    cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: response => {
        resolve({
          bearer_token: response.idToken.jwtToken,
        });
      },

      onFailure: error => {
        reject(new APIError(401, {
          message: 'Failed to login with the supplied credentails.',
          details: [error],
        }));
      },
    });
  });
};

The above code depends on having a pool ID and client ID. The below picture points arrows at where you can obtain them. Also, it is possible to use a login UI generated by AWS in the circled area if we want to get up and running more quickly.

image

Upgrade Sound Library

The game currently uses an old version of Howler. Now that we're in a NodeJS environment, we need to replace it with a NodeJS package. After some review of what is out there, I found some potential candidates:

Custom Unit Sets

Our existing apps hard-codes the set used by all teams. Create a UI that allows a user to create their own set with a similar look & feel to the original game. It will be similar, but not identical. Here are some basic requirements:

  • Display the north end of the board similar to this, except there won't be a trash can, color picker, or avatar picker (MVP).
  • The south end of the board where you pick your units will differ. Each available type of unit will only appear once and cannot be moved.
  • Units can be placed on the board by the easiest means you can think of provided it is both mouse and touch compatible. For example, you might accomplish this by tapping a unit in the pick area to select it, then picking an empty tile. The original game used drag-n-drop, but I don't expect that to be easy.
  • Units can be removed from the board by the easiest means you can think of. For example, you might accomplish this by tapping the unit twice in a row.
  • There is no need to limit the number of picked units at this time. You can setup a game with 20 knights vs 20 witches if you want.

That's it! There is no need to make it possible to play with the custom set or make it possible to define the custom set for both teams. We're just going for MVP here. Just bear in mind that after it is done, we'll be looking to add these features:

  • I'm hoping that the next app we create will be similar to the "Classic" app except you can define the set for both teams before beginning the game. That means the new UI will need a method to export the custom set data for game setup.
  • When defining the sets for multiple player, we need to visually indicate which player is getting customized. So, for example, it might show the top half of the board first. Then, when you click a button to indicate you are done, it will switch. The bottom half of the board will appear and units are picked from above it.
  • It would be nice if we could freely switch between sides. With a click of a button, you can swap between seeing the top board or the bottom board.
  • It would be nice to see a preview of the full board before starting the game.

npm start fails?

Hi .. I get an error when doing npm start:

MacBook-Air:tactics me$ npm start

> [email protected] start /Users/me/Projects/other/tactics
> NODE_ENV=development webpack --watch --progress --hide-modules & node --experimental-modules --loader ./resolver.mjs --require dotenv/config src/server.js || true

(node:4731) ExperimentalWarning: The ESM module loader is experimental.
ReferenceError: URL is not defined
    at file:///Users/me/Projects/other/tactics/resolver.mjs:18:17
    at ModuleJob.run (internal/modules/esm/ModuleJob.js:106:14)
    at <anonymous>
MacBook-Air:tactics me$   0% compiling
webpack is watching the files…

Hash: 6d47d01fa6d1309d4776                                                                
Version: webpack 4.23.1
Time: 3034ms
Built at: 2019-05-09 23:38:13
             Asset      Size       Chunks                    Chunk Names
  chaos-app.min.js  24.4 KiB    chaos-app  [emitted]         chaos-app
classic-app.min.js  24.8 KiB  classic-app  [emitted]         classic-app
 createGame.min.js   157 KiB   createGame  [emitted]         createGame
faceoff-app.min.js    24 KiB  faceoff-app  [emitted]         faceoff-app
   game-app.min.js  32.8 KiB     game-app  [emitted]         game-app
    tactics.min.js  4.85 MiB      tactics  [emitted]  [big]  tactics
         ww.min.js   773 KiB           ww  [emitted]  [big]  ww
Entrypoint tactics [big] = tactics.min.js
Entrypoint faceoff-app = faceoff-app.min.js
Entrypoint chaos-app = chaos-app.min.js
Entrypoint classic-app = classic-app.min.js
Entrypoint game-app = game-app.min.js
Entrypoint ww [big] = ww.min.js
Entrypoint createGame = createGame.min.js

MacBook-Air:tactics me$ 
MacBook-Air:tactics me$ npm --v
6.9.0
MacBook-Air:tactics me$ 

What could be the problem?

Break Game Logic out of Board Class

As we prepare to integrate the client into a server, better abstraction is required of the client. The first step was accomplished while creating the "Undo" button, which is the centralization of all action initiation (e.g. moving, attacking, turning, and passing). This involved adding a lot more game logic to the board class, which isn't ideal. The next step in better abstraction is to create a new "Game" class with these expectations:

  1. The existing app JS files will no longer interface with a board object. Rather, they will interface with a game object.
  2. Roughly 75% of the code in the board class will be transferred to the new Game class.
  3. The game class is responsible for instantiating and managing a board object. This requires moving a little code from the core Tactics JS file to the Game class.
  4. Unlike the rest of the code base, the new class will use ES6 class syntax.

Host / run the game on a server not working?

I tried to host the game on my server, just to see if it works.

I've build the dist and the files where generated in static/ folder. These files I transfered to Zeit Now to test: https://static.thehangrycoder.now.sh/

When I start the game (for example the classic https://static.thehangrycoder.now.sh/classic.html) , I see it gets loaded, but after a while hangs.

When I check the network tab I see a 404's on some POST commands. Is there something I'm missing?

More Units

The original game had a lot of different kinds of units that each have their own images, animations, and sound effects. The images can be obtained by extracting them from the original game's flash files, but it is harder to string them together into their animations. This is a list of all of the animations for a given unit:

  1. Walking (up, down, left, right)
  2. Moving aside to allow another unit to pass (up, down, left, right)
  3. Attacking (up, down, left, right)
  4. Blocking, if applicable (up, down, left, right)
  5. Special attacks (Cleric Heal, Furgon Shrub, Golem Ambusher Stone Throw)

Each frame of each animation typically consists of 3 images: uncolored, colored, and shadow. These 3 images are overlapped to create a complete picture, but must be kept separate since the game is expected to apply a team color to one of them. Ideally, the images should be placed on a spritesheet with a data file that describes how the images should be rendered to reproduce the animations. Rendering information may include the position of each image within the frame or other effects that should be applied to the image (such as rotation, scale, and/or color effects).

If you would like to try to extract this information, please email [email protected] so that I can send you the flash files.

This issue will be resolved once we've identified an efficient strategy for extracting animation data.

Always enable 2-finger pan/zoom

Right now there is a "lock" icon to enable 1-finger panning or 2-finger pan-zooming. It is not convenient to have to unlock it every time you want to pan and/or zoom the board. Since game-play does not require 2-finger gestures, such gestures should always be enabled. But there are some caveats. Requirements:

  1. When locked, 2-finger pan/zooming is enabled.
  2. Once a 2nd-finger is touching the device, all board interactivity should cease. That is, fingers hovering over units should not cause their info cards to pop up, nor should releasing the fingers cause units to become selected.
  3. I am considering removing 1-finger panning and the lock icon altogether to save space in the button bar. This would make the 1st requirement easier since the pan zoom can be set to be enabled at all times. So, only 1-finger panning logic would need to be removed.

Opponent Offline Message

When opening a game in which you are a player and your opponent is not in-game, a temporary message is displayed in the chat window with helpful information on the opponent's online and notification status. It is temporary because it disappears once a message is sent or received.

Message when notification are ON:
If online (but not in-game): Your opponent is online, but not looking at this game right now. They have been notified that it is there turn. Please come back later if they don't show up soon.

If offline: Your opponent is offline. They have been notified that it is there turn. Please come back later if they don't show up soon.

Message when notification are OFF:
If online (but not in-game): Your opponent is online, but not looking at this game right now. Please come back later if they don't show up soon.

If offline: Your opponent is offline right now. Please come back later.

Resources

Hello, I would like to know if the resources can be exported to local files. I would like to make a fully mobile version of the game and get better performance having all images of units locale saved. Anyway, if the domain that are published breaks, get down or dissapears, we lose the resources, and thats not good at all. I would like to have full control of those resources. Do you think thats possible?
thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.