diff options
author | Tor Andersson <tor@ccxvii.net> | 2021-05-01 00:48:35 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2021-05-01 00:48:35 +0200 |
commit | 652852e3104ce4020de53231ee7691a4970439d6 (patch) | |
tree | 57a053cb2104520e240cd44a4dfb9f92fd5ede07 /views | |
parent | 156f7f8546890c6406001061dae199f8320ca83b (diff) | |
download | server-652852e3104ce4020de53231ee7691a4970439d6.tar.gz |
Add server and lobby code.
Diffstat (limited to 'views')
-rw-r--r-- | views/about.ejs | 83 | ||||
-rw-r--r-- | views/banned.ejs | 3 | ||||
-rw-r--r-- | views/change_password.ejs | 15 | ||||
-rw-r--r-- | views/create.ejs | 22 | ||||
-rw-r--r-- | views/error.ejs | 1 | ||||
-rw-r--r-- | views/header.ejs | 32 | ||||
-rw-r--r-- | views/index.ejs | 19 | ||||
-rw-r--r-- | views/info.ejs | 83 | ||||
-rw-r--r-- | views/join.ejs | 85 | ||||
-rw-r--r-- | views/login.ejs | 15 | ||||
-rw-r--r-- | views/profile.ejs | 84 | ||||
-rw-r--r-- | views/signup.ejs | 18 | ||||
-rw-r--r-- | views/users.ejs | 16 |
13 files changed, 476 insertions, 0 deletions
diff --git a/views/about.ejs b/views/about.ejs new file mode 100644 index 0000000..ed1b54d --- /dev/null +++ b/views/about.ejs @@ -0,0 +1,83 @@ +<%- include('header', { title: "Rally the Troops!" }) %> +<style>li img{height:1.0em;vertical-align:middle}</style> + +<p> +Rally the Troops! is created and maintained by Tor Andersson. +It is an open source project, and you can find the code on <a href="https://github.com/ccxvii/rally-the-troops">GitHub</a>. + +<h2> +Tips & Tricks +</h2> + +<ul> + +<li> +Open a separate browser tab or window for each side when playing solo. + +<li> +Use the middle mouse button to drag and scroll around the map. + +<li> +The <i>Enter</i> and <i>Escape</i> keys open and close the chat box. + +<li> +To invite your friends to a private game, send them the address of the join page. + +<li> +Chat messages can only be seen by players who are part of a game. +They are hidden from observers. + +<li> +The <img src="/images/cog.svg"> menu has links to rules, player aids and other reference material. +In some games you can also choose between alternative graphics and layout options. + +<li> +The <img src="/images/earth-africa-europe.svg"> button hides all counters and markers, +if you need to check something on the map that is obscured. + +<li> +The <img src="/images/scroll-quill.svg"> button hides the game log and player status displays, so you can +see more of the map. + +<li> +The <img src="/images/chat-bubble.svg"> button lights up if you have unread chat messages. + +</ul> + +<h2> +Licensing +</h2> + +<p> +All games are used with consent from their respective rights holders. + +<p> +Icons are sourced from <a href="https://game-icons.net">game-icons.net</a> +by Delapouite, Lorc, and others under the +<a href="https://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a> license. + +<!-- +<h2> +Other Games +</h2> + +<p> +Here are some web sites where you can play other historical games: + +<dl> +<dt><a href="https://www.boardgamearena.com/">boardgamearena.com</a> +<dd>Polis +<dd>Unconditional Surrender +<dt><a href="http://civ.rol-play.com/">civ.rol-play.com</a> +<dd>Advanced Civilization +<dt><a href="https://paronglans.com/">paronglans.com</a> +<dd>Julius Caesar +<dt><a href="http://playfriedrich.com/">playfriedrich.com</a> +<dd>Friedrich +<dt><a href="https://www.yucata.de/">yucata.de</a> +<dd>A Few Acres of Snow +<dd>Pax Porfiriana +<dd>Polis +<dd>Sekigahara +</dl> +--> diff --git a/views/banned.ejs b/views/banned.ejs new file mode 100644 index 0000000..4c08bc2 --- /dev/null +++ b/views/banned.ejs @@ -0,0 +1,3 @@ +<%- include('header', { title: "Banned" }) %> +<p> +Sorry, but this IP or account has been banned. diff --git a/views/change_password.ejs b/views/change_password.ejs new file mode 100644 index 0000000..ab15a4a --- /dev/null +++ b/views/change_password.ejs @@ -0,0 +1,15 @@ +<%- include('header', { title: "Change password" }) %> +<form action="/change_password" method="post"> +<p> +Name: <%= user.name %> +<p> +Mail: <%= user.mail %> +<p> +<label for="password">Old Password: </label><br> +<input type="password" id="password" name="password" required> +<p> +<label for="newpass">New Password: </label><br> +<input type="password" id="newpass" name="newpass" required> +<p> +<button type="submit">Change password</button> +</form> diff --git a/views/create.ejs b/views/create.ejs new file mode 100644 index 0000000..a23fab5 --- /dev/null +++ b/views/create.ejs @@ -0,0 +1,22 @@ +<%- include('header', { title: title.title_name }) %> +<style>form{display:block;margin-left:200px;}</style> +<a href="/info/<%= title.title_id %>"><img class="logo" src="/<%= title.title_id %>/cover.jpg"></a> +<form action="/create/<%= title.title_id %>" method="post"> +<p> +Scenario:<br> +<select id="scenario" name="scenario"> +<% scenarios.forEach((scenario) => { %> +<option value="<%= scenario %>"><%= scenario %></option> +<% }); %> +</select> +<p> +Description:<br> +<input type="text" autocomplete="off" id="description" name="description" size="50"> +<p> +<label> +<input type="checkbox" id="private" name="private" value="private"> +<span>Private</span> +</label> +<p> +<button type="submit">Create</button> +</form> diff --git a/views/error.ejs b/views/error.ejs new file mode 100644 index 0000000..b7d9632 --- /dev/null +++ b/views/error.ejs @@ -0,0 +1 @@ +<%- include('header', { title: "Error" }) %> diff --git a/views/header.ejs b/views/header.ejs new file mode 100644 index 0000000..9e101dd --- /dev/null +++ b/views/header.ejs @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> +<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> +<% if (typeof refresh != 'undefined' && refresh > 0) { %><meta http-equiv="refresh" content="<%= refresh %>"><% } %> +<link rel="icon" href="/images/rally-the-troops.png"> +<link rel="stylesheet" href="/fonts/fonts.css"> +<link rel="stylesheet" href="/style.css"> +<title><%= title %></title> +</head> +<body> +<div class="header"> +<div><a href="/"><img src="/images/rally-the-troops.svg" width="48" height="48"></a></div> +<div> +<span><a href="/about">About</a></span> +<% + if (user) { + %><span><a href="/profile">Profile (<%= user.name %>)</a></span><% + } else { + %><span><a href="/signup">Signup</a></span><% + %><span><a href="/login">Login</a></span><% + } +%> +</div> +</div> +<div class="main"> +<h1><%= title %></h1> +<% + if (typeof message != 'undefined' && message.length > 0) { + %><p class="error"><%= Array.isArray(message) ? message.join("\n") : message %></p><% + } +%> diff --git a/views/index.ejs b/views/index.ejs new file mode 100644 index 0000000..a9abeff --- /dev/null +++ b/views/index.ejs @@ -0,0 +1,19 @@ +<%- include('header', { title: "Rally the Troops!" }) %> +<style> +.list { display: flex; flex-wrap: wrap; justify-content: left; } +.list a { margin: 1em; display: block; } +.list img { box-shadow: 2px 2px 4px 0px rgba(0,0,0,0.5); } +</style> + +<p> +Rally the Troops! is a website where you can play historic games with other +players. + +<p> +Registration and use is free, and there are no ads. + +<div class="list"> +</div> + +<p> +Join the <a href="https://discord.gg/CBrTh8k84A">Discord</a> server to find players or report bugs. diff --git a/views/info.ejs b/views/info.ejs new file mode 100644 index 0000000..27cb543 --- /dev/null +++ b/views/info.ejs @@ -0,0 +1,83 @@ +<%- include('header', { title: title.title_name, refresh: (user ? 300 : 0) }) %> +<img class="logo" src="/<%= title.title_id %>/cover.jpg"> +<%- include('../public/' + title.title_id + '/about.html') %> +<br clear=left> +<p> +Read more about the game on +<a href="https://boardgamegeek.com/boardgame/<%= title.bgg %>">boardgamegeek.com</a>. + +<% if (user) { %> + +<h2>Open Games</h2> +<table class="wide"> +<tr><th>ID<th>Scenario<th>Owner<th>Description<th>Created<th> +<% if (open_games.length > 0) { %> +<% open_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td><%= row.scenario %> +<td><%= row.owner_name %> +<td><%= row.description %> +<td class="nowrap"><%= row.ctime %> +<td><a href="/join/<%= row.game_id %>">Join</a> +<% }); } else { %> +<tr><td colspan="6">No open games. +<% } %> +</table> + +<p> +<a href="/create/<%= title.title_id %>">Create a new game</a>. + +<% if (active_games.length > 0) { %> +<h2>Active Games</h2> +<table class="wide"> +<tr><th>ID<th>Scenario<th>Players<th>Description<th>Changed<th>Turn<th> +<% active_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td><%= row.scenario %> +<td><%= row.players.join(", ") %> +<td><%= row.description %> +<td class="nowrap"><%= row.mtime %> +<% + if (row.your_turn) { + %><td class="your_turn"><%= row.active %><% + } else { + %><td><%= row.active %><% + } + let me = row.players.reduce((n,p) => n + (p === user.name ? 1 : 0), 0); + if (me == 1) { + %><td><a href="/play/<%= row.game_id %>">Play</a><% + } else if (me > 1) { + %><td><a href="/join/<%= row.game_id %>">Play</a><% + } else { + %><td><a href="/join/<%= row.game_id %>">View</a><% + } +%> +<% }); %> +</table> +<% } %> + +<% if (finished_games.length > 0) { %> +<h2>Finished Games</h2> +<table class="wide"> +<tr><th>ID<th>Scenario<th>Players<th>Description<th>Finished<th>Result<th> +<% finished_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td><%= row.scenario %> +<td><%= row.players.join(", ") %> +<td><%= row.description %> +<td class="nowrap"><%= row.mtime %> +<td><%= row.result %> +<td><a href="/join/<%= row.game_id %>">View</a> +<% }); %> +</table> +<% } %> + +<% } else { %> + +<p> +Login to create or join a game. + +<% } %> diff --git a/views/join.ejs b/views/join.ejs new file mode 100644 index 0000000..810e0f4 --- /dev/null +++ b/views/join.ejs @@ -0,0 +1,85 @@ +<%- include('header', { title: game.title_name, refresh: game.status == 0 ? 15 : 0 }) %> +<script> +function confirm_delete(status) { + let warning = "Are you sure you want to DELETE this game?"; + if (window.confirm(warning)) + window.open("/delete/<%= game.game_id %>"); +} +</script> + +<a href="/info/<%= game.title_id %>"><img class="logo" src="/<%= game.title_id %>/cover.jpg"></a> + +<p> +Owner: <%= game.owner_name %> +<p> +Scenario: <%= game.scenario %> +<p> +Description: <%= game.description || "No description." %> + +<br clear=left> + +<p> +<table> +<tr> +<% + roles.forEach((role) => { + %><th><%= role.role %><% + }); +%> +<tr> +<% + roles.forEach((role) => { + if (game.active == role.role || game.active == "Both" || game.active == "All") { + %><td style="min-width:9em" class="your_turn"><% + } else { + %><td style="min-width:9em"><% + } + let p = players.find(p => p.role == role.role); + if (game.status == 0) { + if (p) { + if ((p.user_id == user.user_id) || (game.owner_id == user.user_id)) { + %><a style="color:red;text-decoration:none" href="/part/<%= game.game_id %>/<%= p.user_id %>/<%= p.role %>">❌</a> <% + %><%= p.name %><% + } else { + %><%= p.name %><% + } + } else { + %><a href="/join/<%= game.game_id %>/<%= role.role %>">Join</a><% + } + } else { + if (p) { + if (p.user_id == user.user_id) { + %><a href="/play/<%= game.game_id %>/<%= p.role %>">Play</a><% + } else { + %><%= p.name %><% + } + } else { + %><i>Empty</i><% + } + } + }); + if (game.status > 0 && !players.some(p => p.user_id == user.user_id)) { + %> + <tr><td colspan="<%= roles.length %>"><a href="/play/<%= game.game_id %>/Observer">View</a> + <% + } +%> +</table> + +<p> +<% + if (game.status == 0) { + if (players.length == roles.length) { + if (game.owner_id == user.user_id) { + %><form action="/start/<%= game.game_id %>"><button type="submit">Start!</button></form><% + } else { + %>Waiting for <%= game.owner_name %> to start the game.<% + } + } else { + %>Waiting for players to join the game.<% + } + } + if (game.owner_id == user.user_id && (game.status == 0 || solo)) { + %><p><br><button onclick="confirm_delete()">Delete</button><% + } +%> diff --git a/views/login.ejs b/views/login.ejs new file mode 100644 index 0000000..a5e2546 --- /dev/null +++ b/views/login.ejs @@ -0,0 +1,15 @@ +<%- include('header', { title: "Login" }) %> +<% if (user) { %> +<p>You're already logged in! +<% } else { %> +<form action="/login" method="post"> +<p> +<label for="username">Name: </label><br> +<input type="text" id="username" name="username" required> +<p> +<label for="password">Password: </label><br> +<input type="password" id="password" name="password" required> +<p> +<button type="submit">Login</button> +</form> +<% } %> diff --git a/views/profile.ejs b/views/profile.ejs new file mode 100644 index 0000000..60f1ff9 --- /dev/null +++ b/views/profile.ejs @@ -0,0 +1,84 @@ +<%- include('header', { title: "Rally the Troops!", refresh: (active_games.length > 0 ? 300 : 0) }) %> +<style>td.nowrap a { color: black; text-decoration: none; }</style> + +<img class="logo" src="<%= avatar %>" width="80" height="80"> +<p> +Welcome, <%= user.name %>! +<p> +Your mail address is <%= user.mail %>. + +<br clear=left> + +<p> +<a href="/change_password">Change password</a> + +<p> +<a href="/logout">Logout</a> + +<% if (open_games.length > 0) { %> +<h2>Open Games</h2> +<table class="wide"> +<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Created<th> +<% open_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td><%= row.scenario %> +<td><%= row.players.join(", ") %> +<td><%= row.description %> +<td class="nowrap"><%= row.ctime %> +<td><a href="/join/<%= row.game_id %>">Join</a> +<% }); %> +</table> +<% } %> + +<% if (active_games.length > 0) { %> +<h2>Active Games</h2> +<table class="wide"> +<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Changed<th>Turn<th> +<% active_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td><%= row.scenario %> +<td><%= row.players.join(", ") %> +<td><%= row.description %> +<td class="nowrap"><%= row.mtime %> +<% + if (row.your_turn) { + %><td class="your_turn"><%= row.active %><% + } else { + %><td><%= row.active %><% + } + if (row.players.reduce((n,p) => n + (p === user.name ? 1 : 0), 0) == 1) { + %><td><a href="/play/<%= row.game_id %>">Play</a><% + } else { + %><td><a href="/join/<%= row.game_id %>">Play</a><% + } +%> +<% }); %> +</table> +<% } %> + +<% if (finished_games.length > 0) { %> +<h2>Finished Games</h2> +<table class="wide"> +<tr><th>ID<th>Game<th>Scenario<th>Players<th>Description<th>Finished<th>Result<th> +<% finished_games.forEach((row) => { %> +<tr> +<td><%= row.game_id %> +<td class="nowrap"><a href="/info/<%= row.title_id %>"><%= row.title_name %></a> +<td><%= row.scenario %> +<td><%= row.players.join(", ") %> +<td><%= row.description %> +<td class="nowrap"><%= row.mtime %> +<td><%= row.result %> +<td><a href="/join/<%= row.game_id %>">View</a> +<% }); %> +</table> +<% } %> + +<% if (open_games.length == 0 && active_games.length == 0 && finished_games.length == 0) { %> +<p> +You don't have any current or finished games. +<% } %> diff --git a/views/signup.ejs b/views/signup.ejs new file mode 100644 index 0000000..819da3f --- /dev/null +++ b/views/signup.ejs @@ -0,0 +1,18 @@ +<%- include('header', { title: "Signup" }) %> +<% if (user) { %> +<p>You're already logged in! +<% } else { %> +<form action="/signup" method="post"> +<p> +<label for="username">Name: </label><br> +<input type="text" id="username" name="username" required> +<p> +<label for="mail">Mail: </label><br> +<input type="text" id="mail" name="mail" required> +<p> +<label for="password">Password: </label><br> +<input type="password" id="password" name="password" required> +<p> +<button type="submit">Create Account</button> +</form> +<% } %> diff --git a/views/users.ejs b/views/users.ejs new file mode 100644 index 0000000..a8f5c7d --- /dev/null +++ b/views/users.ejs @@ -0,0 +1,16 @@ +<%- include('header', { title: "User list" }) %> +<style> +td.avatar{padding:0;width:80px;} +td.avatar img{display:block;width:80px;height:80px;} +</style> + +<table class="wide"> +<tr><th>Avatar<th>Name<th>Member since<th>Last seen + +<% userList.forEach((row) => { %> +<tr> +<td class="avatar"><img src="<%= row.avatar %>"> +<td><%= row.name %> +<td><%= row.ctime %> +<td><%= row.atime %> +<% }); %> |