BUGFIX: train, untrain, purchase, sell while spying

This commit is contained in:
2019-06-06 06:44:16 +10:00
parent 29da939815
commit 92385bb72d
3 changed files with 236 additions and 192 deletions
+4
View File
@@ -24,8 +24,12 @@ let excluded = [ //messages that should not be logged
'Can\'t train while attacking', 'Can\'t train while attacking',
'Can\'t untrain while attacking', 'Can\'t untrain while attacking',
'Can\'t train while spying',
'Can\'t untrain while spying',
'Can\'t purchase while attacking', 'Can\'t purchase while attacking',
'Can\'t sell while attacking', 'Can\'t sell while attacking',
'Can\'t purchase while spying',
'Can\'t sell while spying',
'Purchase made', 'Purchase made',
'Sale made', 'Sale made',
+110 -90
View File
@@ -4,7 +4,7 @@ require('dotenv').config();
//utilities //utilities
let { log } = require('../common/utilities.js'); let { log } = require('../common/utilities.js');
let { getStatistics, getOwned, isAttacking } = require('./utilities.js'); let { getStatistics, getOwned, isAttacking, isSpying } = require('./utilities.js');
const equipmentRequest = (connection) => (req, res) => { const equipmentRequest = (connection) => (req, res) => {
//validate the credentials //validate the credentials
@@ -95,81 +95,91 @@ const purchaseRequest = (connection) => (req, res) => {
return; return;
} }
//get the player's gold isSpying(connection, req.body.id, (err, spying) => {
let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err; if (err) throw err;
//just in case if (spying) {
if (results.length === 0) { res.status(400).write(log('Can\'t purchase while spying', req.body.id, req.body. token, req.body.type, req.body.name));
res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token));
res.end(); res.end();
return; return;
} }
//get the stats for all objects //get the player's gold
getStatistics((err, { statistics }) => { let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err; if (err) throw err;
//valid parameters //just in case
if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { if (results.length === 0) {
res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name)); res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token));
res.end(); res.end();
return; return;
} }
//enough gold? //get the stats for all objects
if (results[0].gold < statistics[req.body.type][req.body.name].cost) { getStatistics((err, { statistics }) => {
res.status(400).write(log('Not enough gold', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//for sale?
if (!statistics[req.body.type][req.body.name].visible || !statistics[req.body.type][req.body.name].purchasable) {
res.status(400).write(log('Item not for sale', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//high enough level?
if (results[0].scientists < statistics[req.body.type][req.body.name].scientistsRequired) {
res.status(400).write(log('Not enough scientists', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//purchase approved.
//get the user's current item data (including quantity)
let query = 'SELECT * FROM equipment WHERE accountId = ? AND name = ?;';
connection.query(query, [req.body.id, req.body.name], (err, results) => {
if (err) throw err; if (err) throw err;
//add to or update the record //valid parameters
let query; if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) {
if (results.length > 0) { res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name));
query = 'UPDATE equipment SET quantity = quantity + 1 WHERE accountId = ? AND name = ? AND type = ?;'; res.end();
} else { return;
query = 'INSERT INTO equipment (accountId, name, type, quantity) VALUES (?, ?, ?, 1);';
} }
connection.query(query, [req.body.id, req.body.name, req.body.type], (err) => { //enough gold?
if (results[0].gold < statistics[req.body.type][req.body.name].cost) {
res.status(400).write(log('Not enough gold', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//for sale?
if (!statistics[req.body.type][req.body.name].visible || !statistics[req.body.type][req.body.name].purchasable) {
res.status(400).write(log('Item not for sale', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//high enough level?
if (results[0].scientists < statistics[req.body.type][req.body.name].scientistsRequired) {
res.status(400).write(log('Not enough scientists', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//purchase approved.
//get the user's current item data (including quantity)
let query = 'SELECT * FROM equipment WHERE accountId = ? AND name = ?;';
connection.query(query, [req.body.id, req.body.name], (err, results) => {
if (err) throw err; if (err) throw err;
//remove gold from the user's account //add to or update the record
let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;'; let query;
connection.query(query, [statistics[req.body.type][req.body.name].cost, req.body.id], (err) => { if (results.length > 0) {
query = 'UPDATE equipment SET quantity = quantity + 1 WHERE accountId = ? AND name = ? AND type = ?;';
} else {
query = 'INSERT INTO equipment (accountId, name, type, quantity) VALUES (?, ?, ?, 1);';
}
connection.query(query, [req.body.id, req.body.name, req.body.type], (err) => {
if (err) throw err; if (err) throw err;
//return the new owned data //remove gold from the user's account
getOwned(connection, req.body.id, (err, results) => { let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;';
connection.query(query, [statistics[req.body.type][req.body.name].cost, req.body.id], (err) => {
if (err) throw err; if (err) throw err;
res.status(200).json(Object.assign(results)); //return the new owned data
res.end(); getOwned(connection, req.body.id, (err, results) => {
if (err) throw err;
log('Purchase made', req.body.id, req.body.token, req.body.type, req.body.name); res.status(200).json(Object.assign(results));
res.end();
log('Purchase made', req.body.id, req.body.token, req.body.type, req.body.name);
});
}); });
}); });
}); });
@@ -202,65 +212,75 @@ const sellRequest = (connection) => (req, res) => {
return; return;
} }
//get the player's item quantity isSpying(connection, req.body.id, (err, spying) => {
let query = 'SELECT * FROM equipment WHERE accountId = ? AND type = ? AND name = ?;';
connection.query(query, [req.body.id, req.body.type, req.body.name], (err, results) => {
if (err) throw err; if (err) throw err;
if (results.length === 0) { if (spying) {
res.status(400).write(log('Can\'t sell something you don\'t own', req.body.id, req.body. token, req.body.type, req.body.name)); res.status(400).write(log('Can\'t sell while spying', req.body.id, req.body. token, req.body.type, req.body.name));
res.end(); res.end();
return; return;
} }
//get the stats for all objects //get the player's item quantity
getStatistics((err, { statistics }) => { let query = 'SELECT * FROM equipment WHERE accountId = ? AND type = ? AND name = ?;';
connection.query(query, [req.body.id, req.body.type, req.body.name], (err, results) => {
if (err) throw err; if (err) throw err;
//valid parameters if (results.length === 0) {
if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { res.status(400).write(log('Can\'t sell something you don\'t own', req.body.id, req.body. token, req.body.type, req.body.name));
res.status(400).write(log('Invalid equipment sell parameters', req.body.id, req.body.token, req.body.type, req.body.name));
res.end(); res.end();
return; return;
} }
//for sale? //get the stats for all objects
if (!statistics[req.body.type][req.body.name].saleable) { getStatistics((err, { statistics }) => {
res.status(400).write(log('Item can\'t be sold', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//sale approved.
//add gold to the user's account
let query = 'UPDATE profiles SET gold = gold + ? WHERE accountId = ?;';
connection.query(query, [Math.floor(statistics[req.body.type][req.body.name].cost/2), req.body.id], (err) => {
if (err) throw err; if (err) throw err;
//remove the item from the inventory //valid parameters
let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;'; if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) {
connection.query(query, [results[0].id], (err) => { res.status(400).write(log('Invalid equipment sell parameters', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//for sale?
if (!statistics[req.body.type][req.body.name].saleable) {
res.status(400).write(log('Item can\'t be sold', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
//sale approved.
//add gold to the user's account
let query = 'UPDATE profiles SET gold = gold + ? WHERE accountId = ?;';
connection.query(query, [Math.floor(statistics[req.body.type][req.body.name].cost/2), req.body.id], (err) => {
if (err) throw err; if (err) throw err;
//return the new owned data //remove the item from the inventory
getOwned(connection, req.body.id, (err, results) => { let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;';
connection.query(query, [results[0].id], (err) => {
if (err) throw err; if (err) throw err;
res.status(200).json(Object.assign(results)); //return the new owned data
res.end(); getOwned(connection, req.body.id, (err, results) => {
log('Sale made', req.body.id, req.body.token, req.body.type, req.body.name);
//Extra: clean the database
let query = 'DELETE FROM equipment WHERE quantity <= 0;';
connection.query(query, (err) => {
if (err) throw err; if (err) throw err;
log('Cleaned database', 'equipment sale'); res.status(200).json(Object.assign(results));
res.end();
log('Sale made', req.body.id, req.body.token, req.body.type, req.body.name);
//Extra: clean the database
let query = 'DELETE FROM equipment WHERE quantity <= 0;';
connection.query(query, (err) => {
if (err) throw err;
log('Cleaned database', 'equipment sale');
});
}); });
}); });
}) });
}); });
}); });
}); });
+122 -102
View File
@@ -4,7 +4,7 @@ require('dotenv').config();
//libraries //libraries
let CronJob = require('cron').CronJob; let CronJob = require('cron').CronJob;
let { isAttacking } = require('./utilities.js'); let { isAttacking, isSpying } = require('./utilities.js');
//utilities //utilities
let { logDiagnostics } = require('./diagnostics.js'); let { logDiagnostics } = require('./diagnostics.js');
@@ -189,67 +189,77 @@ const trainRequest = (connection) => (req, res) => {
return; return;
} }
//determine the cost of the training TODO: make these global for the client too isSpying(connection, req.body.id, (err, spying) => {
let cost = 0;
switch(req.body.role) {
case 'soldier':
cost = 100;
break;
case 'spy':
cost = 300;
break;
case 'scientist':
cost = 120;
break;
}
//verify that the user has a high enough gold and recruit balance
let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err; if (err) throw err;
if (results[0].recruits <= 0) { if (spying) {
res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token)); res.status(400).write(log('Can\'t train while spying', req.body.id));
res.end(); res.end();
return; return;
} }
if (results[0].gold < cost) { //determine the cost of the training TODO: make these global for the client too
res.status(400).write(log('Not enough gold', results[0].gold, req.body.id, req.body.token)); let cost = 0;
res.end(); switch(req.body.role) {
return; case 'soldier':
cost = 100;
break;
case 'spy':
cost = 300;
break;
case 'scientist':
cost = 120;
break;
} }
//update the profile with new values (NOTE: extra protection for network latency) //verify that the user has a high enough gold and recruit balance
let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;'; let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;';
connection.query(query, [cost, req.body.role === 'soldier' ? 1 : 0, req.body.role === 'spy' ? 1 : 0, req.body.role === 'scientist' ? 1 : 0, req.body.id, cost], (err) => { connection.query(query, [req.body.id], (err, results) => {
if (err) throw err; if (err) throw err;
//send the new profile data as JSON (NOTE: possible duplication) if (results[0].recruits <= 0) {
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token));
connection.query(query, [req.body.id], (err, results) => { res.end();
return;
}
if (results[0].gold < cost) {
res.status(400).write(log('Not enough gold', results[0].gold, req.body.id, req.body.token));
res.end();
return;
}
//update the profile with new values (NOTE: extra protection for network latency)
let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;';
connection.query(query, [cost, req.body.role === 'soldier' ? 1 : 0, req.body.role === 'spy' ? 1 : 0, req.body.role === 'scientist' ? 1 : 0, req.body.id, cost], (err) => {
if (err) throw err; if (err) throw err;
//check just in case //send the new profile data as JSON (NOTE: possible duplication)
if (results.length !== 1) { let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token)); connection.query(query, [req.body.id], (err, results) => {
res.end(); if (err) throw err;
return;
}
//results.length === 1 //check just in case
res.status(200).json({ if (results.length !== 1) {
username: results[0].username, res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token));
gold: results[0].gold, res.end();
recruits: results[0].recruits, return;
soldiers: results[0].soldiers, }
spies: results[0].spies,
scientists: results[0].scientists //results.length === 1
res.status(200).json({
username: results[0].username,
gold: results[0].gold,
recruits: results[0].recruits,
soldiers: results[0].soldiers,
spies: results[0].spies,
scientists: results[0].scientists
});
res.end();
log('Train executed', results[0].username, req.body.role, req.body.id, req.body.token);
}); });
res.end();
log('Train executed', results[0].username, req.body.role, req.body.id, req.body.token);
}); });
}); });
}); });
@@ -286,72 +296,82 @@ const untrainRequest = (connection) => (req, res) => {
return; return;
} }
//verify that the user has a high enough balance isSpying(connection, req.body.id, (err, spying) => {
let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err; if (err) throw err;
if (req.body.role === 'soldier' && results[0].soldiers <= 0) { if (spying) {
res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token)); res.status(400).write(log('Can\'t untrain while spying', req.body.id, req.body.token));
res.end(); res.end();
return; return;
} }
if (req.body.role === 'spy' && results[0].spies <= 0) { //verify that the user has a high enough balance
res.status(400).write(log('Not enough spies', results[0].spies, req.body.id, req.body.token)); let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
res.end(); connection.query(query, [req.body.id], (err, results) => {
return;
}
if (req.body.role === 'scientist' && results[0].scientists <= 0) {
res.status(400).write(log('Not enough scientists', results[0].scientists, req.body.id, req.body.token));
res.end();
return;
}
//hacky
let roleName = null;
if (req.body.role === 'soldier') {
roleName = 'soldiers';
} else if (req.body.role === 'spy') {
roleName = 'spies';
} else if (req.body.role === 'scientist') {
roleName = 'scientists';
} else {
res.status(400).write(log('Unknown role received', req.body.role, req.body.id, req.body.token));
res.end();
return;
}
//update the profile with new values (NOTE: extra protection for network latency)
let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${roleName} > 0;`;
connection.query(query, [roleName === 'soldiers' ? 1 : 0, roleName === 'spies' ? 1 : 0, roleName === 'scientists' ? 1 : 0, req.body.id], (err) => {
if (err) throw err; if (err) throw err;
//send the new profile data as JSON (NOTE: possible duplication) if (req.body.role === 'soldier' && results[0].soldiers <= 0) {
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token));
connection.query(query, [req.body.id], (err, results) => { res.end();
return;
}
if (req.body.role === 'spy' && results[0].spies <= 0) {
res.status(400).write(log('Not enough spies', results[0].spies, req.body.id, req.body.token));
res.end();
return;
}
if (req.body.role === 'scientist' && results[0].scientists <= 0) {
res.status(400).write(log('Not enough scientists', results[0].scientists, req.body.id, req.body.token));
res.end();
return;
}
//hacky
let roleName = null;
if (req.body.role === 'soldier') {
roleName = 'soldiers';
} else if (req.body.role === 'spy') {
roleName = 'spies';
} else if (req.body.role === 'scientist') {
roleName = 'scientists';
} else {
res.status(400).write(log('Unknown role received', req.body.role, req.body.id, req.body.token));
res.end();
return;
}
//update the profile with new values (NOTE: extra protection for network latency)
let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${roleName} > 0;`;
connection.query(query, [roleName === 'soldiers' ? 1 : 0, roleName === 'spies' ? 1 : 0, roleName === 'scientists' ? 1 : 0, req.body.id], (err) => {
if (err) throw err; if (err) throw err;
//check just in case //send the new profile data as JSON (NOTE: possible duplication)
if (results.length !== 1) { let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token)); connection.query(query, [req.body.id], (err, results) => {
res.end(); if (err) throw err;
return;
}
//results.length === 1 //check just in case
res.status(200).json({ if (results.length !== 1) {
username: results[0].username, res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token));
gold: results[0].gold, res.end();
recruits: results[0].recruits, return;
soldiers: results[0].soldiers, }
spies: results[0].spies,
scientists: results[0].scientists //results.length === 1
res.status(200).json({
username: results[0].username,
gold: results[0].gold,
recruits: results[0].recruits,
soldiers: results[0].soldiers,
spies: results[0].spies,
scientists: results[0].scientists
});
res.end();
log('Untrain executed', results[0].username, roleName, req.body.id, req.body.token);
}); });
res.end();
log('Untrain executed', results[0].username, roleName, req.body.id, req.body.token);
}); });
}); });
}); });