/*
* lottery.cpp
* Code for the Highport Lottery
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* Permission to use, modify and distribute is granted via the
* Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
* Contributions by Tim Callahan, Jonathan Hseu
* Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
*
*/
#include "mud.h"
#include "factions.h"
#include <fcntl.h>
// Max lottery #
#define MAXBONE 25
void bubblesort(int numbers[], int array_size) {
int i, j, temp;
for(i = (array_size - 1); i >= 0; i--) {
for(j = 1; j <= i; j++) {
if(numbers[j-1] > numbers[j]) {
temp = numbers[j-1];
numbers[j-1] = numbers[j];
numbers[j] = temp;
}
}
}
}
LottoTicket::LottoTicket(const char* name, int pNumbers[], int pCycle) {
for(int i = 0; i<6; i++) {
numbers[i] = pNumbers[i];
}
owner = name;
lottoCycle = pCycle;
}
void LottoTicket::saveToXml(xmlNodePtr rootNode) {
xmlNodePtr curNode = xml::newStringChild(rootNode, "Ticket");
xml::newStringChild(curNode, "Owner", owner);
xml::newNumChild(curNode, "LottoCycle", lottoCycle);
saveShortIntArray(curNode, "Numbers", "LotteryNum", numbers, 6);
}
LottoTicket::LottoTicket(xmlNodePtr rootNode) {
xmlNodePtr curNode = rootNode->children;
while(curNode) {
if(NODE_NAME(curNode, "Owner")) xml::copyToBString(owner, curNode);
else if(NODE_NAME(curNode, "LottoCycle")) xml::copyToNum(lottoCycle, curNode);
else if(NODE_NAME(curNode, "Numbers")) xml::loadNumArray<short>(curNode, numbers, "LotteryNum", 6);
curNode = curNode->next;
}
}
void Config::setLotteryRunTime() {
struct tm *timeToRun=0;
struct tm *curTime=0;
long i=0;
// Sets the run time to the sunday of the next week
timeToRun = new tm;
memset(timeToRun, 0, sizeof(*timeToRun));
i = time(0);
curTime = localtime(&i);
timeToRun->tm_hour = 20;
timeToRun->tm_min = 0;
timeToRun->tm_sec = 0;
timeToRun->tm_mon = curTime->tm_mon;
timeToRun->tm_mday = curTime->tm_mday + (7 - curTime->tm_wday);
timeToRun->tm_year = curTime->tm_year;
i = mktime(timeToRun);
delete timeToRun;
lotteryRunTime = i;
}
void Config::runLottery() {
int numbers[6];
int go=1, x=0, j=0, reCalc=0;
// Lottery hasn't been rigged
if(1) {
while(go) {
numbers[x] = mrand(1,MAXBONE);
for(j = 0; j < x; j++) {
if(numbers[x] == numbers[j]) {
reCalc = 1;
break;
}
}
if(reCalc) {
reCalc = 0;
continue;
}
x++;
if(x>5)
go = 0;
}
bubblesort(numbers, 5);
numbers[5] = mrand(1,MAXBONE);
for(x=0; x < 6; x++)
lotteryNumbers[x] = numbers[x];
} else {
// It has been rigged!
}
lotteryCycle++;
lotteryTicketsSold=0; // Reset tickets sold
for( LottoTicket* ticket : tickets) {
delete ticket;
}
tickets.clear();
lotteryWinnings = 0; // Reset amount won
if(lotteryWon == 1) // Reset the jackpot
lotteryJackpot = 500000;
else
lotteryJackpot = (long)(lotteryJackpot * 1.15);
lotteryJackpot = MIN(lotteryJackpot, 3000000);
lotteryWon = 0;
broadcast(
"### The Highport Powerbone numbers have been drawn.\n### The jackpot is $%ld!",
lotteryJackpot);
broadcast(
"### The winning numbers are %02d %02d %02d %02d %02d with a power bone of %02d!",
lotteryNumbers[0], lotteryNumbers[1], lotteryNumbers[2],
lotteryNumbers[3], lotteryNumbers[4], lotteryNumbers[5]);
save();
setLotteryRunTime();
}
int dmLottery(Player* player, cmd* cmnd) {
if(cmnd->num < 2 || strcmp(cmnd->str[1], "run")) {
player->print("Type \"*lottery run\" to run the lottery.\nTo view lottery info, type \"lottery\".\n");
return(0);
}
gConfig->runLottery();
return(0);
}
int createLotteryTicket(Object **object, const char *name) {
int numbers[6];
int go=1, x=0, j=0, reCalc=0;
char desc[80];
strcpy(desc, "");
if(!loadObject(TICKET_OBJ, object))
return(-1);
while(go) {
numbers[x] = mrand(1,MAXBONE);
for(j = 0; j < x; j++) {
if(numbers[x] == numbers[j]) {
reCalc = 1;
break;
}
}
if(reCalc) {
reCalc = 0;
continue;
}
x++;
if(x>5)
go = 0;
}
bubblesort(numbers, 5);
numbers[5] = mrand(1,MAXBONE);
sprintf(
desc,
"A lottery ticket with the numbers: %02d %02d %02d %02d %02d (%02d)",
numbers[0], numbers[1], numbers[2], numbers[3], numbers[4],
numbers[5]);
(*object)->description = desc;
(*object)->setType(LOTTERYTICKET);
// Not valid untill next week
(*object)->setLotteryCycle(gConfig->getCurrentLotteryCycle() + 1);
gConfig->increaseJackpot(gConfig->getLotteryTicketPrice()/2);
(*object)->setFlag(O_NO_DROP);
for(x = 0; x < 6; x++)
(*object)->setLotteryNumbers(x, numbers[x]);
LottoTicket* ticket = new LottoTicket(name, numbers, gConfig->getCurrentLotteryCycle()+1);
gConfig->addTicket(ticket);
return(0);
}
void Config::increaseJackpot(int amnt) {
if(amnt < 0)
return;
lotteryJackpot += amnt;
lotteryJackpot = MIN(lotteryJackpot, 10000000);
}
void Config::addTicket(LottoTicket* ticket) {
tickets.push_back(ticket);
gConfig->lotteryTicketsSold++;
gConfig->save();
}
int Config::getCurrentLotteryCycle() {
return(lotteryCycle);
}
int Config::getLotteryEnabled() {
return(lotteryEnabled);
}
long Config::getLotteryJackpot() {
return(lotteryJackpot);
}
int Config::getLotteryTicketPrice() {
return(lotteryTicketPrice);
}
void Config::getNumbers(short numberArray[]) {
for(int i = 0; i < 6; i++)
numberArray[i] = lotteryNumbers[i];
}
long Config::getLotteryWinnings() {
return(lotteryWinnings);
}
void Config::winLottery() {
lotteryWon = 0;
lotteryJackpot = 500000;
}
int Config::getLotteryTicketsSold() {
return(lotteryTicketsSold);
}
void Config::addLotteryWinnings(long prize) {
lotteryWinnings += prize;
}
bstring Config::getLotteryRunTimeStr() {
return(ctime(&gConfig->lotteryRunTime));
}
time_t Config::getLotteryRunTime() {
return(lotteryRunTime);
}
int cmdClaim(Player* player, cmd* cmnd) {
BaseRoom *inRoom = player->getRoomParent();
Object *ticket=0;
long prize=0;
if(!player->ableToDoCommand())
return(0);
if(!inRoom->flagIsSet(R_LOTTERY_OFFICE)) {
player->print("You can only claim a prize in the lottery office.\n");
return(0);
}
if(cmnd->num < 2) {
player->print("Claim your prize from what?\n");
return(0);
}
player->unhide();
ticket = player->findObject(player, cmnd, 1);
if(!ticket) {
player->print("You don't have that.\n");
return(0);
}
if(ticket->getType() != LOTTERYTICKET) {
player->print("That isn't a lottery ticket!\n");
return(0);
}
if(ticket->getLotteryNumbers(0) == 0) {
player->print("That isn't a lottery ticket!\n");
return(0);
}
if(player->inUniqueRoom() && !Faction::willDoBusinessWith(player, player->getUniqueRoomParent()->getFaction())) {
player->print("The shopkeeper refuses to do business with you.\n");
return(0);
}
if(ticket->getLotteryCycle() > gConfig->getCurrentLotteryCycle()) {
player->print("Sorry that ticket can't be claimed untill after the next drawing!\n");
return(0);
}
if(ticket->getLotteryCycle() < gConfig->getCurrentLotteryCycle()) {
player->print("Sorry, that ticket's too old!\n");
return(0);
}
prize = checkPrize(ticket);
player->delObj(ticket, true);
delete ticket;
if(prize == 0) {
player->print("Sorry, this ticket isn't worth anything.\n");
return(0);
}
logn("log.prizes", "%s just won %ld.\n", player->getCName(), prize);
gConfig->addLotteryWinnings(prize);
broadcast(player->getSock(), player->getParent(), "%s claims a Powerbone ticket.", player->getCName());
if(prize != gConfig->getLotteryJackpot()) { // Didn't win the big pot
player->print("Sorry you didn't win the jackpot this time, but you did win $%ld today!\n", prize);
player->print("The lottery official hands you %ld gold coin%s.\n", prize, prize != 1 ? "s" : "");
player->coins.add(prize, GOLD);
gServer->logGold(GOLD_IN, player, Money(prize, GOLD), NULL, "Lottery");
return(0);
} else { // Big winner
broadcast("### %s just won the Highport Powerbones' Jackpot of %ld gold coin%s!", player->getCName(), prize, prize != 1 ? "s" : "");
// Reset the pot!
player->print("The lottery official hands you %ld gold coin%s.\n", prize, prize != 1 ? "s" : "");
player->coins.add(prize, GOLD);
gServer->logGold(GOLD_IN, player, Money(prize, GOLD), NULL, "LotteryJackpot");
gConfig->winLottery();
return(0);
}
}
int lotteryPrizes[] = { 0, // 0
500, // 1
1000, // 2
3000, // 3
7000, // 4
7000, // 5
10000, // 6
10000, // 7
50000, // 8
250000, // 9
500000 // 10
};
int checkPrize(Object *ticket) {
short numbers[6];
int matches=0, pb=0, i=0, j=0;
if( ticket->getType() != LOTTERYTICKET ||
ticket->getLotteryCycle() != gConfig->getCurrentLotteryCycle()
)
return(0);
gConfig->getNumbers(numbers);
if(ticket->getLotteryNumbers(5) == numbers[5])
pb = 1;
for(i=0; i<5; i++) {
for(j = 0; j < 5; j++) {
if(ticket->getLotteryNumbers(i) == numbers[j]) {
matches++;
}
}
}
if(matches == 0 && pb == 1)
return(lotteryPrizes[1]);
else if(matches == 2 && pb == 0)
return(lotteryPrizes[2]);
else if(matches == 1 && pb == 1)
return(lotteryPrizes[3]);
else if(matches == 2 && pb == 1)
return(lotteryPrizes[4]);
else if(matches == 3 && pb == 0)
return(lotteryPrizes[5]);
else if(matches == 3 && pb == 1)
return(lotteryPrizes[6]);
else if(matches == 4 && pb == 0)
return(lotteryPrizes[7]);
else if(matches == 4 && pb == 1)
return(lotteryPrizes[8]);
else if(matches == 5 && pb == 0)
return(lotteryPrizes[9]);
else if(matches == 5 && pb == 1)
return(gConfig->getLotteryJackpot());
return(0);
}
int cmdLottery(Player* player, cmd* cmnd) {
short numbers[6];
if(!player->ableToDoCommand())
return(0);
gConfig->getNumbers(numbers);
player->print("Current Powerbone cycle: %-3d Current Jackpot: $%ld\nCurrent winning numbers: %02d %02d %02d %02d %02d Powerbone: %02d\n",
gConfig->getCurrentLotteryCycle(), gConfig->getLotteryJackpot(),
numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5]);
player->print("Time of the next drawing: %s", gConfig->getLotteryRunTimeStr().c_str());
if(player->isDm()) {
player->print("Winnings so far this cycle: %ld\nTickets sold: %d\n",
gConfig->getLotteryWinnings(), gConfig->getLotteryTicketsSold());
}
return(0);
}