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 untrain while attacking',
'Can\'t train while spying',
'Can\'t untrain while spying',
'Can\'t purchase while attacking',
'Can\'t sell while attacking',
'Can\'t purchase while spying',
'Can\'t sell while spying',
'Purchase made',
'Sale made',
+110 -90
View File
@@ -4,7 +4,7 @@ require('dotenv').config();
//utilities
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) => {
//validate the credentials
@@ -95,81 +95,91 @@ const purchaseRequest = (connection) => (req, res) => {
return;
}
//get the player's gold
let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
isSpying(connection, req.body.id, (err, spying) => {
if (err) throw err;
//just in case
if (results.length === 0) {
res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token));
if (spying) {
res.status(400).write(log('Can\'t purchase while spying', req.body.id, req.body. token, req.body.type, req.body.name));
res.end();
return;
}
//get the stats for all objects
getStatistics((err, { statistics }) => {
//get the player's gold
let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err;
//valid parameters
if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) {
res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name));
//just in case
if (results.length === 0) {
res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token));
res.end();
return;
}
//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) => {
//get the stats for all objects
getStatistics((err, { statistics }) => {
if (err) throw err;
//add to or update the record
let query;
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);';
//valid parameters
if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) {
res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name));
res.end();
return;
}
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;
//remove gold from the user's account
let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;';
connection.query(query, [statistics[req.body.type][req.body.name].cost, req.body.id], (err) => {
//add to or update the record
let query;
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;
//return the new owned data
getOwned(connection, req.body.id, (err, results) => {
//remove gold from the user's account
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;
res.status(200).json(Object.assign(results));
res.end();
//return the new owned data
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;
}
//get the player's item quantity
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) => {
isSpying(connection, req.body.id, (err, spying) => {
if (err) throw err;
if (results.length === 0) {
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));
if (spying) {
res.status(400).write(log('Can\'t sell while spying', req.body.id, req.body. token, req.body.type, req.body.name));
res.end();
return;
}
//get the stats for all objects
getStatistics((err, { statistics }) => {
//get the player's item quantity
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;
//valid parameters
if(!statistics[req.body.type] || !statistics[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));
if (results.length === 0) {
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.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) => {
//get the stats for all objects
getStatistics((err, { statistics }) => {
if (err) throw err;
//remove the item from the inventory
let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;';
connection.query(query, [results[0].id], (err) => {
//valid parameters
if(!statistics[req.body.type] || !statistics[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();
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;
//return the new owned data
getOwned(connection, req.body.id, (err, results) => {
//remove the item from the inventory
let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;';
connection.query(query, [results[0].id], (err) => {
if (err) throw err;
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) => {
//return the new owned data
getOwned(connection, req.body.id, (err, results) => {
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
let CronJob = require('cron').CronJob;
let { isAttacking } = require('./utilities.js');
let { isAttacking, isSpying } = require('./utilities.js');
//utilities
let { logDiagnostics } = require('./diagnostics.js');
@@ -189,67 +189,77 @@ const trainRequest = (connection) => (req, res) => {
return;
}
//determine the cost of the training TODO: make these global for the client too
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) => {
isSpying(connection, req.body.id, (err, spying) => {
if (err) throw err;
if (results[0].recruits <= 0) {
res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token));
if (spying) {
res.status(400).write(log('Can\'t train while spying', req.body.id));
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;
//determine the cost of the training TODO: make these global for the client too
let cost = 0;
switch(req.body.role) {
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)
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) => {
//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;
//send the new profile data as JSON (NOTE: possible duplication)
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (results[0].recruits <= 0) {
res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token));
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;
//check just in case
if (results.length !== 1) {
res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token));
res.end();
return;
}
//send the new profile data as JSON (NOTE: possible duplication)
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err;
//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
//check just in case
if (results.length !== 1) {
res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token));
res.end();
return;
}
//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;
}
//verify that the user has a high enough balance
let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
isSpying(connection, req.body.id, (err, spying) => {
if (err) throw err;
if (req.body.role === 'soldier' && results[0].soldiers <= 0) {
res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token));
if (spying) {
res.status(400).write(log('Can\'t untrain while spying', req.body.id, req.body.token));
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) => {
//verify that the user has a high enough balance
let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err;
//send the new profile data as JSON (NOTE: possible duplication)
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (req.body.role === 'soldier' && results[0].soldiers <= 0) {
res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token));
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;
//check just in case
if (results.length !== 1) {
res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token));
res.end();
return;
}
//send the new profile data as JSON (NOTE: possible duplication)
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
connection.query(query, [req.body.id], (err, results) => {
if (err) throw err;
//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
//check just in case
if (results.length !== 1) {
res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token));
res.end();
return;
}
//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);
});
});
});