-
-
Save Hidden50/8ade6c00cec861c41715001a319ff415 to your computer and use it in GitHub Desktop.
Scrappie's PS Auction bot script (has a lot of features grown on top of each other. sorry, this code is quite ugly..)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
//////////////////////////////////////////////////////////////////////////////// | |
// // | |
// Requested by Ana1ytic, this is an spl auction implementation // | |
// // | |
//////////////////////////////////////////////////////////////////////////////// | |
// // | |
// Documentation // | |
// .makeauction NAME, STARTMONEY // | |
// if used in a room and user is RO, the auction will bind to the room. // | |
// .auction bind/unbind // | |
// .auction delete // | |
// .auction addmanagers // | |
// .auction allownom TEAMNAME // | |
// .auction stopnom // | |
// .auction nom PLAYER // | |
// .auction bid AMOUNT // | |
// .auction teaminfo TEAMNAME // | |
// // | |
//////////////////////////////////////////////////////////////////////////////// | |
var auctions = global.auctions = require('./../data/auctions.json'); | |
var auction_timer = {}; | |
var auctionsfile_busy = false; | |
var auctionsfile_needUpdate = false; | |
function saveAuctions() { | |
if (auctionsfile_busy) { | |
auctionsfile_needUpdate = true; // file is busy, save afterwards | |
} else { | |
auctionsfile_needUpdate = false; | |
auctionsfile_busy = true; | |
// saving now.. | |
fs.writeFile('./data/auctions.json', JSON.stringify(auctions, null, 4), | |
function (err) { | |
global.auctions = auctions; | |
auctionsfile_busy = false; | |
// after save.. if it's been modified we need to save again. | |
if (err) return console.log(err); | |
if (auctionsfile_needUpdate) | |
saveAuctions(); | |
} | |
); | |
} | |
} | |
function ExtractKeyword(argString, Keywords) { | |
// argString must be an object, so that it can be modified like a var parameter | |
var pos; | |
var target = argString.toLowerCase() + ' '; | |
for (var k in Keywords) { | |
pos = target.indexOf(Keywords[k].toLowerCase() + ' '); | |
if (pos >= 0) { | |
if (argString.substring(0, pos).trim()) | |
continue; // there's letters before the keyword. But it's only a match if it's the first word. | |
var temp = argString.substring(pos + Keywords[k].length).trim(); | |
argString.valueOf = argString.toSource = argString.toString = function() { | |
return temp; | |
}; | |
return Keywords[k]; | |
} | |
} | |
return ''; | |
} | |
//commandparser.Context.prototype.aucBroadcast = function (auction, message) { | |
// if (auction.rooms.indexOf(this.room) < 0) this.pmReply(message); | |
// for (var r in auction.rooms) Bot.say(auction.rooms[r], message); | |
//} | |
Settings.addPermissions(['makeauction', 'auction']); | |
const aucCmds = ['delete', 'bind', 'unbind', 'addmanagers', 'addmanager', 'addteams', | |
'addteam', 'addplayer', 'addplayers', 'allownom', 'stopnom', 'report', 'run', 'stop', 'reset', 'nom', 'nominate', 'bid', 'team', 'teaminfo', 'players']; | |
exports.commands = { | |
makeauction: function(arg, by, room, cmd) { | |
/* creates an auction with (by) as the only owner. If (by) is a room owner, the room the command is | |
used in becomes linked to the auction and any events within it will be broadcast to the room. */ | |
arg = arg.split(',').map( s => s.trim() ); | |
by = toId(by); | |
arg[0] = toId(arg[0]); | |
if (!arg[0]) | |
return this.restrictReply('Usage: ``.makeauction NAME`` or ``.makeauction NAME, STARTMONEY``. If the command is used by a room owner inside a room, the auction will auto-bind to that room and broadcast to it.', 'makeauction'); | |
if (auctions[arg[0]]) | |
return this.restrictReply('An auction with this name already exists.', 'makeauction'); | |
var auction = auctions[arg[0]] = { | |
name: arg[0], | |
startmoney: arg[1] || 100000, | |
owners: [by], | |
rooms: [], // rooms that events in this auction will broadcast to | |
managers: {}, // users able to use management commands | |
teams: {}, // teams that may bid in this auction | |
running: false, | |
allownom: false, // the team currently allowed to nominate | |
nomorder: false, // array that specifies in which order teams get to nominate | |
nomqueue: false, // array with the next planned nominations (last to first) | |
nommedplayer: false, // id of the nominated player | |
bid: false, // current bid (in credits) | |
bidder: false, // last team to bid | |
players: {} // list of players up for auctioning | |
}; | |
this.restrictReply('Auction **' + arg[0] + '** has been created.', 'makeauction'); | |
if (this.can('makeauction')) { | |
auction.rooms.push(room); | |
var oldAuction = auctions.defaults[room]; | |
if (oldAuction) auctions[oldAuction].rooms.filter( s => s !== room ); | |
auctions.defaults[room] = arg[0]; | |
this.restrictReply('**' + auction.name + '** has been bound to this room. ' + | |
'The room will now be notified of any events in this auction. (Do ``.auction unbind`` to reverse this.)', 'auction'); | |
} | |
return saveAuctions(); | |
}, | |
auc: 'auction', | |
auction: function(arg, by, room, cmd) { | |
by = toId(by); | |
arg = Object(arg); // required for ExtractKeyword() to modify this string | |
// which auction is this referring to and which action should be performed? | |
var auction = ExtractKeyword(arg, Object.keys(auctions)); | |
var keyword = ExtractKeyword(arg, aucCmds); | |
if (!auction) { | |
// no auction specified? Maybe there is a default for this room. | |
if (auctions.defaults[room]) auction = auctions.defaults[room]; | |
else { | |
keyword = ''; // no auction specified. Give usage help. | |
this.restrictReply('No auction specified.', 'auction'); | |
} | |
} | |
auction = auctions[auction]; | |
arg = arg.toString(); | |
switch (keyword) { | |
/* Usage Help ****************************************************************/ | |
case '': { | |
if (auction) { | |
this.restrictReply('Usage: ``.auction COMMAND``.', 'auction'); | |
} else { | |
this.restrictReply('Usage: ``.auction NAME COMMAND``. NAME can be ommitted if the room has a default auction. ' + | |
'Room owners can use ``.auction NAME bind`` to set the default auction.', 'auction'); | |
} | |
this.restrictReply('Command list: Room Owners - ``bind, unbind``. ' + | |
'Auction Owners - ``unbind, delete, addmanagers, allownom TEAMNAME, stopnom``. ' + | |
'Team Managers - ``nom PLAYER, bid AMOUNT``. Anyone - ``teaminfo TEAMNAME``', 'auction'); | |
return; | |
} | |
/* Auction Owner Commands ****************************************************/ | |
case 'delete': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
for (var r in auction.rooms) { | |
if (auctions.defaults[auction.rooms[r]]) | |
delete auctions.defaults[auction.rooms[r]]; | |
} | |
var temp = auction.name; | |
delete auctions[auction.name]; | |
this.aucBroadcast(auction, 'Auction **' + temp + '** has been deleted.'); | |
return saveAuctions(); | |
} | |
case 'bind': { | |
let rank; | |
if (Settings.settings.makeauction && Settings.settings.makeauction[room]) | |
rank = Settings.settings.makeauction[room]; | |
else rank = "#"; | |
if (!this.can('makeauction')) | |
return this.restrictReply('Rank ' + rank + ' required for binding auctions to this room.', 'auction'); | |
if (auction.rooms.indexOf(room) >= 0 && auctions.defaults[room] === auction.name) | |
return this.restrictReply('This auction is already broadcasting to this room.', 'auction'); | |
auction.rooms.push(room); | |
auctions.defaults[room] = auction.name; | |
this.restrictReply('**' + auction.name + '** has been bound to this room. ' + | |
'The room will now be notified of events in this auction.', 'auction'); | |
return saveAuctions(); | |
} | |
case 'unbind': { | |
let rank; | |
if (Settings.settings.makeauction && Settings.settings.makeauction[room]) | |
rank = Settings.settings.makeauction[room]; | |
else rank = "#"; | |
if (!this.can('makeauction') && auction.owners.indexOf(by) < 0) | |
return this.restrictReply('Rank ' + rank + ' required for unbinding auctions from this room.', 'auction'); | |
if (auction.rooms.indexOf(room) < 0 && auctions.defaults[room] !== auction.name) | |
return this.restrictReply('That auction is not broadcasting to this room.', 'auction'); | |
auction.rooms.filter( r => r !== room ); | |
delete auctions.defaults[room]; | |
this.restrictReply('**' + auction.name + '** has been unbound from this room. ' + | |
'The room will no longer be notified of events in this auction.', 'auction'); | |
return saveAuctions(); | |
} | |
case 'addmanagers': | |
case 'addmanager': | |
case 'addteams': | |
case 'addteam': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('Only auction owners can modify teams.'); | |
if (!arg.toString()) return this.restrictReply('Usage: ``.auction NAME addmanagers ' + | |
'TEAMNAME:MANAGER,MANAGER2,..``. Accepts multiple teams at once, separated by ``;``.'); | |
arg = arg.split(';').map( s => s.split(':') ); | |
for (var t in arg) { | |
var teamname = toId(arg[t][0]); | |
if (!teamname) continue; | |
if (!auction.teams[teamname]) { | |
auction.teams[teamname] = { | |
name: teamname, | |
credits: auction.startmoney, | |
managers: [], | |
players: [] | |
}; | |
} | |
if (arg[t][1]) { | |
var newManagers = arg[t][1].split(',').map(toId); | |
for (var m in newManagers) { | |
if (auction.teams[teamname].managers.indexOf(newManagers[m]) < 0) { | |
auction.teams[teamname].managers.push(newManagers[m]); | |
auction.managers[newManagers[m]] = teamname; | |
} | |
} | |
} | |
} | |
this.aucBroadcast(auction, 'Teams in auction **' + auction.name + '** are now: ' + | |
Object.keys(auction.teams).join(', ') + '. Type ``.auction team ' + | |
'TEAMNAME`` for info on a team.', 'auction'); | |
return saveAuctions(); | |
} | |
case 'addplayer': | |
case 'addplayers': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('Only auction owners can modify the player list.'); | |
if (!arg.toString()) return this.restrictReply('Usage: ``.auction NAME addplayers ' + | |
'PLAYERNAME:DESCRIPTION``. Accepts multiple players at once, separated by ``;``.'); | |
arg = arg.split(';').map( s => s.split(':') ); | |
for (var t in arg) { | |
var playername = toId(arg[t][0]); | |
if (!playername) continue; | |
auction.players[playername] = { | |
name: playername, | |
description: arg[t][1] ? arg[t][1].trim() : "", | |
team: false | |
}; | |
} | |
this.aucBroadcast(auction, 'Players in auction **' + auction.name + '** are now: ' + | |
Object.keys(auction.players).join(', ') + '.'); | |
return saveAuctions(); | |
} | |
case 'report': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
Tools.uploadToHastebin(JSON.stringify(auction, null, 4), | |
function(success, hastebinLink) { | |
if (success) return this.restrictReply('Auction object: ' + hastebinLink, 'auction'); | |
else this.restrictReply('An error occured while uploading to hastebin.com/', 'auction'); | |
}.bind(this) | |
); | |
return; | |
} | |
case 'run': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
if (auction.running) | |
return this.restrictReply('The auction is already running.', 'auction'); | |
auction.nomorder = Object.keys(auction.teams).reverse().concat(Object.keys(auction.teams)); | |
auction.nomqueue = [].concat(auction.nomorder); | |
auction.running = true; | |
this.restrictReply('**' + auction.name + '** is now autoselecting who gets to nominate players.', 'auction'); | |
while (auction.teams[auction.allownom = auction.nomqueue.pop()].credits < 3000) { | |
if (auction.nomqueue.length === 0) { | |
auction.running = false; | |
this.aucBroadcast(auction, 'Auction **' + auction.name + '** has ended because every team has less than 3000 Credits left.'); | |
return saveAuctions(); | |
} | |
} | |
this.aucBroadcast(auction, 'It is now **' + auction.allownom + '**\'s turn to nominate a player for auction.'); | |
return saveAuctions(); | |
} | |
case 'allownom': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
if (!auction.teams[arg]) return this.restrictReply('Usage: ``.auction allownom teamname``', 'auction'); | |
if (auction.nomorder.indexOf(arg) >= 0) { | |
if (auction.nomqueue.length < auction.nomorder.length) | |
auction.nomqueue = auction.nomorder.concat(auction.nomqueue); | |
while (auction.nomqueue.pop() !== arg); // pop elements until the team is found | |
} | |
auction.allownom = arg; | |
this.aucBroadcast(auction, 'It is now **' + arg + '**\'s turn to nominate a player for auction.'); | |
return saveAuctions(); | |
} | |
case 'stop': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
if (!auction.running) | |
return this.restrictReply('The auction is already stopped.', 'auction'); | |
auction.running = false; | |
saveAuctions(); // ".auction stop" also calls ".auction stopnom", so no return statement here | |
} | |
case 'stopnom': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
var theNom; | |
if (auction.allownom) theNom = auction.allownom; | |
else if (auction.nommedplayer) theNom = auction.nommedplayer; | |
else return this.restrictReply('There is no nomination to be canceled.', 'auction'); | |
clearTimeout(auction_timer[toId(auction.name)]); | |
auction.allownom = false; | |
auction.nommedplayer = false; | |
auction.bid = false; | |
auction.bidder = false; | |
this.aucBroadcast(auction, theNom + '\'s nomination has been cancelled.'); | |
return saveAuctions(); | |
} | |
case 'reset': { | |
if (auction.owners.indexOf(by) < 0 && !this.isRanked('~')) | |
return this.restrictReply('You do not have permission to do this.'); | |
for (var p in auction.players) | |
auction.players[p].team = false; | |
for (var t in auction.teams) { | |
auction.teams[t].credits = auction.startmoney; | |
auction.teams[t].players = []; | |
} | |
auction.running = false; | |
auction.allownom = false; | |
auction.nomqueue = false; | |
auction.nommedplayer = false; | |
auction.bid = false; | |
auction.bidder = false; | |
this.aucBroadcast(auction, 'Auction **' + auction.name + '** has been reset and will start from zero again. All teams have ``' + auction.startmoney + '`` credits, and all players are available for purchase.'); | |
return saveAuctions(); // ".auction stop" also calls ".auction stopnom", so no return statement here | |
} | |
/* Team Manager Commands *****************************************************/ | |
case 'nom': | |
case 'nominate': { | |
arg = toId(arg); | |
if (!auction.players[arg]) | |
return this.restrictReply('Player not recognized. Usage: ``.auction nominate PLAYERNAME``.', 'auction'); | |
if (auction.players[arg].team) | |
return this.restrictReply('That player is already on team ' + auction.players[arg].team + '.', 'auction'); | |
if (auction.managers[by] !== auction.allownom && auction.owners.indexOf(by) < 0 && !this.isRanked('~')) { | |
if (!auction.managers[by]) | |
return this.restrictReply('Only team managers and auction owners may nominate players.', 'auction'); | |
return this.restrictReply('It is not your turn to nominate yet. (Auction owners may use ' + | |
'``.allownom TEAMNAME`` to give permission.)', 'auction'); | |
} | |
if (auction.nommedplayer) | |
return this.restrictReply('Already nominated ' + auction.nommedplayer, 'auction'); | |
auction.nommedplayer = arg; | |
this.aucBroadcast(auction, by + ' from ' + auction.managers[by] + ' has nominated **' + arg + '** for auction. ' + auction.players[arg].description); | |
arg = "3000"; | |
// no return statement. nominate always calls bid, nomming a player bids the min bid on them. | |
} | |
case 'bid': { | |
if (!auction.managers[by]) return this.restrictReply('Only team managers may bid on players.', 'auction'); | |
if (!auction.nommedplayer) return this.restrictReply('No player is up for auction.', 'auction'); | |
if (Number(arg) != arg) | |
return this.restrictReply('Please enter the amount of credits you want to bid, in multiples of 500.', 'auction'); | |
if (arg % 500 !== 0) | |
arg *= 1000; | |
if (arg % 500 !== 0) | |
return this.restrictReply('Please enter the amount of credits you want to bid, in multiples of 500.', 'auction'); | |
if (Number(arg) <= auction.bid) | |
return this.restrictReply('You have to bid more credits than the previous offer.', 'auction'); | |
if (Number(arg) > auction.teams[auction.managers[by]].credits) { | |
return this.restrictReply('Your team does not have enough funds. Remaining credits: ``' + | |
auction.teams[auction.managers[by]].credits + '``.', 'auction'); | |
} | |
var restmoney = auction.teams[auction.managers[by]].credits - Number(arg); | |
if (1 + restmoney / 3000 + auction.teams[auction.managers[by]].players.length < 10) | |
return this.restrictReply('Your team does not have enough funds. Remaining credits: ``' + | |
auction.teams[auction.managers[by]].credits + '``. Remember you will need to buy at least 10 players.', 'auction'); | |
auction.bidder = auction.managers[by]; | |
auction.bid = arg; | |
this.aucBroadcast(auction, by + '[' + auction.managers[by] + ']: **' + auction.bid + '**.'); | |
clearTimeout(auction_timer[toId(auction.name)]); | |
auction_timer[toId(auction.name)] = setTimeout(() => { | |
this.aucBroadcast(auction, '__Five seconds remaining!__'); | |
auction_timer[toId(auction.name)] = setTimeout(() => { | |
this.aucBroadcast(auction, '**' + auction.bidder + ' has bought ' + auction.players[auction.nommedplayer].name + ' for ' + auction.bid + '!**'); | |
auction.teams[auction.bidder].credits -= arg; | |
auction.teams[auction.bidder].players.push(auction.nommedplayer); | |
auction.players[auction.nommedplayer].team = auction.bidder; | |
auction.nommedplayer = auction.bid = auction.bidder = false; | |
if (!auction.running) | |
auction.allownom = false; | |
else { | |
if (auction.nomqueue.length < auction.nomorder.length) | |
auction.nomqueue = auction.nomorder.concat(auction.nomqueue); | |
while (auction.teams[auction.allownom = auction.nomqueue.pop()].credits < 3000) { | |
if (auction.nomqueue.length === 0) { | |
auction.running = false; | |
this.aucBroadcast(auction, 'Auction **' + auction.name + '** has ended because every team has less than 3000 Credits left.'); | |
return saveAuctions(); | |
} | |
} | |
if (Tools.equalOrHigherRank(Bot.rooms[room].users[toId(this.botName)][0], '*')) { | |
var aucPlayerpool = []; | |
for (p in auction.players) { | |
if (!auction.players[p].team) | |
aucPlayerpool.push(auction.players[p].name); | |
} | |
var htmlTable = "<table style='border: 1px solid #6688aa; border-radius: 10px'><tr><th style='border-bottom: 1px solid #94b8b8; padding: 5px'>Team</th><th style='border-bottom: 1px solid #94b8b8; padding: 5px'>Credits</th><th style='border-bottom: 1px solid #94b8b8; padding: 5px'>Players</th></tr>"; | |
var i = 0; | |
for (t in auction.teams) { | |
var style = "style='background-color: rgba(242, 247, 250, 0.7); color: black'"; | |
if (++i % 2 === 0) style = "style='background-color: rgba(203, 203, 203, 0.7); color: black'"; | |
htmlTable += "<tr " + style + "><td>" + t + "</td><td align='right'>" + auction.teams[t].credits + "</td><td>" + auction.teams[t].players.join(', ') + "</td></tr>"; | |
} | |
htmlTable += "</table>" | |
this.reply("/addhtmlbox <div style='max-height: 400px; overflow-y: auto'><center>" + htmlTable + "</center><p>Players remaining in the pool (" + aucPlayerpool.length + "): " + aucPlayerpool.join(", ") + "</p></div>"); | |
} | |
this.aucBroadcast(auction, 'It is now **' + auction.allownom + '**\'s turn to nominate a player for auction.'); | |
} | |
return saveAuctions(); | |
}, 5000); | |
}, 7000); | |
return saveAuctions(); | |
} | |
/* Reg-User Commands *********************************************************/ | |
case 'teaminfo': | |
case 'team': { | |
var theTeam = auction.teams[arg]; | |
if (!theTeam) { | |
if (auction.managers[by] && !arg) theTeam = auction.teams[auction.managers[by]]; | |
else return this.restrictReply('No team goes by that name here.', 'auction'); | |
} | |
this.restrictReply('Team ' + theTeam.name + ': ``' + theTeam.credits + '`` credits. ' + | |
'Managers: ' + theTeam.managers.join(', ') + '. ``' + theTeam.players.length + '`` Players: ' + theTeam.players.join(', '), 'auction'); | |
return; | |
} | |
case 'players': { | |
var result = []; | |
for (t in auction.teams) | |
result.push(t + ' (' + auction.teams[t].credits + '): ' + auction.teams[t].players.join(', ')); | |
result.push('\r\nPlayers remaining in the pool' + (arg ? ' with a description containing ' + arg : '') + ':'); | |
for (p in auction.players) { | |
if (!auction.players[p].team && (!arg || auction.players[p].description.toLowerCase().indexOf(arg.toLowerCase()) >= 0)) | |
result.push(auction.players[p].name + ': ' + auction.players[p].description); | |
} | |
Tools.uploadToHastebin(result.join('\r\n'), | |
function(success, hastebinLink) { | |
if (success) return this.restrictReply('Players in ' + auction.name + ': ' + hastebinLink, 'auction'); | |
else this.restrictReply('An error occured while uploading to hastebin.com/', 'auction'); | |
}.bind(this) | |
); | |
return; | |
} | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment